1 /* Implementation of the DATE_AND_TIME intrinsic.
2 Copyright (C) 2003-2017 Free Software Foundation, Inc.
3 Contributed by Steven Bosscher.
5 This file is part of the GNU Fortran 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"
33 /* If the re-entrant version of gmtime is not available, provide a
34 fallback implementation. On some targets where the _r version is
35 not available, gmtime uses thread-local storage so it's
39 /* If _POSIX is defined gmtime_r gets defined by mingw-w64 headers. */
45 gmtime_r (const time_t * timep
, struct tm
* result
)
47 *result
= *gmtime (timep
);
53 /* DATE_AND_TIME ([DATE, TIME, ZONE, VALUES])
55 Description: Returns data on the real-time clock and date in a form
56 compatible with the representations defined in ISO 8601:1988.
58 Class: Non-elemental subroutine.
62 DATE (optional) shall be scalar and of type default character.
63 It is an INTENT(OUT) argument. It is assigned a value of the
64 form CCYYMMDD, where CC is the century, YY the year within the
65 century, MM the month within the year, and DD the day within the
66 month. If there is no date available, they are assigned blanks.
68 TIME (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 hhmmss.sss, where hh is the hour of the day, mm is the
71 minutes of the hour, and ss.sss is the seconds and milliseconds
72 of the minute. If there is no clock available, they are assigned
75 ZONE (optional) shall be scalar and of type default character.
76 It is an INTENT(OUT) argument. It is assigned a value of the
77 form [+-]hhmm, where hh and mm are the time difference with
78 respect to Coordinated Universal Time (UTC) in hours and parts
79 of an hour expressed in minutes, respectively. If there is no
80 clock available, they are assigned blanks.
82 VALUES (optional) shall be of type default integer and of rank
83 one. It is an INTENT(OUT) argument. Its size shall be at least
84 8. The values returned in VALUES are as follows:
86 VALUES(1) the year (for example, 2003), or -HUGE(0) if there is
89 VALUES(2) the month of the year, or -HUGE(0) if there
92 VALUES(3) the day of the month, or -HUGE(0) if there is no date
95 VALUES(4) the time difference with respect to Coordinated
96 Universal Time (UTC) in minutes, or -HUGE(0) if this information
99 VALUES(5) the hour of the day, in the range of 0 to 23, or
100 -HUGE(0) if there is no clock;
102 VALUES(6) the minutes of the hour, in the range 0 to 59, or
103 -HUGE(0) if there is no clock;
105 VALUES(7) the seconds of the minute, in the range 0 to 60, or
106 -HUGE(0) if there is no clock;
108 VALUES(8) the milliseconds of the second, in the range 0 to
109 999, or -HUGE(0) if there is no clock.
111 NULL pointer represent missing OPTIONAL arguments. All arguments
112 have INTENT(OUT). Because of the -i8 option, we must implement
113 VALUES for INTEGER(kind=4) and INTEGER(kind=8).
115 Based on libU77's date_time_.c.
118 - Check year boundaries.
123 #define VALUES_SIZE 8
125 extern void date_and_time (char *, char *, char *, gfc_array_i4
*,
126 GFC_INTEGER_4
, GFC_INTEGER_4
, GFC_INTEGER_4
);
127 export_proto(date_and_time
);
130 date_and_time (char *__date
, char *__time
, char *__zone
,
131 gfc_array_i4
*__values
, GFC_INTEGER_4 __date_len
,
132 GFC_INTEGER_4 __time_len
, GFC_INTEGER_4 __zone_len
)
135 char date
[DATE_LEN
+ 1];
136 char timec
[TIME_LEN
+ 1];
137 char zone
[ZONE_LEN
+ 1];
138 GFC_INTEGER_4 values
[VALUES_SIZE
];
141 struct tm local_time
;
146 if (!gf_gettime (<
, &usecs
))
148 values
[7] = usecs
/ 1000;
150 localtime_r (<
, &local_time
);
151 gmtime_r (<
, &UTC_time
);
153 /* All arguments can be derived from VALUES. */
154 values
[0] = 1900 + local_time
.tm_year
;
155 values
[1] = 1 + local_time
.tm_mon
;
156 values
[2] = local_time
.tm_mday
;
157 values
[3] = (local_time
.tm_min
- UTC_time
.tm_min
+
158 60 * (local_time
.tm_hour
- UTC_time
.tm_hour
+
159 24 * (local_time
.tm_yday
- UTC_time
.tm_yday
)));
160 values
[4] = local_time
.tm_hour
;
161 values
[5] = local_time
.tm_min
;
162 values
[6] = local_time
.tm_sec
;
165 snprintf (date
, DATE_LEN
+ 1, "%04d%02d%02d",
166 values
[0], values
[1], values
[2]);
168 snprintf (timec
, TIME_LEN
+ 1, "%02d%02d%02d.%03d",
169 values
[4], values
[5], values
[6], values
[7]);
172 snprintf (zone
, ZONE_LEN
+ 1, "%+03d%02d",
173 values
[3] / 60, abs (values
[3] % 60));
177 memset (date
, ' ', DATE_LEN
);
178 date
[DATE_LEN
] = '\0';
180 memset (timec
, ' ', TIME_LEN
);
181 timec
[TIME_LEN
] = '\0';
183 memset (zone
, ' ', ZONE_LEN
);
184 zone
[ZONE_LEN
] = '\0';
186 for (i
= 0; i
< VALUES_SIZE
; i
++)
187 values
[i
] = - GFC_INTEGER_4_HUGE
;
190 /* Copy the values into the arguments. */
193 index_type len
, delta
, elt_size
;
195 elt_size
= GFC_DESCRIPTOR_SIZE (__values
);
196 len
= GFC_DESCRIPTOR_EXTENT(__values
,0);
197 delta
= GFC_DESCRIPTOR_STRIDE(__values
,0);
201 if (unlikely (len
< VALUES_SIZE
))
202 runtime_error ("Incorrect extent in VALUE argument to"
203 " DATE_AND_TIME intrinsic: is %ld, should"
204 " be >=%ld", (long int) len
, (long int) VALUES_SIZE
);
206 /* Cope with different type kinds. */
209 GFC_INTEGER_4
*vptr4
= __values
->base_addr
;
211 for (i
= 0; i
< VALUES_SIZE
; i
++, vptr4
+= delta
)
214 else if (elt_size
== 8)
216 GFC_INTEGER_8
*vptr8
= (GFC_INTEGER_8
*)__values
->base_addr
;
218 for (i
= 0; i
< VALUES_SIZE
; i
++, vptr8
+= delta
)
220 if (values
[i
] == - GFC_INTEGER_4_HUGE
)
221 *vptr8
= - GFC_INTEGER_8_HUGE
;
231 fstrcpy (__zone
, __zone_len
, zone
, ZONE_LEN
);
234 fstrcpy (__time
, __time_len
, timec
, TIME_LEN
);
237 fstrcpy (__date
, __date_len
, date
, DATE_LEN
);
241 /* SECNDS (X) - Non-standard
243 Description: Returns the system time of day, or elapsed time, as a GFC_REAL_4
246 Class: Non-elemental subroutine.
250 X must be REAL(4) and the result is of the same type. The accuracy is system
257 yields the time in elapsed seconds since X. If X is 0.0, T is the time in
258 seconds since midnight. Note that a time that spans midnight but is less than
259 24hours will be calculated correctly. */
261 extern GFC_REAL_4
secnds (GFC_REAL_4
*);
262 export_proto(secnds
);
265 secnds (GFC_REAL_4
*x
)
267 GFC_INTEGER_4 values
[VALUES_SIZE
];
268 GFC_REAL_4 temp1
, temp2
;
270 /* Make the INTEGER*4 array for passing to date_and_time. */
271 gfc_array_i4
*avalues
= xmalloc (sizeof (gfc_array_i4
));
272 avalues
->base_addr
= &values
[0];
273 GFC_DESCRIPTOR_DTYPE (avalues
) = ((BT_REAL
<< GFC_DTYPE_TYPE_SHIFT
)
274 & GFC_DTYPE_TYPE_MASK
) +
275 (4 << GFC_DTYPE_SIZE_SHIFT
);
277 GFC_DIMENSION_SET(avalues
->dim
[0], 0, 7, 1);
279 date_and_time (NULL
, NULL
, NULL
, avalues
, 0, 0, 0);
283 temp1
= 3600.0 * (GFC_REAL_4
)values
[4] +
284 60.0 * (GFC_REAL_4
)values
[5] +
285 (GFC_REAL_4
)values
[6] +
286 0.001 * (GFC_REAL_4
)values
[7];
287 temp2
= fmod (*x
, 86400.0);
288 temp2
= (temp1
- temp2
>= 0.0) ? temp2
: (temp2
- 86400.0);
289 return temp1
- temp2
;
294 /* ITIME(X) - Non-standard
296 Description: Returns the current local time hour, minutes, and seconds
297 in elements 1, 2, and 3 of X, respectively. */
303 struct tm local_time
;
307 if (lt
!= (time_t) -1)
309 localtime_r (<
, &local_time
);
311 x
[0] = local_time
.tm_hour
;
312 x
[1] = local_time
.tm_min
;
313 x
[2] = local_time
.tm_sec
;
317 extern void itime_i4 (gfc_array_i4
*);
318 export_proto(itime_i4
);
321 itime_i4 (gfc_array_i4
*__values
)
324 index_type len
, delta
;
327 /* Call helper function. */
330 /* Copy the value into the array. */
331 len
= GFC_DESCRIPTOR_EXTENT(__values
,0);
333 delta
= GFC_DESCRIPTOR_STRIDE(__values
,0);
337 vptr
= __values
->base_addr
;
338 for (i
= 0; i
< 3; i
++, vptr
+= delta
)
343 extern void itime_i8 (gfc_array_i8
*);
344 export_proto(itime_i8
);
347 itime_i8 (gfc_array_i8
*__values
)
350 index_type len
, delta
;
353 /* Call helper function. */
356 /* Copy the value into the array. */
357 len
= GFC_DESCRIPTOR_EXTENT(__values
,0);
359 delta
= GFC_DESCRIPTOR_STRIDE(__values
,0);
363 vptr
= __values
->base_addr
;
364 for (i
= 0; i
< 3; i
++, vptr
+= delta
)
370 /* IDATE(X) - Non-standard
372 Description: Fills TArray with the numerical values at the current
373 local time. The day (in the range 1-31), month (in the range 1-12),
374 and year appear in elements 1, 2, and 3 of X, respectively.
375 The year has four significant digits. */
381 struct tm local_time
;
385 if (lt
!= (time_t) -1)
387 localtime_r (<
, &local_time
);
389 x
[0] = local_time
.tm_mday
;
390 x
[1] = 1 + local_time
.tm_mon
;
391 x
[2] = 1900 + local_time
.tm_year
;
395 extern void idate_i4 (gfc_array_i4
*);
396 export_proto(idate_i4
);
399 idate_i4 (gfc_array_i4
*__values
)
402 index_type len
, delta
;
405 /* Call helper function. */
408 /* Copy the value into the array. */
409 len
= GFC_DESCRIPTOR_EXTENT(__values
,0);
411 delta
= GFC_DESCRIPTOR_STRIDE(__values
,0);
415 vptr
= __values
->base_addr
;
416 for (i
= 0; i
< 3; i
++, vptr
+= delta
)
421 extern void idate_i8 (gfc_array_i8
*);
422 export_proto(idate_i8
);
425 idate_i8 (gfc_array_i8
*__values
)
428 index_type len
, delta
;
431 /* Call helper function. */
434 /* Copy the value into the array. */
435 len
= GFC_DESCRIPTOR_EXTENT(__values
,0);
437 delta
= GFC_DESCRIPTOR_STRIDE(__values
,0);
441 vptr
= __values
->base_addr
;
442 for (i
= 0; i
< 3; i
++, vptr
+= delta
)
448 /* GMTIME(STIME, TARRAY) - Non-standard
450 Description: Given a system time value STime, fills TArray with values
451 extracted from it appropriate to the GMT time zone using gmtime_r(3).
453 The array elements are as follows:
455 1. Seconds after the minute, range 0-59 or 0-61 to allow for leap seconds
456 2. Minutes after the hour, range 0-59
457 3. Hours past midnight, range 0-23
458 4. Day of month, range 1-31
459 5. Number of months since January, range 0-11
461 7. Number of days since Sunday, range 0-6
462 8. Days since January 1, range 0-365
463 9. Daylight savings indicator: positive if daylight savings is in effect,
464 zero if not, and negative if the information isn't available. */
467 gmtime_0 (const time_t * t
, int x
[9])
483 extern void gmtime_i4 (GFC_INTEGER_4
*, gfc_array_i4
*);
484 export_proto(gmtime_i4
);
487 gmtime_i4 (GFC_INTEGER_4
* t
, gfc_array_i4
* tarray
)
490 index_type len
, delta
;
494 /* Call helper function. */
498 /* Copy the values into the array. */
499 len
= GFC_DESCRIPTOR_EXTENT(tarray
,0);
501 delta
= GFC_DESCRIPTOR_STRIDE(tarray
,0);
505 vptr
= tarray
->base_addr
;
506 for (i
= 0; i
< 9; i
++, vptr
+= delta
)
510 extern void gmtime_i8 (GFC_INTEGER_8
*, gfc_array_i8
*);
511 export_proto(gmtime_i8
);
514 gmtime_i8 (GFC_INTEGER_8
* t
, gfc_array_i8
* tarray
)
517 index_type len
, delta
;
521 /* Call helper function. */
525 /* Copy the values into the array. */
526 len
= GFC_DESCRIPTOR_EXTENT(tarray
,0);
528 delta
= GFC_DESCRIPTOR_STRIDE(tarray
,0);
532 vptr
= tarray
->base_addr
;
533 for (i
= 0; i
< 9; i
++, vptr
+= delta
)
540 /* LTIME(STIME, TARRAY) - Non-standard
542 Description: Given a system time value STime, fills TArray with values
543 extracted from it appropriate to the local time zone using localtime_r(3).
545 The array elements are as follows:
547 1. Seconds after the minute, range 0-59 or 0-61 to allow for leap seconds
548 2. Minutes after the hour, range 0-59
549 3. Hours past midnight, range 0-23
550 4. Day of month, range 1-31
551 5. Number of months since January, range 0-11
553 7. Number of days since Sunday, range 0-6
554 8. Days since January 1, range 0-365
555 9. Daylight savings indicator: positive if daylight savings is in effect,
556 zero if not, and negative if the information isn't available. */
559 ltime_0 (const time_t * t
, int x
[9])
563 localtime_r (t
, <
);
575 extern void ltime_i4 (GFC_INTEGER_4
*, gfc_array_i4
*);
576 export_proto(ltime_i4
);
579 ltime_i4 (GFC_INTEGER_4
* t
, gfc_array_i4
* tarray
)
582 index_type len
, delta
;
586 /* Call helper function. */
590 /* Copy the values into the array. */
591 len
= GFC_DESCRIPTOR_EXTENT(tarray
,0);
593 delta
= GFC_DESCRIPTOR_STRIDE(tarray
,0);
597 vptr
= tarray
->base_addr
;
598 for (i
= 0; i
< 9; i
++, vptr
+= delta
)
602 extern void ltime_i8 (GFC_INTEGER_8
*, gfc_array_i8
*);
603 export_proto(ltime_i8
);
606 ltime_i8 (GFC_INTEGER_8
* t
, gfc_array_i8
* tarray
)
609 index_type len
, delta
;
613 /* Call helper function. */
617 /* Copy the values into the array. */
618 len
= GFC_DESCRIPTOR_EXTENT(tarray
,0);
620 delta
= GFC_DESCRIPTOR_STRIDE(tarray
,0);
624 vptr
= tarray
->base_addr
;
625 for (i
= 0; i
< 9; i
++, vptr
+= delta
)