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 if (unlikely (len
< VALUES_SIZE
))
285 runtime_error ("Incorrect extent in VALUE argument to"
286 " DATE_AND_TIME intrinsic: is %ld, should"
287 " be >=%ld", (long int) len
, (long int) VALUES_SIZE
);
289 /* Cope with different type kinds. */
292 GFC_INTEGER_4
*vptr4
= __values
->data
;
294 for (i
= 0; i
< VALUES_SIZE
; i
++, vptr4
+= delta
)
297 else if (elt_size
== 8)
299 GFC_INTEGER_8
*vptr8
= (GFC_INTEGER_8
*)__values
->data
;
301 for (i
= 0; i
< VALUES_SIZE
; i
++, vptr8
+= delta
)
303 if (values
[i
] == - GFC_INTEGER_4_HUGE
)
304 *vptr8
= - GFC_INTEGER_8_HUGE
;
315 assert (__zone_len
>= ZONE_LEN
);
316 fstrcpy (__zone
, ZONE_LEN
, zone
, ZONE_LEN
);
321 assert (__time_len
>= TIME_LEN
);
322 fstrcpy (__time
, TIME_LEN
, timec
, TIME_LEN
);
327 assert (__date_len
>= DATE_LEN
);
328 fstrcpy (__date
, DATE_LEN
, date
, DATE_LEN
);
333 /* SECNDS (X) - Non-standard
335 Description: Returns the system time of day, or elapsed time, as a GFC_REAL_4
338 Class: Non-elemental subroutine.
342 X must be REAL(4) and the result is of the same type. The accuracy is system
349 yields the time in elapsed seconds since X. If X is 0.0, T is the time in
350 seconds since midnight. Note that a time that spans midnight but is less than
351 24hours will be calculated correctly. */
353 extern GFC_REAL_4
secnds (GFC_REAL_4
*);
354 export_proto(secnds
);
357 secnds (GFC_REAL_4
*x
)
359 GFC_INTEGER_4 values
[VALUES_SIZE
];
360 GFC_REAL_4 temp1
, temp2
;
362 /* Make the INTEGER*4 array for passing to date_and_time. */
363 gfc_array_i4
*avalues
= internal_malloc_size (sizeof (gfc_array_i4
));
364 avalues
->data
= &values
[0];
365 GFC_DESCRIPTOR_DTYPE (avalues
) = ((GFC_DTYPE_REAL
<< GFC_DTYPE_TYPE_SHIFT
)
366 & GFC_DTYPE_TYPE_MASK
) +
367 (4 << GFC_DTYPE_SIZE_SHIFT
);
369 GFC_DIMENSION_SET(avalues
->dim
[0], 0, 7, 1);
371 date_and_time (NULL
, NULL
, NULL
, avalues
, 0, 0, 0);
375 temp1
= 3600.0 * (GFC_REAL_4
)values
[4] +
376 60.0 * (GFC_REAL_4
)values
[5] +
377 (GFC_REAL_4
)values
[6] +
378 0.001 * (GFC_REAL_4
)values
[7];
379 temp2
= fmod (*x
, 86400.0);
380 temp2
= (temp1
- temp2
>= 0.0) ? temp2
: (temp2
- 86400.0);
381 return temp1
- temp2
;
386 /* ITIME(X) - Non-standard
388 Description: Returns the current local time hour, minutes, and seconds
389 in elements 1, 2, and 3 of X, respectively. */
394 #ifndef HAVE_NO_DATE_TIME
396 struct tm local_time
;
400 if (lt
!= (time_t) -1)
402 localtime_r (<
, &local_time
);
404 x
[0] = local_time
.tm_hour
;
405 x
[1] = local_time
.tm_min
;
406 x
[2] = local_time
.tm_sec
;
409 x
[0] = x
[1] = x
[2] = -1;
413 extern void itime_i4 (gfc_array_i4
*);
414 export_proto(itime_i4
);
417 itime_i4 (gfc_array_i4
*__values
)
420 index_type len
, delta
;
423 /* Call helper function. */
426 /* Copy the value into the array. */
427 len
= GFC_DESCRIPTOR_EXTENT(__values
,0);
429 delta
= GFC_DESCRIPTOR_STRIDE(__values
,0);
433 vptr
= __values
->data
;
434 for (i
= 0; i
< 3; i
++, vptr
+= delta
)
439 extern void itime_i8 (gfc_array_i8
*);
440 export_proto(itime_i8
);
443 itime_i8 (gfc_array_i8
*__values
)
446 index_type len
, delta
;
449 /* Call helper function. */
452 /* Copy the value into the array. */
453 len
= GFC_DESCRIPTOR_EXTENT(__values
,0);
455 delta
= GFC_DESCRIPTOR_STRIDE(__values
,0);
459 vptr
= __values
->data
;
460 for (i
= 0; i
< 3; i
++, vptr
+= delta
)
466 /* IDATE(X) - Non-standard
468 Description: Fills TArray with the numerical values at the current
469 local time. The day (in the range 1-31), month (in the range 1-12),
470 and year appear in elements 1, 2, and 3 of X, respectively.
471 The year has four significant digits. */
476 #ifndef HAVE_NO_DATE_TIME
478 struct tm local_time
;
482 if (lt
!= (time_t) -1)
484 localtime_r (<
, &local_time
);
486 x
[0] = local_time
.tm_mday
;
487 x
[1] = 1 + local_time
.tm_mon
;
488 x
[2] = 1900 + local_time
.tm_year
;
491 x
[0] = x
[1] = x
[2] = -1;
495 extern void idate_i4 (gfc_array_i4
*);
496 export_proto(idate_i4
);
499 idate_i4 (gfc_array_i4
*__values
)
502 index_type len
, delta
;
505 /* Call helper function. */
508 /* Copy the value into the array. */
509 len
= GFC_DESCRIPTOR_EXTENT(__values
,0);
511 delta
= GFC_DESCRIPTOR_STRIDE(__values
,0);
515 vptr
= __values
->data
;
516 for (i
= 0; i
< 3; i
++, vptr
+= delta
)
521 extern void idate_i8 (gfc_array_i8
*);
522 export_proto(idate_i8
);
525 idate_i8 (gfc_array_i8
*__values
)
528 index_type len
, delta
;
531 /* Call helper function. */
534 /* Copy the value into the array. */
535 len
= GFC_DESCRIPTOR_EXTENT(__values
,0);
537 delta
= GFC_DESCRIPTOR_STRIDE(__values
,0);
541 vptr
= __values
->data
;
542 for (i
= 0; i
< 3; i
++, vptr
+= delta
)
548 /* GMTIME(STIME, TARRAY) - Non-standard
550 Description: Given a system time value STime, fills TArray with values
551 extracted from it appropriate to the GMT time zone using gmtime_r(3).
553 The array elements are as follows:
555 1. Seconds after the minute, range 0-59 or 0-61 to allow for leap seconds
556 2. Minutes after the hour, range 0-59
557 3. Hours past midnight, range 0-23
558 4. Day of month, range 0-31
559 5. Number of months since January, range 0-11
561 7. Number of days since Sunday, range 0-6
562 8. Days since January 1
563 9. Daylight savings indicator: positive if daylight savings is in effect,
564 zero if not, and negative if the information isn't available. */
567 gmtime_0 (const time_t * t
, int x
[9])
583 extern void gmtime_i4 (GFC_INTEGER_4
*, gfc_array_i4
*);
584 export_proto(gmtime_i4
);
587 gmtime_i4 (GFC_INTEGER_4
* t
, gfc_array_i4
* tarray
)
590 index_type len
, delta
;
594 /* Call helper function. */
598 /* Copy the values into the array. */
599 len
= GFC_DESCRIPTOR_EXTENT(tarray
,0);
601 delta
= GFC_DESCRIPTOR_STRIDE(tarray
,0);
606 for (i
= 0; i
< 9; i
++, vptr
+= delta
)
610 extern void gmtime_i8 (GFC_INTEGER_8
*, gfc_array_i8
*);
611 export_proto(gmtime_i8
);
614 gmtime_i8 (GFC_INTEGER_8
* t
, gfc_array_i8
* tarray
)
617 index_type len
, delta
;
621 /* Call helper function. */
625 /* Copy the values into the array. */
626 len
= GFC_DESCRIPTOR_EXTENT(tarray
,0);
628 delta
= GFC_DESCRIPTOR_STRIDE(tarray
,0);
633 for (i
= 0; i
< 9; i
++, vptr
+= delta
)
640 /* LTIME(STIME, TARRAY) - Non-standard
642 Description: Given a system time value STime, fills TArray with values
643 extracted from it appropriate to the local time zone using localtime_r(3).
645 The array elements are as follows:
647 1. Seconds after the minute, range 0-59 or 0-61 to allow for leap seconds
648 2. Minutes after the hour, range 0-59
649 3. Hours past midnight, range 0-23
650 4. Day of month, range 0-31
651 5. Number of months since January, range 0-11
653 7. Number of days since Sunday, range 0-6
654 8. Days since January 1
655 9. Daylight savings indicator: positive if daylight savings is in effect,
656 zero if not, and negative if the information isn't available. */
659 ltime_0 (const time_t * t
, int x
[9])
663 localtime_r (t
, <
);
675 extern void ltime_i4 (GFC_INTEGER_4
*, gfc_array_i4
*);
676 export_proto(ltime_i4
);
679 ltime_i4 (GFC_INTEGER_4
* t
, gfc_array_i4
* tarray
)
682 index_type len
, delta
;
686 /* Call helper function. */
690 /* Copy the values into the array. */
691 len
= GFC_DESCRIPTOR_EXTENT(tarray
,0);
693 delta
= GFC_DESCRIPTOR_STRIDE(tarray
,0);
698 for (i
= 0; i
< 9; i
++, vptr
+= delta
)
702 extern void ltime_i8 (GFC_INTEGER_8
*, gfc_array_i8
*);
703 export_proto(ltime_i8
);
706 ltime_i8 (GFC_INTEGER_8
* t
, gfc_array_i8
* tarray
)
709 index_type len
, delta
;
713 /* Call helper function. */
717 /* Copy the values into the array. */
718 len
= GFC_DESCRIPTOR_EXTENT(tarray
,0);
720 delta
= GFC_DESCRIPTOR_STRIDE(tarray
,0);
725 for (i
= 0; i
< 9; i
++, vptr
+= delta
)