1 /* Implementation of the DATE_AND_TIME intrinsic.
2 Copyright (C) 2003, 2004, 2005, 2006, 2007, 2009, 2010, 2011
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"
35 #define abs(x) ((x)>=0 ? (x) : -(x))
39 /* If the re-entrant version of gmtime is not available, provide a
40 fallback implementation. On some targets where the _r version is
41 not available, gmtime uses thread-local storage so it's
45 /* If _POSIX is defined gmtime_r gets defined by mingw-w64 headers. */
51 gmtime_r (const time_t * timep, struct tm * result)
53 *result = *gmtime (timep);
59 /* DATE_AND_TIME ([DATE, TIME, ZONE, VALUES])
61 Description: Returns data on the real-time clock and date in a form
62 compatible with the representations defined in ISO 8601:1988.
64 Class: Non-elemental subroutine.
68 DATE (optional) shall be scalar and of type default character.
69 It is an INTENT(OUT) argument. It is assigned a value of the
70 form CCYYMMDD, where CC is the century, YY the year within the
71 century, MM the month within the year, and DD the day within the
72 month. If there is no date available, they are assigned blanks.
74 TIME (optional) shall be scalar and of type default character.
75 It is an INTENT(OUT) argument. It is assigned a value of the
76 form hhmmss.sss, where hh is the hour of the day, mm is the
77 minutes of the hour, and ss.sss is the seconds and milliseconds
78 of the minute. If there is no clock available, they are assigned
81 ZONE (optional) shall be scalar and of type default character.
82 It is an INTENT(OUT) argument. It is assigned a value of the
83 form [+-]hhmm, where hh and mm are the time difference with
84 respect to Coordinated Universal Time (UTC) in hours and parts
85 of an hour expressed in minutes, respectively. If there is no
86 clock available, they are assigned blanks.
88 VALUES (optional) shall be of type default integer and of rank
89 one. It is an INTENT(OUT) argument. Its size shall be at least
90 8. The values returned in VALUES are as follows:
92 VALUES(1) the year (for example, 2003), or -HUGE(0) if there is
95 VALUES(2) the month of the year, or -HUGE(0) if there
98 VALUES(3) the day of the month, or -HUGE(0) if there is no date
101 VALUES(4) the time difference with respect to Coordinated
102 Universal Time (UTC) in minutes, or -HUGE(0) if this information
105 VALUES(5) the hour of the day, in the range of 0 to 23, or
106 -HUGE(0) if there is no clock;
108 VALUES(6) the minutes of the hour, in the range 0 to 59, or
109 -HUGE(0) if there is no clock;
111 VALUES(7) the seconds of the minute, in the range 0 to 60, or
112 -HUGE(0) if there is no clock;
114 VALUES(8) the milliseconds of the second, in the range 0 to
115 999, or -HUGE(0) if there is no clock.
117 NULL pointer represent missing OPTIONAL arguments. All arguments
118 have INTENT(OUT). Because of the -i8 option, we must implement
119 VALUES for INTEGER(kind=4) and INTEGER(kind=8).
121 Based on libU77's date_time_.c.
124 - Check year boundaries.
129 #define VALUES_SIZE 8
131 extern void date_and_time (char *, char *, char *, gfc_array_i4 *,
132 GFC_INTEGER_4, GFC_INTEGER_4, GFC_INTEGER_4);
133 export_proto(date_and_time);
136 date_and_time (char *__date, char *__time, char *__zone,
137 gfc_array_i4 *__values, GFC_INTEGER_4 __date_len,
138 GFC_INTEGER_4 __time_len, GFC_INTEGER_4 __zone_len)
141 char date[DATE_LEN + 1];
142 char timec[TIME_LEN + 1];
143 char zone[ZONE_LEN + 1];
144 GFC_INTEGER_4 values[VALUES_SIZE];
146 #ifndef HAVE_NO_DATE_TIME
148 struct tm local_time;
153 if (!gf_gettime (<, &usecs))
155 values[7] = usecs / 1000;
157 localtime_r (<, &local_time);
158 gmtime_r (<, &UTC_time);
160 /* All arguments can be derived from VALUES. */
161 values[0] = 1900 + local_time.tm_year;
162 values[1] = 1 + local_time.tm_mon;
163 values[2] = local_time.tm_mday;
164 values[3] = (local_time.tm_min - UTC_time.tm_min +
165 60 * (local_time.tm_hour - UTC_time.tm_hour +
166 24 * (local_time.tm_yday - UTC_time.tm_yday)));
167 values[4] = local_time.tm_hour;
168 values[5] = local_time.tm_min;
169 values[6] = local_time.tm_sec;
173 snprintf (date, DATE_LEN + 1, "%04d%02d%02d",
174 values[0], values[1], values[2]);
176 snprintf (timec, TIME_LEN + 1, "%02d%02d%02d.%03d",
177 values[4], values[5], values[6], values[7]);
180 snprintf (zone, ZONE_LEN + 1, "%+03d%02d",
181 values[3] / 60, abs (values[3] % 60));
184 sprintf (date, "%04d%02d%02d", values[0], values[1], values[2]);
187 sprintf (timec, "%02d%02d%02d.%03d",
188 values[4], values[5], values[6], values[7]);
191 sprintf (zone, "%+03d%02d",
192 values[3] / 60, abs (values[3] % 60));
197 memset (date, ' ', DATE_LEN);
198 date[DATE_LEN] = '\0';
200 memset (timec, ' ', TIME_LEN);
201 timec[TIME_LEN] = '\0';
203 memset (zone, ' ', ZONE_LEN);
204 zone[ZONE_LEN] = '\0';
206 for (i = 0; i < VALUES_SIZE; i++)
207 values[i] = - GFC_INTEGER_4_HUGE;
209 #else /* if defined HAVE_NO_DATE_TIME */
210 /* We really have *nothing* to return, so return blanks and HUGE(0). */
212 memset (date, ' ', DATE_LEN);
213 date[DATE_LEN] = '\0';
215 memset (timec, ' ', TIME_LEN);
216 timec[TIME_LEN] = '\0';
218 memset (zone, ' ', ZONE_LEN);
219 zone[ZONE_LEN] = '\0';
221 for (i = 0; i < VALUES_SIZE; i++)
222 values[i] = - GFC_INTEGER_4_HUGE;
223 #endif /* HAVE_NO_DATE_TIME */
225 /* Copy the values into the arguments. */
228 index_type len, delta, elt_size;
230 elt_size = GFC_DESCRIPTOR_SIZE (__values);
231 len = GFC_DESCRIPTOR_EXTENT(__values,0);
232 delta = GFC_DESCRIPTOR_STRIDE(__values,0);
236 if (unlikely (len < VALUES_SIZE))
237 runtime_error ("Incorrect extent in VALUE argument to"
238 " DATE_AND_TIME intrinsic: is %ld, should"
239 " be >=%ld", (long int) len, (long int) VALUES_SIZE);
241 /* Cope with different type kinds. */
244 GFC_INTEGER_4 *vptr4 = __values->data;
246 for (i = 0; i < VALUES_SIZE; i++, vptr4 += delta)
249 else if (elt_size == 8)
251 GFC_INTEGER_8 *vptr8 = (GFC_INTEGER_8 *)__values->data;
253 for (i = 0; i < VALUES_SIZE; i++, vptr8 += delta)
255 if (values[i] == - GFC_INTEGER_4_HUGE)
256 *vptr8 = - GFC_INTEGER_8_HUGE;
266 fstrcpy (__zone, __zone_len, zone, ZONE_LEN);
269 fstrcpy (__time, __time_len, timec, TIME_LEN);
272 fstrcpy (__date, __date_len, date, DATE_LEN);
276 /* SECNDS (X) - Non-standard
278 Description: Returns the system time of day, or elapsed time, as a GFC_REAL_4
281 Class: Non-elemental subroutine.
285 X must be REAL(4) and the result is of the same type. The accuracy is system
292 yields the time in elapsed seconds since X. If X is 0.0, T is the time in
293 seconds since midnight. Note that a time that spans midnight but is less than
294 24hours will be calculated correctly. */
296 extern GFC_REAL_4 secnds (GFC_REAL_4 *);
297 export_proto(secnds);
300 secnds (GFC_REAL_4 *x)
302 GFC_INTEGER_4 values[VALUES_SIZE];
303 GFC_REAL_4 temp1, temp2;
305 /* Make the INTEGER*4 array for passing to date_and_time. */
306 gfc_array_i4 *avalues = internal_malloc_size (sizeof (gfc_array_i4));
307 avalues->data = &values[0];
308 GFC_DESCRIPTOR_DTYPE (avalues) = ((BT_REAL << GFC_DTYPE_TYPE_SHIFT)
309 & GFC_DTYPE_TYPE_MASK) +
310 (4 << GFC_DTYPE_SIZE_SHIFT);
312 GFC_DIMENSION_SET(avalues->dim[0], 0, 7, 1);
314 date_and_time (NULL, NULL, NULL, avalues, 0, 0, 0);
318 temp1 = 3600.0 * (GFC_REAL_4)values[4] +
319 60.0 * (GFC_REAL_4)values[5] +
320 (GFC_REAL_4)values[6] +
321 0.001 * (GFC_REAL_4)values[7];
322 temp2 = fmod (*x, 86400.0);
323 temp2 = (temp1 - temp2 >= 0.0) ? temp2 : (temp2 - 86400.0);
324 return temp1 - temp2;
329 /* ITIME(X) - Non-standard
331 Description: Returns the current local time hour, minutes, and seconds
332 in elements 1, 2, and 3 of X, respectively. */
337 #ifndef HAVE_NO_DATE_TIME
339 struct tm local_time;
343 if (lt != (time_t) -1)
345 localtime_r (<, &local_time);
347 x[0] = local_time.tm_hour;
348 x[1] = local_time.tm_min;
349 x[2] = local_time.tm_sec;
352 x[0] = x[1] = x[2] = -1;
356 extern void itime_i4 (gfc_array_i4 *);
357 export_proto(itime_i4);
360 itime_i4 (gfc_array_i4 *__values)
363 index_type len, delta;
366 /* Call helper function. */
369 /* Copy the value into the array. */
370 len = GFC_DESCRIPTOR_EXTENT(__values,0);
372 delta = GFC_DESCRIPTOR_STRIDE(__values,0);
376 vptr = __values->data;
377 for (i = 0; i < 3; i++, vptr += delta)
382 extern void itime_i8 (gfc_array_i8 *);
383 export_proto(itime_i8);
386 itime_i8 (gfc_array_i8 *__values)
389 index_type len, delta;
392 /* Call helper function. */
395 /* Copy the value into the array. */
396 len = GFC_DESCRIPTOR_EXTENT(__values,0);
398 delta = GFC_DESCRIPTOR_STRIDE(__values,0);
402 vptr = __values->data;
403 for (i = 0; i < 3; i++, vptr += delta)
409 /* IDATE(X) - Non-standard
411 Description: Fills TArray with the numerical values at the current
412 local time. The day (in the range 1-31), month (in the range 1-12),
413 and year appear in elements 1, 2, and 3 of X, respectively.
414 The year has four significant digits. */
419 #ifndef HAVE_NO_DATE_TIME
421 struct tm local_time;
425 if (lt != (time_t) -1)
427 localtime_r (<, &local_time);
429 x[0] = local_time.tm_mday;
430 x[1] = 1 + local_time.tm_mon;
431 x[2] = 1900 + local_time.tm_year;
434 x[0] = x[1] = x[2] = -1;
438 extern void idate_i4 (gfc_array_i4 *);
439 export_proto(idate_i4);
442 idate_i4 (gfc_array_i4 *__values)
445 index_type len, delta;
448 /* Call helper function. */
451 /* Copy the value into the array. */
452 len = GFC_DESCRIPTOR_EXTENT(__values,0);
454 delta = GFC_DESCRIPTOR_STRIDE(__values,0);
458 vptr = __values->data;
459 for (i = 0; i < 3; i++, vptr += delta)
464 extern void idate_i8 (gfc_array_i8 *);
465 export_proto(idate_i8);
468 idate_i8 (gfc_array_i8 *__values)
471 index_type len, delta;
474 /* Call helper function. */
477 /* Copy the value into the array. */
478 len = GFC_DESCRIPTOR_EXTENT(__values,0);
480 delta = GFC_DESCRIPTOR_STRIDE(__values,0);
484 vptr = __values->data;
485 for (i = 0; i < 3; i++, vptr += delta)
491 /* GMTIME(STIME, TARRAY) - Non-standard
493 Description: Given a system time value STime, fills TArray with values
494 extracted from it appropriate to the GMT time zone using gmtime_r(3).
496 The array elements are as follows:
498 1. Seconds after the minute, range 0-59 or 0-61 to allow for leap seconds
499 2. Minutes after the hour, range 0-59
500 3. Hours past midnight, range 0-23
501 4. Day of month, range 0-31
502 5. Number of months since January, range 0-11
504 7. Number of days since Sunday, range 0-6
505 8. Days since January 1
506 9. Daylight savings indicator: positive if daylight savings is in effect,
507 zero if not, and negative if the information isn't available. */
510 gmtime_0 (const time_t * t, int x[9])
526 extern void gmtime_i4 (GFC_INTEGER_4 *, gfc_array_i4 *);
527 export_proto(gmtime_i4);
530 gmtime_i4 (GFC_INTEGER_4 * t, gfc_array_i4 * tarray)
533 index_type len, delta;
537 /* Call helper function. */
541 /* Copy the values into the array. */
542 len = GFC_DESCRIPTOR_EXTENT(tarray,0);
544 delta = GFC_DESCRIPTOR_STRIDE(tarray,0);
549 for (i = 0; i < 9; i++, vptr += delta)
553 extern void gmtime_i8 (GFC_INTEGER_8 *, gfc_array_i8 *);
554 export_proto(gmtime_i8);
557 gmtime_i8 (GFC_INTEGER_8 * t, gfc_array_i8 * tarray)
560 index_type len, delta;
564 /* Call helper function. */
568 /* Copy the values into the array. */
569 len = GFC_DESCRIPTOR_EXTENT(tarray,0);
571 delta = GFC_DESCRIPTOR_STRIDE(tarray,0);
576 for (i = 0; i < 9; i++, vptr += delta)
583 /* LTIME(STIME, TARRAY) - Non-standard
585 Description: Given a system time value STime, fills TArray with values
586 extracted from it appropriate to the local time zone using localtime_r(3).
588 The array elements are as follows:
590 1. Seconds after the minute, range 0-59 or 0-61 to allow for leap seconds
591 2. Minutes after the hour, range 0-59
592 3. Hours past midnight, range 0-23
593 4. Day of month, range 0-31
594 5. Number of months since January, range 0-11
596 7. Number of days since Sunday, range 0-6
597 8. Days since January 1
598 9. Daylight savings indicator: positive if daylight savings is in effect,
599 zero if not, and negative if the information isn't available. */
602 ltime_0 (const time_t * t, int x[9])
606 localtime_r (t, <);
618 extern void ltime_i4 (GFC_INTEGER_4 *, gfc_array_i4 *);
619 export_proto(ltime_i4);
622 ltime_i4 (GFC_INTEGER_4 * t, gfc_array_i4 * tarray)
625 index_type len, delta;
629 /* Call helper function. */
633 /* Copy the values into the array. */
634 len = GFC_DESCRIPTOR_EXTENT(tarray,0);
636 delta = GFC_DESCRIPTOR_STRIDE(tarray,0);
641 for (i = 0; i < 9; i++, vptr += delta)
645 extern void ltime_i8 (GFC_INTEGER_8 *, gfc_array_i8 *);
646 export_proto(ltime_i8);
649 ltime_i8 (GFC_INTEGER_8 * t, gfc_array_i8 * tarray)
652 index_type len, delta;
656 /* Call helper function. */
660 /* Copy the values into the array. */
661 len = GFC_DESCRIPTOR_EXTENT(tarray,0);
663 delta = GFC_DESCRIPTOR_STRIDE(tarray,0);
668 for (i = 0; i < 9; i++, vptr += delta)