1 /* Implementation of the DATE_AND_TIME intrinsic.
2 Copyright (C) 2003, 2004, 2005, 2006, 2007, 2009, 2010
3 Free Software Foundation, Inc.
4 Contributed by Steven Bosscher.
6 This file is part of the GNU Fortran runtime library (libgfortran).
8 Libgfortran is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public
10 License as published by the Free Software Foundation; either
11 version 3 of the License, or (at your option) any later version.
13 Libgfortran is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 Under Section 7 of GPL version 3, you are granted additional
19 permissions described in the GCC Runtime Library Exception, version
20 3.1, as published by the Free Software Foundation.
22 You should have received a copy of the GNU General Public License and
23 a copy of the GCC Runtime Library Exception along with this program;
24 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
25 <http://www.gnu.org/licenses/>. */
27 #include "libgfortran.h"
32 #undef HAVE_NO_DATE_TIME
33 #if TIME_WITH_SYS_TIME
34 # include <sys/time.h>
38 # include <sys/time.h>
43 # define HAVE_NO_DATE_TIME
44 # endif /* HAVE_TIME_H */
45 # endif /* HAVE_SYS_TIME_H */
46 #endif /* TIME_WITH_SYS_TIME */
49 #define abs(x) ((x)>=0 ? (x) : -(x))
53 /* If the re-entrant versions of localtime and gmtime are not
54 available, provide fallback implementations. On some targets where
55 the _r versions are not available, localtime and gmtime use
56 thread-local storage so they are threadsafe. */
58 #ifndef HAVE_LOCALTIME_R
59 /* If _POSIX is defined localtime_r gets defined by mingw-w64 headers. */
65 localtime_r (const time_t * timep, struct tm * result)
67 *result = *localtime (timep);
73 /* If _POSIX is defined gmtime_r gets defined by mingw-w64 headers. */
79 gmtime_r (const time_t * timep, struct tm * result)
81 *result = *gmtime (timep);
87 /* DATE_AND_TIME ([DATE, TIME, ZONE, VALUES])
89 Description: Returns data on the real-time clock and date in a form
90 compatible with the representations defined in ISO 8601:1988.
92 Class: Non-elemental subroutine.
96 DATE (optional) shall be scalar and of type default character, and
97 shall be of length at least 8 in order to contain the complete
98 value. It is an INTENT(OUT) argument. Its leftmost 8 characters
99 are assigned a value of the form CCYYMMDD, where CC is the century,
100 YY the year within the century, MM the month within the year, and
101 DD the day within the month. If there is no date available, they
104 TIME (optional) shall be scalar and of type default character, and
105 shall be of length at least 10 in order to contain the complete
106 value. It is an INTENT(OUT) argument. Its leftmost 10 characters
107 are assigned a value of the form hhmmss.sss, where hh is the hour
108 of the day, mm is the minutes of the hour, and ss.sss is the
109 seconds and milliseconds of the minute. If there is no clock
110 available, they are assigned blanks.
112 ZONE (optional) shall be scalar and of type default character, and
113 shall be of length at least 5 in order to contain the complete
114 value. It is an INTENT(OUT) argument. Its leftmost 5 characters
115 are assigned a value of the form [+-]hhmm, where hh and mm are the
116 time difference with respect to Coordinated Universal Time (UTC) in
117 hours and parts of an hour expressed in minutes, respectively. If
118 there is no clock available, they are assigned blanks.
120 VALUES (optional) shall be of type default integer and of rank
121 one. It is an INTENT(OUT) argument. Its size shall be at least
122 8. The values returned in VALUES are as follows:
124 VALUES(1) the year (for example, 2003), or -HUGE(0) if there is
127 VALUES(2) the month of the year, or -HUGE(0) if there
128 is no date available;
130 VALUES(3) the day of the month, or -HUGE(0) if there is no date
133 VALUES(4) the time difference with respect to Coordinated
134 Universal Time (UTC) in minutes, or -HUGE(0) if this information
137 VALUES(5) the hour of the day, in the range of 0 to 23, or
138 -HUGE(0) if there is no clock;
140 VALUES(6) the minutes of the hour, in the range 0 to 59, or
141 -HUGE(0) if there is no clock;
143 VALUES(7) the seconds of the minute, in the range 0 to 60, or
144 -HUGE(0) if there is no clock;
146 VALUES(8) the milliseconds of the second, in the range 0 to
147 999, or -HUGE(0) if there is no clock.
149 NULL pointer represent missing OPTIONAL arguments. All arguments
150 have INTENT(OUT). Because of the -i8 option, we must implement
151 VALUES for INTEGER(kind=4) and INTEGER(kind=8).
153 Based on libU77's date_time_.c.
156 - Check year boundaries.
161 #define VALUES_SIZE 8
163 extern void date_and_time (char *, char *, char *, gfc_array_i4 *,
164 GFC_INTEGER_4, GFC_INTEGER_4, GFC_INTEGER_4);
165 export_proto(date_and_time);
168 date_and_time (char *__date, char *__time, char *__zone,
169 gfc_array_i4 *__values, GFC_INTEGER_4 __date_len,
170 GFC_INTEGER_4 __time_len, GFC_INTEGER_4 __zone_len)
173 char date[DATE_LEN + 1];
174 char timec[TIME_LEN + 1];
175 char zone[ZONE_LEN + 1];
176 GFC_INTEGER_4 values[VALUES_SIZE];
178 #ifndef HAVE_NO_DATE_TIME
180 struct tm local_time;
183 #if HAVE_GETTIMEOFDAY
187 if (!gettimeofday (&tp, NULL))
190 values[7] = tp.tv_usec / 1000;
201 #endif /* HAVE_GETTIMEOFDAY */
203 if (lt != (time_t) -1)
205 localtime_r (<, &local_time);
206 gmtime_r (<, &UTC_time);
208 /* All arguments can be derived from VALUES. */
209 values[0] = 1900 + local_time.tm_year;
210 values[1] = 1 + local_time.tm_mon;
211 values[2] = local_time.tm_mday;
212 values[3] = (local_time.tm_min - UTC_time.tm_min +
213 60 * (local_time.tm_hour - UTC_time.tm_hour +
214 24 * (local_time.tm_yday - UTC_time.tm_yday)));
215 values[4] = local_time.tm_hour;
216 values[5] = local_time.tm_min;
217 values[6] = local_time.tm_sec;
221 snprintf (date, DATE_LEN + 1, "%04d%02d%02d",
222 values[0], values[1], values[2]);
224 snprintf (timec, TIME_LEN + 1, "%02d%02d%02d.%03d",
225 values[4], values[5], values[6], values[7]);
228 snprintf (zone, ZONE_LEN + 1, "%+03d%02d",
229 values[3] / 60, abs (values[3] % 60));
232 sprintf (date, "%04d%02d%02d", values[0], values[1], values[2]);
235 sprintf (timec, "%02d%02d%02d.%03d",
236 values[4], values[5], values[6], values[7]);
239 sprintf (zone, "%+03d%02d",
240 values[3] / 60, abs (values[3] % 60));
245 memset (date, ' ', DATE_LEN);
246 date[DATE_LEN] = '\0';
248 memset (timec, ' ', TIME_LEN);
249 timec[TIME_LEN] = '\0';
251 memset (zone, ' ', ZONE_LEN);
252 zone[ZONE_LEN] = '\0';
254 for (i = 0; i < VALUES_SIZE; i++)
255 values[i] = - GFC_INTEGER_4_HUGE;
257 #else /* if defined HAVE_NO_DATE_TIME */
258 /* We really have *nothing* to return, so return blanks and HUGE(0). */
260 memset (date, ' ', DATE_LEN);
261 date[DATE_LEN] = '\0';
263 memset (timec, ' ', TIME_LEN);
264 timec[TIME_LEN] = '\0';
266 memset (zone, ' ', ZONE_LEN);
267 zone[ZONE_LEN] = '\0';
269 for (i = 0; i < VALUES_SIZE; i++)
270 values[i] = - GFC_INTEGER_4_HUGE;
271 #endif /* HAVE_NO_DATE_TIME */
273 /* Copy the values into the arguments. */
276 index_type len, delta, elt_size;
278 elt_size = GFC_DESCRIPTOR_SIZE (__values);
279 len = GFC_DESCRIPTOR_EXTENT(__values,0);
280 delta = GFC_DESCRIPTOR_STRIDE(__values,0);
284 assert (len >= VALUES_SIZE);
285 /* Cope with different type kinds. */
288 GFC_INTEGER_4 *vptr4 = __values->data;
290 for (i = 0; i < VALUES_SIZE; i++, vptr4 += delta)
293 else if (elt_size == 8)
295 GFC_INTEGER_8 *vptr8 = (GFC_INTEGER_8 *)__values->data;
297 for (i = 0; i < VALUES_SIZE; i++, vptr8 += delta)
299 if (values[i] == - GFC_INTEGER_4_HUGE)
300 *vptr8 = - GFC_INTEGER_8_HUGE;
311 assert (__zone_len >= ZONE_LEN);
312 fstrcpy (__zone, ZONE_LEN, zone, ZONE_LEN);
317 assert (__time_len >= TIME_LEN);
318 fstrcpy (__time, TIME_LEN, timec, TIME_LEN);
323 assert (__date_len >= DATE_LEN);
324 fstrcpy (__date, DATE_LEN, date, DATE_LEN);
329 /* SECNDS (X) - Non-standard
331 Description: Returns the system time of day, or elapsed time, as a GFC_REAL_4
334 Class: Non-elemental subroutine.
338 X must be REAL(4) and the result is of the same type. The accuracy is system
345 yields the time in elapsed seconds since X. If X is 0.0, T is the time in
346 seconds since midnight. Note that a time that spans midnight but is less than
347 24hours will be calculated correctly. */
349 extern GFC_REAL_4 secnds (GFC_REAL_4 *);
350 export_proto(secnds);
353 secnds (GFC_REAL_4 *x)
355 GFC_INTEGER_4 values[VALUES_SIZE];
356 GFC_REAL_4 temp1, temp2;
358 /* Make the INTEGER*4 array for passing to date_and_time. */
359 gfc_array_i4 *avalues = internal_malloc_size (sizeof (gfc_array_i4));
360 avalues->data = &values[0];
361 GFC_DESCRIPTOR_DTYPE (avalues) = ((GFC_DTYPE_REAL << GFC_DTYPE_TYPE_SHIFT)
362 & GFC_DTYPE_TYPE_MASK) +
363 (4 << GFC_DTYPE_SIZE_SHIFT);
365 GFC_DIMENSION_SET(avalues->dim[0], 0, 7, 1);
367 date_and_time (NULL, NULL, NULL, avalues, 0, 0, 0);
371 temp1 = 3600.0 * (GFC_REAL_4)values[4] +
372 60.0 * (GFC_REAL_4)values[5] +
373 (GFC_REAL_4)values[6] +
374 0.001 * (GFC_REAL_4)values[7];
375 temp2 = fmod (*x, 86400.0);
376 temp2 = (temp1 - temp2 >= 0.0) ? temp2 : (temp2 - 86400.0);
377 return temp1 - temp2;
382 /* ITIME(X) - Non-standard
384 Description: Returns the current local time hour, minutes, and seconds
385 in elements 1, 2, and 3 of X, respectively. */
390 #ifndef HAVE_NO_DATE_TIME
392 struct tm local_time;
396 if (lt != (time_t) -1)
398 localtime_r (<, &local_time);
400 x[0] = local_time.tm_hour;
401 x[1] = local_time.tm_min;
402 x[2] = local_time.tm_sec;
405 x[0] = x[1] = x[2] = -1;
409 extern void itime_i4 (gfc_array_i4 *);
410 export_proto(itime_i4);
413 itime_i4 (gfc_array_i4 *__values)
416 index_type len, delta;
419 /* Call helper function. */
422 /* Copy the value into the array. */
423 len = GFC_DESCRIPTOR_EXTENT(__values,0);
425 delta = GFC_DESCRIPTOR_STRIDE(__values,0);
429 vptr = __values->data;
430 for (i = 0; i < 3; i++, vptr += delta)
435 extern void itime_i8 (gfc_array_i8 *);
436 export_proto(itime_i8);
439 itime_i8 (gfc_array_i8 *__values)
442 index_type len, delta;
445 /* Call helper function. */
448 /* Copy the value into the array. */
449 len = GFC_DESCRIPTOR_EXTENT(__values,0);
451 delta = GFC_DESCRIPTOR_STRIDE(__values,0);
455 vptr = __values->data;
456 for (i = 0; i < 3; i++, vptr += delta)
462 /* IDATE(X) - Non-standard
464 Description: Fills TArray with the numerical values at the current
465 local time. The day (in the range 1-31), month (in the range 1-12),
466 and year appear in elements 1, 2, and 3 of X, respectively.
467 The year has four significant digits. */
472 #ifndef HAVE_NO_DATE_TIME
474 struct tm local_time;
478 if (lt != (time_t) -1)
480 localtime_r (<, &local_time);
482 x[0] = local_time.tm_mday;
483 x[1] = 1 + local_time.tm_mon;
484 x[2] = 1900 + local_time.tm_year;
487 x[0] = x[1] = x[2] = -1;
491 extern void idate_i4 (gfc_array_i4 *);
492 export_proto(idate_i4);
495 idate_i4 (gfc_array_i4 *__values)
498 index_type len, delta;
501 /* Call helper function. */
504 /* Copy the value into the array. */
505 len = GFC_DESCRIPTOR_EXTENT(__values,0);
507 delta = GFC_DESCRIPTOR_STRIDE(__values,0);
511 vptr = __values->data;
512 for (i = 0; i < 3; i++, vptr += delta)
517 extern void idate_i8 (gfc_array_i8 *);
518 export_proto(idate_i8);
521 idate_i8 (gfc_array_i8 *__values)
524 index_type len, delta;
527 /* Call helper function. */
530 /* Copy the value into the array. */
531 len = GFC_DESCRIPTOR_EXTENT(__values,0);
533 delta = GFC_DESCRIPTOR_STRIDE(__values,0);
537 vptr = __values->data;
538 for (i = 0; i < 3; i++, vptr += delta)
544 /* GMTIME(STIME, TARRAY) - Non-standard
546 Description: Given a system time value STime, fills TArray with values
547 extracted from it appropriate to the GMT time zone using gmtime_r(3).
549 The array elements are as follows:
551 1. Seconds after the minute, range 0-59 or 0-61 to allow for leap seconds
552 2. Minutes after the hour, range 0-59
553 3. Hours past midnight, range 0-23
554 4. Day of month, range 0-31
555 5. Number of months since January, range 0-11
557 7. Number of days since Sunday, range 0-6
558 8. Days since January 1
559 9. Daylight savings indicator: positive if daylight savings is in effect,
560 zero if not, and negative if the information isn't available. */
563 gmtime_0 (const time_t * t, int x[9])
579 extern void gmtime_i4 (GFC_INTEGER_4 *, gfc_array_i4 *);
580 export_proto(gmtime_i4);
583 gmtime_i4 (GFC_INTEGER_4 * t, gfc_array_i4 * tarray)
586 index_type len, delta;
590 /* Call helper function. */
594 /* Copy the values into the array. */
595 len = GFC_DESCRIPTOR_EXTENT(tarray,0);
597 delta = GFC_DESCRIPTOR_STRIDE(tarray,0);
602 for (i = 0; i < 9; i++, vptr += delta)
606 extern void gmtime_i8 (GFC_INTEGER_8 *, gfc_array_i8 *);
607 export_proto(gmtime_i8);
610 gmtime_i8 (GFC_INTEGER_8 * t, gfc_array_i8 * tarray)
613 index_type len, delta;
617 /* Call helper function. */
621 /* Copy the values into the array. */
622 len = GFC_DESCRIPTOR_EXTENT(tarray,0);
624 delta = GFC_DESCRIPTOR_STRIDE(tarray,0);
629 for (i = 0; i < 9; i++, vptr += delta)
636 /* LTIME(STIME, TARRAY) - Non-standard
638 Description: Given a system time value STime, fills TArray with values
639 extracted from it appropriate to the local time zone using localtime_r(3).
641 The array elements are as follows:
643 1. Seconds after the minute, range 0-59 or 0-61 to allow for leap seconds
644 2. Minutes after the hour, range 0-59
645 3. Hours past midnight, range 0-23
646 4. Day of month, range 0-31
647 5. Number of months since January, range 0-11
649 7. Number of days since Sunday, range 0-6
650 8. Days since January 1
651 9. Daylight savings indicator: positive if daylight savings is in effect,
652 zero if not, and negative if the information isn't available. */
655 ltime_0 (const time_t * t, int x[9])
659 localtime_r (t, <);
671 extern void ltime_i4 (GFC_INTEGER_4 *, gfc_array_i4 *);
672 export_proto(ltime_i4);
675 ltime_i4 (GFC_INTEGER_4 * t, gfc_array_i4 * tarray)
678 index_type len, delta;
682 /* Call helper function. */
686 /* Copy the values into the array. */
687 len = GFC_DESCRIPTOR_EXTENT(tarray,0);
689 delta = GFC_DESCRIPTOR_STRIDE(tarray,0);
694 for (i = 0; i < 9; i++, vptr += delta)
698 extern void ltime_i8 (GFC_INTEGER_8 *, gfc_array_i8 *);
699 export_proto(ltime_i8);
702 ltime_i8 (GFC_INTEGER_8 * t, gfc_array_i8 * tarray)
705 index_type len, delta;
709 /* Call helper function. */
713 /* Copy the values into the array. */
714 len = GFC_DESCRIPTOR_EXTENT(tarray,0);
716 delta = GFC_DESCRIPTOR_STRIDE(tarray,0);
721 for (i = 0; i < 9; i++, vptr += delta)