Fix PR42664.
[official-gcc/constexpr.git] / libgfortran / intrinsics / date_and_time.c
blob4bc6e6928c0dcdf28209621aca17d7b5fc179053
1 /* Implementation of the DATE_AND_TIME intrinsic.
2 Copyright (C) 2003, 2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
3 Contributed by Steven Bosscher.
5 This file is part of the GNU Fortran 95 runtime library (libgfortran).
7 Libgfortran is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public
9 License as published by the Free Software Foundation; either
10 version 3 of the License, or (at your option) any later version.
12 Libgfortran is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 Under Section 7 of GPL version 3, you are granted additional
18 permissions described in the GCC Runtime Library Exception, version
19 3.1, as published by the Free Software Foundation.
21 You should have received a copy of the GNU General Public License and
22 a copy of the GCC Runtime Library Exception along with this program;
23 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 <http://www.gnu.org/licenses/>. */
26 #include "libgfortran.h"
27 #include <string.h>
28 #include <assert.h>
29 #include <stdlib.h>
31 #undef HAVE_NO_DATE_TIME
32 #if TIME_WITH_SYS_TIME
33 # include <sys/time.h>
34 # include <time.h>
35 #else
36 # if HAVE_SYS_TIME_H
37 # include <sys/time.h>
38 # else
39 # ifdef HAVE_TIME_H
40 # include <time.h>
41 # else
42 # define HAVE_NO_DATE_TIME
43 # endif /* HAVE_TIME_H */
44 # endif /* HAVE_SYS_TIME_H */
45 #endif /* TIME_WITH_SYS_TIME */
47 #ifndef abs
48 #define abs(x) ((x)>=0 ? (x) : -(x))
49 #endif
52 /* If the re-entrant versions of localtime and gmtime are not
53 available, provide fallback implementations. On some targets where
54 the _r versions are not available, localtime and gmtime use
55 thread-local storage so they are threadsafe. */
57 #ifndef HAVE_LOCALTIME_R
58 static struct tm *
59 localtime_r (const time_t * timep, struct tm * result)
61 *result = *localtime (timep);
62 return result;
64 #endif
66 #ifndef HAVE_GMTIME_R
67 static struct tm *
68 gmtime_r (const time_t * timep, struct tm * result)
70 *result = *gmtime (timep);
71 return result;
73 #endif
76 /* DATE_AND_TIME ([DATE, TIME, ZONE, VALUES])
78 Description: Returns data on the real-time clock and date in a form
79 compatible with the representations defined in ISO 8601:1988.
81 Class: Non-elemental subroutine.
83 Arguments:
85 DATE (optional) shall be scalar and of type default character, and
86 shall be of length at least 8 in order to contain the complete
87 value. It is an INTENT(OUT) argument. Its leftmost 8 characters
88 are assigned a value of the form CCYYMMDD, where CC is the century,
89 YY the year within the century, MM the month within the year, and
90 DD the day within the month. If there is no date available, they
91 are assigned blanks.
93 TIME (optional) shall be scalar and of type default character, and
94 shall be of length at least 10 in order to contain the complete
95 value. It is an INTENT(OUT) argument. Its leftmost 10 characters
96 are assigned a value of the form hhmmss.sss, where hh is the hour
97 of the day, mm is the minutes of the hour, and ss.sss is the
98 seconds and milliseconds of the minute. If there is no clock
99 available, they are assigned blanks.
101 ZONE (optional) shall be scalar and of type default character, and
102 shall be of length at least 5 in order to contain the complete
103 value. It is an INTENT(OUT) argument. Its leftmost 5 characters
104 are assigned a value of the form [+-]hhmm, where hh and mm are the
105 time difference with respect to Coordinated Universal Time (UTC) in
106 hours and parts of an hour expressed in minutes, respectively. If
107 there is no clock available, they are assigned blanks.
109 VALUES (optional) shall be of type default integer and of rank
110 one. It is an INTENT(OUT) argument. Its size shall be at least
111 8. The values returned in VALUES are as follows:
113 VALUES(1) the year (for example, 2003), or -HUGE(0) if there is
114 no date available;
116 VALUES(2) the month of the year, or -HUGE(0) if there
117 is no date available;
119 VALUES(3) the day of the month, or -HUGE(0) if there is no date
120 available;
122 VALUES(4) the time difference with respect to Coordinated
123 Universal Time (UTC) in minutes, or -HUGE(0) if this information
124 is not available;
126 VALUES(5) the hour of the day, in the range of 0 to 23, or
127 -HUGE(0) if there is no clock;
129 VALUES(6) the minutes of the hour, in the range 0 to 59, or
130 -HUGE(0) if there is no clock;
132 VALUES(7) the seconds of the minute, in the range 0 to 60, or
133 -HUGE(0) if there is no clock;
135 VALUES(8) the milliseconds of the second, in the range 0 to
136 999, or -HUGE(0) if there is no clock.
138 NULL pointer represent missing OPTIONAL arguments. All arguments
139 have INTENT(OUT). Because of the -i8 option, we must implement
140 VALUES for INTEGER(kind=4) and INTEGER(kind=8).
142 Based on libU77's date_time_.c.
144 TODO :
145 - Check year boundaries.
147 #define DATE_LEN 8
148 #define TIME_LEN 10
149 #define ZONE_LEN 5
150 #define VALUES_SIZE 8
152 extern void date_and_time (char *, char *, char *, gfc_array_i4 *,
153 GFC_INTEGER_4, GFC_INTEGER_4, GFC_INTEGER_4);
154 export_proto(date_and_time);
156 void
157 date_and_time (char *__date, char *__time, char *__zone,
158 gfc_array_i4 *__values, GFC_INTEGER_4 __date_len,
159 GFC_INTEGER_4 __time_len, GFC_INTEGER_4 __zone_len)
161 int i;
162 char date[DATE_LEN + 1];
163 char timec[TIME_LEN + 1];
164 char zone[ZONE_LEN + 1];
165 GFC_INTEGER_4 values[VALUES_SIZE];
167 #ifndef HAVE_NO_DATE_TIME
168 time_t lt;
169 struct tm local_time;
170 struct tm UTC_time;
172 #if HAVE_GETTIMEOFDAY
174 struct timeval tp;
176 if (!gettimeofday (&tp, NULL))
178 lt = tp.tv_sec;
179 values[7] = tp.tv_usec / 1000;
181 else
183 lt = time (NULL);
184 values[7] = 0;
187 #else
188 lt = time (NULL);
189 values[7] = 0;
190 #endif /* HAVE_GETTIMEOFDAY */
192 if (lt != (time_t) -1)
194 localtime_r (&lt, &local_time);
195 gmtime_r (&lt, &UTC_time);
197 /* All arguments can be derived from VALUES. */
198 values[0] = 1900 + local_time.tm_year;
199 values[1] = 1 + local_time.tm_mon;
200 values[2] = local_time.tm_mday;
201 values[3] = (local_time.tm_min - UTC_time.tm_min +
202 60 * (local_time.tm_hour - UTC_time.tm_hour +
203 24 * (local_time.tm_yday - UTC_time.tm_yday)));
204 values[4] = local_time.tm_hour;
205 values[5] = local_time.tm_min;
206 values[6] = local_time.tm_sec;
208 #if HAVE_SNPRINTF
209 if (__date)
210 snprintf (date, DATE_LEN + 1, "%04d%02d%02d",
211 values[0], values[1], values[2]);
212 if (__time)
213 snprintf (timec, TIME_LEN + 1, "%02d%02d%02d.%03d",
214 values[4], values[5], values[6], values[7]);
216 if (__zone)
217 snprintf (zone, ZONE_LEN + 1, "%+03d%02d",
218 values[3] / 60, abs (values[3] % 60));
219 #else
220 if (__date)
221 sprintf (date, "%04d%02d%02d", values[0], values[1], values[2]);
223 if (__time)
224 sprintf (timec, "%02d%02d%02d.%03d",
225 values[4], values[5], values[6], values[7]);
227 if (__zone)
228 sprintf (zone, "%+03d%02d",
229 values[3] / 60, abs (values[3] % 60));
230 #endif
232 else
234 memset (date, ' ', DATE_LEN);
235 date[DATE_LEN] = '\0';
237 memset (timec, ' ', TIME_LEN);
238 timec[TIME_LEN] = '\0';
240 memset (zone, ' ', ZONE_LEN);
241 zone[ZONE_LEN] = '\0';
243 for (i = 0; i < VALUES_SIZE; i++)
244 values[i] = - GFC_INTEGER_4_HUGE;
246 #else /* if defined HAVE_NO_DATE_TIME */
247 /* We really have *nothing* to return, so return blanks and HUGE(0). */
249 memset (date, ' ', DATE_LEN);
250 date[DATE_LEN] = '\0';
252 memset (timec, ' ', TIME_LEN);
253 timec[TIME_LEN] = '\0';
255 memset (zone, ' ', ZONE_LEN);
256 zone[ZONE_LEN] = '\0';
258 for (i = 0; i < VALUES_SIZE; i++)
259 values[i] = - GFC_INTEGER_4_HUGE;
260 #endif /* HAVE_NO_DATE_TIME */
262 /* Copy the values into the arguments. */
263 if (__values)
265 index_type len, delta, elt_size;
267 elt_size = GFC_DESCRIPTOR_SIZE (__values);
268 len = GFC_DESCRIPTOR_EXTENT(__values,0);
269 delta = GFC_DESCRIPTOR_STRIDE(__values,0);
270 if (delta == 0)
271 delta = 1;
273 assert (len >= VALUES_SIZE);
274 /* Cope with different type kinds. */
275 if (elt_size == 4)
277 GFC_INTEGER_4 *vptr4 = __values->data;
279 for (i = 0; i < VALUES_SIZE; i++, vptr4 += delta)
280 *vptr4 = values[i];
282 else if (elt_size == 8)
284 GFC_INTEGER_8 *vptr8 = (GFC_INTEGER_8 *)__values->data;
286 for (i = 0; i < VALUES_SIZE; i++, vptr8 += delta)
288 if (values[i] == - GFC_INTEGER_4_HUGE)
289 *vptr8 = - GFC_INTEGER_8_HUGE;
290 else
291 *vptr8 = values[i];
294 else
295 abort ();
298 if (__zone)
300 assert (__zone_len >= ZONE_LEN);
301 fstrcpy (__zone, ZONE_LEN, zone, ZONE_LEN);
304 if (__time)
306 assert (__time_len >= TIME_LEN);
307 fstrcpy (__time, TIME_LEN, timec, TIME_LEN);
310 if (__date)
312 assert (__date_len >= DATE_LEN);
313 fstrcpy (__date, DATE_LEN, date, DATE_LEN);
318 /* SECNDS (X) - Non-standard
320 Description: Returns the system time of day, or elapsed time, as a GFC_REAL_4
321 in seconds.
323 Class: Non-elemental subroutine.
325 Arguments:
327 X must be REAL(4) and the result is of the same type. The accuracy is system
328 dependent.
330 Usage:
332 T = SECNDS (X)
334 yields the time in elapsed seconds since X. If X is 0.0, T is the time in
335 seconds since midnight. Note that a time that spans midnight but is less than
336 24hours will be calculated correctly. */
338 extern GFC_REAL_4 secnds (GFC_REAL_4 *);
339 export_proto(secnds);
341 GFC_REAL_4
342 secnds (GFC_REAL_4 *x)
344 GFC_INTEGER_4 values[VALUES_SIZE];
345 GFC_REAL_4 temp1, temp2;
347 /* Make the INTEGER*4 array for passing to date_and_time. */
348 gfc_array_i4 *avalues = internal_malloc_size (sizeof (gfc_array_i4));
349 avalues->data = &values[0];
350 GFC_DESCRIPTOR_DTYPE (avalues) = ((GFC_DTYPE_REAL << GFC_DTYPE_TYPE_SHIFT)
351 & GFC_DTYPE_TYPE_MASK) +
352 (4 << GFC_DTYPE_SIZE_SHIFT);
354 GFC_DIMENSION_SET(avalues->dim[0], 0, 7, 1);
356 date_and_time (NULL, NULL, NULL, avalues, 0, 0, 0);
358 free_mem (avalues);
360 temp1 = 3600.0 * (GFC_REAL_4)values[4] +
361 60.0 * (GFC_REAL_4)values[5] +
362 (GFC_REAL_4)values[6] +
363 0.001 * (GFC_REAL_4)values[7];
364 temp2 = fmod (*x, 86400.0);
365 temp2 = (temp1 - temp2 >= 0.0) ? temp2 : (temp2 - 86400.0);
366 return temp1 - temp2;
371 /* ITIME(X) - Non-standard
373 Description: Returns the current local time hour, minutes, and seconds
374 in elements 1, 2, and 3 of X, respectively. */
376 static void
377 itime0 (int x[3])
379 #ifndef HAVE_NO_DATE_TIME
380 time_t lt;
381 struct tm local_time;
383 lt = time (NULL);
385 if (lt != (time_t) -1)
387 localtime_r (&lt, &local_time);
389 x[0] = local_time.tm_hour;
390 x[1] = local_time.tm_min;
391 x[2] = local_time.tm_sec;
393 #else
394 x[0] = x[1] = x[2] = -1;
395 #endif
398 extern void itime_i4 (gfc_array_i4 *);
399 export_proto(itime_i4);
401 void
402 itime_i4 (gfc_array_i4 *__values)
404 int x[3], i;
405 index_type len, delta;
406 GFC_INTEGER_4 *vptr;
408 /* Call helper function. */
409 itime0(x);
411 /* Copy the value into the array. */
412 len = GFC_DESCRIPTOR_EXTENT(__values,0);
413 assert (len >= 3);
414 delta = GFC_DESCRIPTOR_STRIDE(__values,0);
415 if (delta == 0)
416 delta = 1;
418 vptr = __values->data;
419 for (i = 0; i < 3; i++, vptr += delta)
420 *vptr = x[i];
424 extern void itime_i8 (gfc_array_i8 *);
425 export_proto(itime_i8);
427 void
428 itime_i8 (gfc_array_i8 *__values)
430 int x[3], i;
431 index_type len, delta;
432 GFC_INTEGER_8 *vptr;
434 /* Call helper function. */
435 itime0(x);
437 /* Copy the value into the array. */
438 len = GFC_DESCRIPTOR_EXTENT(__values,0);
439 assert (len >= 3);
440 delta = GFC_DESCRIPTOR_STRIDE(__values,0);
441 if (delta == 0)
442 delta = 1;
444 vptr = __values->data;
445 for (i = 0; i < 3; i++, vptr += delta)
446 *vptr = x[i];
451 /* IDATE(X) - Non-standard
453 Description: Fills TArray with the numerical values at the current
454 local time. The day (in the range 1-31), month (in the range 1-12),
455 and year appear in elements 1, 2, and 3 of X, respectively.
456 The year has four significant digits. */
458 static void
459 idate0 (int x[3])
461 #ifndef HAVE_NO_DATE_TIME
462 time_t lt;
463 struct tm local_time;
465 lt = time (NULL);
467 if (lt != (time_t) -1)
469 localtime_r (&lt, &local_time);
471 x[0] = local_time.tm_mday;
472 x[1] = 1 + local_time.tm_mon;
473 x[2] = 1900 + local_time.tm_year;
475 #else
476 x[0] = x[1] = x[2] = -1;
477 #endif
480 extern void idate_i4 (gfc_array_i4 *);
481 export_proto(idate_i4);
483 void
484 idate_i4 (gfc_array_i4 *__values)
486 int x[3], i;
487 index_type len, delta;
488 GFC_INTEGER_4 *vptr;
490 /* Call helper function. */
491 idate0(x);
493 /* Copy the value into the array. */
494 len = GFC_DESCRIPTOR_EXTENT(__values,0);
495 assert (len >= 3);
496 delta = GFC_DESCRIPTOR_STRIDE(__values,0);
497 if (delta == 0)
498 delta = 1;
500 vptr = __values->data;
501 for (i = 0; i < 3; i++, vptr += delta)
502 *vptr = x[i];
506 extern void idate_i8 (gfc_array_i8 *);
507 export_proto(idate_i8);
509 void
510 idate_i8 (gfc_array_i8 *__values)
512 int x[3], i;
513 index_type len, delta;
514 GFC_INTEGER_8 *vptr;
516 /* Call helper function. */
517 idate0(x);
519 /* Copy the value into the array. */
520 len = GFC_DESCRIPTOR_EXTENT(__values,0);
521 assert (len >= 3);
522 delta = GFC_DESCRIPTOR_STRIDE(__values,0);
523 if (delta == 0)
524 delta = 1;
526 vptr = __values->data;
527 for (i = 0; i < 3; i++, vptr += delta)
528 *vptr = x[i];
533 /* GMTIME(STIME, TARRAY) - Non-standard
535 Description: Given a system time value STime, fills TArray with values
536 extracted from it appropriate to the GMT time zone using gmtime_r(3).
538 The array elements are as follows:
540 1. Seconds after the minute, range 0-59 or 0-61 to allow for leap seconds
541 2. Minutes after the hour, range 0-59
542 3. Hours past midnight, range 0-23
543 4. Day of month, range 0-31
544 5. Number of months since January, range 0-11
545 6. Years since 1900
546 7. Number of days since Sunday, range 0-6
547 8. Days since January 1
548 9. Daylight savings indicator: positive if daylight savings is in effect,
549 zero if not, and negative if the information isn't available. */
551 static void
552 gmtime_0 (const time_t * t, int x[9])
554 struct tm lt;
556 gmtime_r (t, &lt);
557 x[0] = lt.tm_sec;
558 x[1] = lt.tm_min;
559 x[2] = lt.tm_hour;
560 x[3] = lt.tm_mday;
561 x[4] = lt.tm_mon;
562 x[5] = lt.tm_year;
563 x[6] = lt.tm_wday;
564 x[7] = lt.tm_yday;
565 x[8] = lt.tm_isdst;
568 extern void gmtime_i4 (GFC_INTEGER_4 *, gfc_array_i4 *);
569 export_proto(gmtime_i4);
571 void
572 gmtime_i4 (GFC_INTEGER_4 * t, gfc_array_i4 * tarray)
574 int x[9], i;
575 index_type len, delta;
576 GFC_INTEGER_4 *vptr;
577 time_t tt;
579 /* Call helper function. */
580 tt = (time_t) *t;
581 gmtime_0(&tt, x);
583 /* Copy the values into the array. */
584 len = GFC_DESCRIPTOR_EXTENT(tarray,0);
585 assert (len >= 9);
586 delta = GFC_DESCRIPTOR_STRIDE(tarray,0);
587 if (delta == 0)
588 delta = 1;
590 vptr = tarray->data;
591 for (i = 0; i < 9; i++, vptr += delta)
592 *vptr = x[i];
595 extern void gmtime_i8 (GFC_INTEGER_8 *, gfc_array_i8 *);
596 export_proto(gmtime_i8);
598 void
599 gmtime_i8 (GFC_INTEGER_8 * t, gfc_array_i8 * tarray)
601 int x[9], i;
602 index_type len, delta;
603 GFC_INTEGER_8 *vptr;
604 time_t tt;
606 /* Call helper function. */
607 tt = (time_t) *t;
608 gmtime_0(&tt, x);
610 /* Copy the values into the array. */
611 len = GFC_DESCRIPTOR_EXTENT(tarray,0);
612 assert (len >= 9);
613 delta = GFC_DESCRIPTOR_STRIDE(tarray,0);
614 if (delta == 0)
615 delta = 1;
617 vptr = tarray->data;
618 for (i = 0; i < 9; i++, vptr += delta)
619 *vptr = x[i];
625 /* LTIME(STIME, TARRAY) - Non-standard
627 Description: Given a system time value STime, fills TArray with values
628 extracted from it appropriate to the local time zone using localtime_r(3).
630 The array elements are as follows:
632 1. Seconds after the minute, range 0-59 or 0-61 to allow for leap seconds
633 2. Minutes after the hour, range 0-59
634 3. Hours past midnight, range 0-23
635 4. Day of month, range 0-31
636 5. Number of months since January, range 0-11
637 6. Years since 1900
638 7. Number of days since Sunday, range 0-6
639 8. Days since January 1
640 9. Daylight savings indicator: positive if daylight savings is in effect,
641 zero if not, and negative if the information isn't available. */
643 static void
644 ltime_0 (const time_t * t, int x[9])
646 struct tm lt;
648 localtime_r (t, &lt);
649 x[0] = lt.tm_sec;
650 x[1] = lt.tm_min;
651 x[2] = lt.tm_hour;
652 x[3] = lt.tm_mday;
653 x[4] = lt.tm_mon;
654 x[5] = lt.tm_year;
655 x[6] = lt.tm_wday;
656 x[7] = lt.tm_yday;
657 x[8] = lt.tm_isdst;
660 extern void ltime_i4 (GFC_INTEGER_4 *, gfc_array_i4 *);
661 export_proto(ltime_i4);
663 void
664 ltime_i4 (GFC_INTEGER_4 * t, gfc_array_i4 * tarray)
666 int x[9], i;
667 index_type len, delta;
668 GFC_INTEGER_4 *vptr;
669 time_t tt;
671 /* Call helper function. */
672 tt = (time_t) *t;
673 ltime_0(&tt, x);
675 /* Copy the values into the array. */
676 len = GFC_DESCRIPTOR_EXTENT(tarray,0);
677 assert (len >= 9);
678 delta = GFC_DESCRIPTOR_STRIDE(tarray,0);
679 if (delta == 0)
680 delta = 1;
682 vptr = tarray->data;
683 for (i = 0; i < 9; i++, vptr += delta)
684 *vptr = x[i];
687 extern void ltime_i8 (GFC_INTEGER_8 *, gfc_array_i8 *);
688 export_proto(ltime_i8);
690 void
691 ltime_i8 (GFC_INTEGER_8 * t, gfc_array_i8 * tarray)
693 int x[9], i;
694 index_type len, delta;
695 GFC_INTEGER_8 *vptr;
696 time_t tt;
698 /* Call helper function. */
699 tt = (time_t) * t;
700 ltime_0(&tt, x);
702 /* Copy the values into the array. */
703 len = GFC_DESCRIPTOR_EXTENT(tarray,0);
704 assert (len >= 9);
705 delta = GFC_DESCRIPTOR_STRIDE(tarray,0);
706 if (delta == 0)
707 delta = 1;
709 vptr = tarray->data;
710 for (i = 0; i < 9; i++, vptr += delta)
711 *vptr = x[i];