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"
31 #undef HAVE_NO_DATE_TIME
32 #if TIME_WITH_SYS_TIME
33 # include <sys/time.h>
37 # include <sys/time.h>
42 # define HAVE_NO_DATE_TIME
43 # endif /* HAVE_TIME_H */
44 # endif /* HAVE_SYS_TIME_H */
45 #endif /* TIME_WITH_SYS_TIME */
48 #define abs(x) ((x)>=0 ? (x) : -(x))
51 /* DATE_AND_TIME ([DATE, TIME, ZONE, VALUES])
53 Description: Returns data on the real-time clock and date in a form
54 compatible with the representations defined in ISO 8601:1988.
56 Class: Non-elemental subroutine.
60 DATE (optional) shall be scalar and of type default character, and
61 shall be of length at least 8 in order to contain the complete
62 value. It is an INTENT(OUT) argument. Its leftmost 8 characters
63 are assigned a value of the form CCYYMMDD, where CC is the century,
64 YY the year within the century, MM the month within the year, and
65 DD the day within the month. If there is no date available, they
68 TIME (optional) shall be scalar and of type default character, and
69 shall be of length at least 10 in order to contain the complete
70 value. It is an INTENT(OUT) argument. Its leftmost 10 characters
71 are assigned a value of the form hhmmss.sss, where hh is the hour
72 of the day, mm is the minutes of the hour, and ss.sss is the
73 seconds and milliseconds of the minute. If there is no clock
74 available, they are assigned blanks.
76 ZONE (optional) shall be scalar and of type default character, and
77 shall be of length at least 5 in order to contain the complete
78 value. It is an INTENT(OUT) argument. Its leftmost 5 characters
79 are assigned a value of the form [+-]hhmm, where hh and mm are the
80 time difference with respect to Coordinated Universal Time (UTC) in
81 hours and parts of an hour expressed in minutes, respectively. If
82 there is no clock available, they are assigned blanks.
84 VALUES (optional) shall be of type default integer and of rank
85 one. It is an INTENT(OUT) argument. Its size shall be at least
86 8. The values returned in VALUES are as follows:
88 VALUES(1) the year (for example, 2003), or -HUGE(0) if there is
91 VALUES(2) the month of the year, or -HUGE(0) if there
94 VALUES(3) the day of the month, or -HUGE(0) if there is no date
97 VALUES(4) the time difference with respect to Coordinated
98 Universal Time (UTC) in minutes, or -HUGE(0) if this information
101 VALUES(5) the hour of the day, in the range of 0 to 23, or
102 -HUGE(0) if there is no clock;
104 VALUES(6) the minutes of the hour, in the range 0 to 59, or
105 -HUGE(0) if there is no clock;
107 VALUES(7) the seconds of the minute, in the range 0 to 60, or
108 -HUGE(0) if there is no clock;
110 VALUES(8) the milliseconds of the second, in the range 0 to
111 999, or -HUGE(0) if there is no clock.
113 NULL pointer represent missing OPTIONAL arguments. All arguments
114 have INTENT(OUT). Because of the -i8 option, we must implement
115 VALUES for INTEGER(kind=4) and INTEGER(kind=8).
117 Based on libU77's date_time_.c.
120 - Check year boundaries.
125 #define VALUES_SIZE 8
127 extern void date_and_time (char *, char *, char *, gfc_array_i4 *,
128 GFC_INTEGER_4, GFC_INTEGER_4, GFC_INTEGER_4);
129 export_proto(date_and_time);
132 date_and_time (char *__date, char *__time, char *__zone,
133 gfc_array_i4 *__values, GFC_INTEGER_4 __date_len,
134 GFC_INTEGER_4 __time_len, GFC_INTEGER_4 __zone_len)
137 char date[DATE_LEN + 1];
138 char timec[TIME_LEN + 1];
139 char zone[ZONE_LEN + 1];
140 GFC_INTEGER_4 values[VALUES_SIZE];
142 #ifndef HAVE_NO_DATE_TIME
144 struct tm local_time;
147 #if HAVE_GETTIMEOFDAY
151 if (!gettimeofday (&tp, NULL))
154 values[7] = tp.tv_usec / 1000;
165 #endif /* HAVE_GETTIMEOFDAY */
167 if (lt != (time_t) -1)
169 local_time = *localtime (<);
170 UTC_time = *gmtime (<);
172 /* All arguments can be derived from VALUES. */
173 values[0] = 1900 + local_time.tm_year;
174 values[1] = 1 + local_time.tm_mon;
175 values[2] = local_time.tm_mday;
176 values[3] = (local_time.tm_min - UTC_time.tm_min +
177 60 * (local_time.tm_hour - UTC_time.tm_hour +
178 24 * (local_time.tm_yday - UTC_time.tm_yday)));
179 values[4] = local_time.tm_hour;
180 values[5] = local_time.tm_min;
181 values[6] = local_time.tm_sec;
185 snprintf (date, DATE_LEN + 1, "%04d%02d%02d",
186 values[0], values[1], values[2]);
188 snprintf (timec, TIME_LEN + 1, "%02d%02d%02d.%03d",
189 values[4], values[5], values[6], values[7]);
192 snprintf (zone, ZONE_LEN + 1, "%+03d%02d",
193 values[3] / 60, abs (values[3] % 60));
196 sprintf (date, "%04d%02d%02d", values[0], values[1], values[2]);
199 sprintf (timec, "%02d%02d%02d.%03d",
200 values[4], values[5], values[6], values[7]);
203 sprintf (zone, "%+03d%02d",
204 values[3] / 60, abs (values[3] % 60));
209 memset (date, ' ', DATE_LEN);
210 date[DATE_LEN] = '\0';
212 memset (timec, ' ', TIME_LEN);
213 timec[TIME_LEN] = '\0';
215 memset (zone, ' ', ZONE_LEN);
216 zone[ZONE_LEN] = '\0';
218 for (i = 0; i < VALUES_SIZE; i++)
219 values[i] = - GFC_INTEGER_4_HUGE;
221 #else /* if defined HAVE_NO_DATE_TIME */
222 /* We really have *nothing* to return, so return blanks and HUGE(0). */
224 memset (date, ' ', DATE_LEN);
225 date[DATE_LEN] = '\0';
227 memset (timec, ' ', TIME_LEN);
228 timec[TIME_LEN] = '\0';
230 memset (zone, ' ', ZONE_LEN);
231 zone[ZONE_LEN] = '\0';
233 for (i = 0; i < VALUES_SIZE; i++)
234 values[i] = - GFC_INTEGER_4_HUGE;
235 #endif /* HAVE_NO_DATE_TIME */
237 /* Copy the values into the arguments. */
240 index_type len, delta, elt_size;
242 elt_size = GFC_DESCRIPTOR_SIZE (__values);
243 len = __values->dim[0].ubound + 1 - __values->dim[0].lbound;
244 delta = __values->dim[0].stride;
248 assert (len >= VALUES_SIZE);
249 /* Cope with different type kinds. */
252 GFC_INTEGER_4 *vptr4 = __values->data;
254 for (i = 0; i < VALUES_SIZE; i++, vptr4 += delta)
257 else if (elt_size == 8)
259 GFC_INTEGER_8 *vptr8 = (GFC_INTEGER_8 *)__values->data;
261 for (i = 0; i < VALUES_SIZE; i++, vptr8 += delta)
263 if (values[i] == - GFC_INTEGER_4_HUGE)
264 *vptr8 = - GFC_INTEGER_8_HUGE;
275 assert (__zone_len >= ZONE_LEN);
276 fstrcpy (__zone, ZONE_LEN, zone, ZONE_LEN);
281 assert (__time_len >= TIME_LEN);
282 fstrcpy (__time, TIME_LEN, timec, TIME_LEN);
287 assert (__date_len >= DATE_LEN);
288 fstrcpy (__date, DATE_LEN, date, DATE_LEN);
293 /* SECNDS (X) - Non-standard
295 Description: Returns the system time of day, or elapsed time, as a GFC_REAL_4
298 Class: Non-elemental subroutine.
302 X must be REAL(4) and the result is of the same type. The accuracy is system
309 yields the time in elapsed seconds since X. If X is 0.0, T is the time in
310 seconds since midnight. Note that a time that spans midnight but is less than
311 24hours will be calculated correctly. */
313 extern GFC_REAL_4 secnds (GFC_REAL_4 *);
314 export_proto(secnds);
317 secnds (GFC_REAL_4 *x)
319 GFC_INTEGER_4 values[VALUES_SIZE];
320 GFC_REAL_4 temp1, temp2;
322 /* Make the INTEGER*4 array for passing to date_and_time. */
323 gfc_array_i4 *avalues = internal_malloc_size (sizeof (gfc_array_i4));
324 avalues->data = &values[0];
325 GFC_DESCRIPTOR_DTYPE (avalues) = ((GFC_DTYPE_REAL << GFC_DTYPE_TYPE_SHIFT)
326 & GFC_DTYPE_TYPE_MASK) +
327 (4 << GFC_DTYPE_SIZE_SHIFT);
329 avalues->dim[0].ubound = 7;
330 avalues->dim[0].lbound = 0;
331 avalues->dim[0].stride = 1;
333 date_and_time (NULL, NULL, NULL, avalues, 0, 0, 0);
337 temp1 = 3600.0 * (GFC_REAL_4)values[4] +
338 60.0 * (GFC_REAL_4)values[5] +
339 (GFC_REAL_4)values[6] +
340 0.001 * (GFC_REAL_4)values[7];
341 temp2 = fmod (*x, 86400.0);
342 temp2 = (temp1 - temp2 >= 0.0) ? temp2 : (temp2 - 86400.0);
343 return temp1 - temp2;
348 /* ITIME(X) - Non-standard
350 Description: Returns the current local time hour, minutes, and seconds
351 in elements 1, 2, and 3 of X, respectively. */
356 #ifndef HAVE_NO_DATE_TIME
358 struct tm local_time;
362 if (lt != (time_t) -1)
364 local_time = *localtime (<);
366 x[0] = local_time.tm_hour;
367 x[1] = local_time.tm_min;
368 x[2] = local_time.tm_sec;
371 x[0] = x[1] = x[2] = -1;
375 extern void itime_i4 (gfc_array_i4 *);
376 export_proto(itime_i4);
379 itime_i4 (gfc_array_i4 *__values)
382 index_type len, delta;
385 /* Call helper function. */
388 /* Copy the value into the array. */
389 len = __values->dim[0].ubound + 1 - __values->dim[0].lbound;
391 delta = __values->dim[0].stride;
395 vptr = __values->data;
396 for (i = 0; i < 3; i++, vptr += delta)
401 extern void itime_i8 (gfc_array_i8 *);
402 export_proto(itime_i8);
405 itime_i8 (gfc_array_i8 *__values)
408 index_type len, delta;
411 /* Call helper function. */
414 /* Copy the value into the array. */
415 len = __values->dim[0].ubound + 1 - __values->dim[0].lbound;
417 delta = __values->dim[0].stride;
421 vptr = __values->data;
422 for (i = 0; i < 3; i++, vptr += delta)
428 /* IDATE(X) - Non-standard
430 Description: Fills TArray with the numerical values at the current
431 local time. The day (in the range 1-31), month (in the range 1-12),
432 and year appear in elements 1, 2, and 3 of X, respectively.
433 The year has four significant digits. */
438 #ifndef HAVE_NO_DATE_TIME
440 struct tm local_time;
444 if (lt != (time_t) -1)
446 local_time = *localtime (<);
448 x[0] = local_time.tm_mday;
449 x[1] = 1 + local_time.tm_mon;
450 x[2] = 1900 + local_time.tm_year;
453 x[0] = x[1] = x[2] = -1;
457 extern void idate_i4 (gfc_array_i4 *);
458 export_proto(idate_i4);
461 idate_i4 (gfc_array_i4 *__values)
464 index_type len, delta;
467 /* Call helper function. */
470 /* Copy the value into the array. */
471 len = __values->dim[0].ubound + 1 - __values->dim[0].lbound;
473 delta = __values->dim[0].stride;
477 vptr = __values->data;
478 for (i = 0; i < 3; i++, vptr += delta)
483 extern void idate_i8 (gfc_array_i8 *);
484 export_proto(idate_i8);
487 idate_i8 (gfc_array_i8 *__values)
490 index_type len, delta;
493 /* Call helper function. */
496 /* Copy the value into the array. */
497 len = __values->dim[0].ubound + 1 - __values->dim[0].lbound;
499 delta = __values->dim[0].stride;
503 vptr = __values->data;
504 for (i = 0; i < 3; i++, vptr += delta)
510 /* GMTIME(STIME, TARRAY) - Non-standard
512 Description: Given a system time value STime, fills TArray with values
513 extracted from it appropriate to the GMT time zone using gmtime(3).
515 The array elements are as follows:
517 1. Seconds after the minute, range 0-59 or 0-61 to allow for leap seconds
518 2. Minutes after the hour, range 0-59
519 3. Hours past midnight, range 0-23
520 4. Day of month, range 0-31
521 5. Number of months since January, range 0-11
523 7. Number of days since Sunday, range 0-6
524 8. Days since January 1
525 9. Daylight savings indicator: positive if daylight savings is in effect,
526 zero if not, and negative if the information isn't available. */
529 gmtime_0 (const time_t * t, int x[9])
545 extern void gmtime_i4 (GFC_INTEGER_4 *, gfc_array_i4 *);
546 export_proto(gmtime_i4);
549 gmtime_i4 (GFC_INTEGER_4 * t, gfc_array_i4 * tarray)
552 index_type len, delta;
556 /* Call helper function. */
560 /* Copy the values into the array. */
561 len = tarray->dim[0].ubound + 1 - tarray->dim[0].lbound;
563 delta = tarray->dim[0].stride;
568 for (i = 0; i < 9; i++, vptr += delta)
572 extern void gmtime_i8 (GFC_INTEGER_8 *, gfc_array_i8 *);
573 export_proto(gmtime_i8);
576 gmtime_i8 (GFC_INTEGER_8 * t, gfc_array_i8 * tarray)
579 index_type len, delta;
583 /* Call helper function. */
587 /* Copy the values into the array. */
588 len = tarray->dim[0].ubound + 1 - tarray->dim[0].lbound;
590 delta = tarray->dim[0].stride;
595 for (i = 0; i < 9; i++, vptr += delta)
602 /* LTIME(STIME, TARRAY) - Non-standard
604 Description: Given a system time value STime, fills TArray with values
605 extracted from it appropriate to the local time zone using localtime(3).
607 The array elements are as follows:
609 1. Seconds after the minute, range 0-59 or 0-61 to allow for leap seconds
610 2. Minutes after the hour, range 0-59
611 3. Hours past midnight, range 0-23
612 4. Day of month, range 0-31
613 5. Number of months since January, range 0-11
615 7. Number of days since Sunday, range 0-6
616 8. Days since January 1
617 9. Daylight savings indicator: positive if daylight savings is in effect,
618 zero if not, and negative if the information isn't available. */
621 ltime_0 (const time_t * t, int x[9])
637 extern void ltime_i4 (GFC_INTEGER_4 *, gfc_array_i4 *);
638 export_proto(ltime_i4);
641 ltime_i4 (GFC_INTEGER_4 * t, gfc_array_i4 * tarray)
644 index_type len, delta;
648 /* Call helper function. */
652 /* Copy the values into the array. */
653 len = tarray->dim[0].ubound + 1 - tarray->dim[0].lbound;
655 delta = tarray->dim[0].stride;
660 for (i = 0; i < 9; i++, vptr += delta)
664 extern void ltime_i8 (GFC_INTEGER_8 *, gfc_array_i8 *);
665 export_proto(ltime_i8);
668 ltime_i8 (GFC_INTEGER_8 * t, gfc_array_i8 * tarray)
671 index_type len, delta;
675 /* Call helper function. */
679 /* Copy the values into the array. */
680 len = tarray->dim[0].ubound + 1 - tarray->dim[0].lbound;
682 delta = tarray->dim[0].stride;
687 for (i = 0; i < 9; i++, vptr += delta)