1 /* Implementation of the DATE_AND_TIME intrinsic.
2 Copyright (C) 2003, 2004, 2005, 2006 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 2 of the License, or (at your option) any later version.
12 In addition to the permissions in the GNU General Public License, the
13 Free Software Foundation gives you unlimited permission to link the
14 compiled version of this file into combinations with other programs,
15 and to distribute those combinations without any restriction coming
16 from the use of this file. (The General Public License restrictions
17 do apply in other respects; for example, they cover modification of
18 the file, and distribution when not linked into a combine
21 Libgfortran is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU General Public License for more details.
26 You should have received a copy of the GNU General Public
27 License along with libgfortran; see the file COPYING. If not,
28 write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
29 Boston, MA 02110-1301, USA. */
32 #include <sys/types.h>
37 #include "libgfortran.h"
39 #undef HAVE_NO_DATE_TIME
40 #if TIME_WITH_SYS_TIME
41 # include <sys/time.h>
45 # include <sys/time.h>
50 # define HAVE_NO_DATE_TIME
51 # endif /* HAVE_TIME_H */
52 # endif /* HAVE_SYS_TIME_H */
53 #endif /* TIME_WITH_SYS_TIME */
56 #define abs(x) ((x)>=0 ? (x) : -(x))
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, and
69 shall be of length at least 8 in order to contain the complete
70 value. It is an INTENT(OUT) argument. Its leftmost 8 characters
71 are assigned a value of the form CCYYMMDD, where CC is the century,
72 YY the year within the century, MM the month within the year, and
73 DD the day within the month. If there is no date available, they
76 TIME (optional) shall be scalar and of type default character, and
77 shall be of length at least 10 in order to contain the complete
78 value. It is an INTENT(OUT) argument. Its leftmost 10 characters
79 are assigned a value of the form hhmmss.sss, where hh is the hour
80 of the day, mm is the minutes of the hour, and ss.sss is the
81 seconds and milliseconds of the minute. If there is no clock
82 available, they are assigned blanks.
84 ZONE (optional) shall be scalar and of type default character, and
85 shall be of length at least 5 in order to contain the complete
86 value. It is an INTENT(OUT) argument. Its leftmost 5 characters
87 are assigned a value of the form [+-]hhmm, where hh and mm are the
88 time difference with respect to Coordinated Universal Time (UTC) in
89 hours and parts of an hour expressed in minutes, respectively. If
90 there is no clock available, they are assigned blanks.
92 VALUES (optional) shall be of type default integer and of rank
93 one. It is an INTENT(OUT) argument. Its size shall be at least
94 8. The values returned in VALUES are as follows:
96 VALUES(1) the year (for example, 2003), or -HUGE(0) if there is
99 VALUES(2) the month of the year, or -HUGE(0) if there
100 is no date available;
102 VALUES(3) the day of the month, or -HUGE(0) if there is no date
105 VALUES(4) the time difference with respect to Coordinated
106 Universal Time (UTC) in minutes, or -HUGE(0) if this information
109 VALUES(5) the hour of the day, in the range of 0 to 23, or
110 -HUGE(0) if there is no clock;
112 VALUES(6) the minutes of the hour, in the range 0 to 59, or
113 -HUGE(0) if there is no clock;
115 VALUES(7) the seconds of the minute, in the range 0 to 60, or
116 -HUGE(0) if there is no clock;
118 VALUES(8) the milliseconds of the second, in the range 0 to
119 999, or -HUGE(0) if there is no clock.
121 NULL pointer represent missing OPTIONAL arguments. All arguments
122 have INTENT(OUT). Because of the -i8 option, we must implement
123 VALUES for INTEGER(kind=4) and INTEGER(kind=8).
125 Based on libU77's date_time_.c.
128 - Check year boundaries.
129 - There is no STDC/POSIX way to get VALUES(8). A GNUish way may
135 #define VALUES_SIZE 8
137 extern void date_and_time (char *, char *, char *, gfc_array_i4 *,
138 GFC_INTEGER_4, GFC_INTEGER_4, GFC_INTEGER_4);
139 export_proto(date_and_time);
142 date_and_time (char *__date, char *__time, char *__zone,
143 gfc_array_i4 *__values, GFC_INTEGER_4 __date_len,
144 GFC_INTEGER_4 __time_len, GFC_INTEGER_4 __zone_len)
147 char date[DATE_LEN + 1];
148 char timec[TIME_LEN + 1];
149 char zone[ZONE_LEN + 1];
150 GFC_INTEGER_4 values[VALUES_SIZE];
152 #ifndef HAVE_NO_DATE_TIME
154 struct tm local_time;
159 if (lt != (time_t) -1)
161 local_time = *localtime (<);
162 UTC_time = *gmtime (<);
164 /* All arguments can be derived from VALUES. */
165 values[0] = 1900 + local_time.tm_year;
166 values[1] = 1 + local_time.tm_mon;
167 values[2] = local_time.tm_mday;
168 values[3] = (local_time.tm_min - UTC_time.tm_min +
169 60 * (local_time.tm_hour - UTC_time.tm_hour +
170 24 * (local_time.tm_yday - UTC_time.tm_yday)));
171 values[4] = local_time.tm_hour;
172 values[5] = local_time.tm_min;
173 values[6] = local_time.tm_sec;
176 #if HAVE_GETTIMEOFDAY
179 # if GETTIMEOFDAY_ONE_ARGUMENT
180 if (!gettimeofday (&tp))
182 # if HAVE_STRUCT_TIMEZONE
185 /* Some systems such as HP-UX, do have struct timezone, but
186 gettimeofday takes void* as the 2nd arg. However, the
187 effect of passing anything other than a null pointer is
188 unspecified on HP-UX. Configure checks if gettimeofday
189 actually fails with a non-NULL arg and pretends that
190 struct timezone is missing if it does fail. */
191 if (!gettimeofday (&tp, &tzp))
193 if (!gettimeofday (&tp, (void *) 0))
194 # endif /* HAVE_STRUCT_TIMEZONE */
195 # endif /* GETTIMEOFDAY_ONE_ARGUMENT */
196 values[7] = tp.tv_usec / 1000;
198 #endif /* HAVE_GETTIMEOFDAY */
202 snprintf (date, DATE_LEN + 1, "%04d%02d%02d",
203 values[0], values[1], values[2]);
205 snprintf (timec, TIME_LEN + 1, "%02d%02d%02d.%03d",
206 values[4], values[5], values[6], values[7]);
209 snprintf (zone, ZONE_LEN + 1, "%+03d%02d",
210 values[3] / 60, abs (values[3] % 60));
213 sprintf (date, "%04d%02d%02d", values[0], values[1], values[2]);
216 sprintf (timec, "%02d%02d%02d.%03d",
217 values[4], values[5], values[6], values[7]);
220 sprintf (zone, "%+03d%02d",
221 values[3] / 60, abs (values[3] % 60));
226 memset (date, ' ', DATE_LEN);
227 date[DATE_LEN] = '\0';
229 memset (timec, ' ', TIME_LEN);
230 timec[TIME_LEN] = '\0';
232 memset (zone, ' ', ZONE_LEN);
233 zone[ZONE_LEN] = '\0';
235 for (i = 0; i < VALUES_SIZE; i++)
236 values[i] = - GFC_INTEGER_4_HUGE;
238 #else /* if defined HAVE_NO_DATE_TIME */
239 /* We really have *nothing* to return, so return blanks and HUGE(0). */
241 memset (date, ' ', DATE_LEN);
242 date[DATE_LEN] = '\0';
244 memset (timec, ' ', TIME_LEN);
245 timec[TIME_LEN] = '\0';
247 memset (zone, ' ', ZONE_LEN);
248 zone[ZONE_LEN] = '\0';
250 for (i = 0; i < VALUES_SIZE; i++)
251 values[i] = - GFC_INTEGER_4_HUGE;
252 #endif /* HAVE_NO_DATE_TIME */
254 /* Copy the values into the arguments. */
257 size_t len, delta, elt_size;
259 elt_size = GFC_DESCRIPTOR_SIZE (__values);
260 len = __values->dim[0].ubound + 1 - __values->dim[0].lbound;
261 delta = __values->dim[0].stride;
265 assert (len >= VALUES_SIZE);
266 /* Cope with different type kinds. */
269 GFC_INTEGER_4 *vptr4 = __values->data;
271 for (i = 0; i < VALUES_SIZE; i++, vptr4 += delta)
274 else if (elt_size == 8)
276 GFC_INTEGER_8 *vptr8 = (GFC_INTEGER_8 *)__values->data;
278 for (i = 0; i < VALUES_SIZE; i++, vptr8 += delta)
280 if (values[i] == - GFC_INTEGER_4_HUGE)
281 *vptr8 = - GFC_INTEGER_8_HUGE;
292 assert (__zone_len >= ZONE_LEN);
293 fstrcpy (__zone, ZONE_LEN, zone, ZONE_LEN);
298 assert (__time_len >= TIME_LEN);
299 fstrcpy (__time, TIME_LEN, timec, TIME_LEN);
304 assert (__date_len >= DATE_LEN);
305 fstrcpy (__date, DATE_LEN, date, DATE_LEN);
310 /* SECNDS (X) - Non-standard
312 Description: Returns the system time of day, or elapsed time, as a GFC_REAL_4
315 Class: Non-elemental subroutine.
319 X must be REAL(4) and the result is of the same type. The accuracy is system
326 yields the time in elapsed seconds since X. If X is 0.0, T is the time in
327 seconds since midnight. Note that a time that spans midnight but is less than
328 24hours will be calculated correctly. */
330 extern GFC_REAL_4 secnds (GFC_REAL_4 *);
331 export_proto(secnds);
334 secnds (GFC_REAL_4 *x)
336 GFC_INTEGER_4 values[VALUES_SIZE];
337 GFC_REAL_4 temp1, temp2;
339 /* Make the INTEGER*4 array for passing to date_and_time. */
340 gfc_array_i4 *avalues = internal_malloc_size (sizeof (gfc_array_i4));
341 avalues->data = &values[0];
342 GFC_DESCRIPTOR_DTYPE (avalues) = ((GFC_DTYPE_REAL << GFC_DTYPE_TYPE_SHIFT)
343 & GFC_DTYPE_TYPE_MASK) +
344 (4 << GFC_DTYPE_SIZE_SHIFT);
346 avalues->dim[0].ubound = 7;
347 avalues->dim[0].lbound = 0;
348 avalues->dim[0].stride = 1;
350 date_and_time (NULL, NULL, NULL, avalues, 0, 0, 0);
354 temp1 = 3600.0 * (GFC_REAL_4)values[4] +
355 60.0 * (GFC_REAL_4)values[5] +
356 (GFC_REAL_4)values[6] +
357 0.001 * (GFC_REAL_4)values[7];
358 temp2 = fmod (*x, 86400.0);
359 temp2 = (temp1 - temp2 > 0.0) ? temp2 : (temp2 - 86400.0);
360 return temp1 - temp2;
365 /* ITIME(X) - Non-standard
367 Description: Returns the current local time hour, minutes, and seconds
368 in elements 1, 2, and 3 of X, respectively. */
373 #ifndef HAVE_NO_DATE_TIME
375 struct tm local_time;
379 if (lt != (time_t) -1)
381 local_time = *localtime (<);
383 x[0] = local_time.tm_hour;
384 x[1] = local_time.tm_min;
385 x[2] = local_time.tm_sec;
388 x[0] = x[1] = x[2] = -1;
392 extern void itime_i4 (gfc_array_i4 *);
393 export_proto(itime_i4);
396 itime_i4 (gfc_array_i4 *__values)
402 /* Call helper function. */
405 /* Copy the value into the array. */
406 len = __values->dim[0].ubound + 1 - __values->dim[0].lbound;
408 delta = __values->dim[0].stride;
412 vptr = __values->data;
413 for (i = 0; i < 3; i++, vptr += delta)
418 extern void itime_i8 (gfc_array_i8 *);
419 export_proto(itime_i8);
422 itime_i8 (gfc_array_i8 *__values)
428 /* Call helper function. */
431 /* Copy the value into the array. */
432 len = __values->dim[0].ubound + 1 - __values->dim[0].lbound;
434 delta = __values->dim[0].stride;
438 vptr = __values->data;
439 for (i = 0; i < 3; i++, vptr += delta)
445 /* IDATE(X) - Non-standard
447 Description: Fills TArray with the numerical values at the current
448 local time. The day (in the range 1-31), month (in the range 1-12),
449 and year appear in elements 1, 2, and 3 of X, respectively.
450 The year has four significant digits. */
455 #ifndef HAVE_NO_DATE_TIME
457 struct tm local_time;
461 if (lt != (time_t) -1)
463 local_time = *localtime (<);
465 x[0] = local_time.tm_mday;
466 x[1] = 1 + local_time.tm_mon;
467 x[2] = 1900 + local_time.tm_year;
470 x[0] = x[1] = x[2] = -1;
474 extern void idate_i4 (gfc_array_i4 *);
475 export_proto(idate_i4);
478 idate_i4 (gfc_array_i4 *__values)
484 /* Call helper function. */
487 /* Copy the value into the array. */
488 len = __values->dim[0].ubound + 1 - __values->dim[0].lbound;
490 delta = __values->dim[0].stride;
494 vptr = __values->data;
495 for (i = 0; i < 3; i++, vptr += delta)
500 extern void idate_i8 (gfc_array_i8 *);
501 export_proto(idate_i8);
504 idate_i8 (gfc_array_i8 *__values)
510 /* Call helper function. */
513 /* Copy the value into the array. */
514 len = __values->dim[0].ubound + 1 - __values->dim[0].lbound;
516 delta = __values->dim[0].stride;
520 vptr = __values->data;
521 for (i = 0; i < 3; i++, vptr += delta)
527 /* GMTIME(STIME, TARRAY) - Non-standard
529 Description: Given a system time value STime, fills TArray with values
530 extracted from it appropriate to the GMT time zone using gmtime(3).
532 The array elements are as follows:
534 1. Seconds after the minute, range 0-59 or 0-61 to allow for leap seconds
535 2. Minutes after the hour, range 0-59
536 3. Hours past midnight, range 0-23
537 4. Day of month, range 0-31
538 5. Number of months since January, range 0-11
540 7. Number of days since Sunday, range 0-6
541 8. Days since January 1
542 9. Daylight savings indicator: positive if daylight savings is in effect,
543 zero if not, and negative if the information isn't available. */
546 gmtime_0 (const time_t * t, int x[9])
562 extern void gmtime_i4 (GFC_INTEGER_4 *, gfc_array_i4 *);
563 export_proto(gmtime_i4);
566 gmtime_i4 (GFC_INTEGER_4 * t, gfc_array_i4 * tarray)
573 /* Call helper function. */
577 /* Copy the values into the array. */
578 len = tarray->dim[0].ubound + 1 - tarray->dim[0].lbound;
580 delta = tarray->dim[0].stride;
585 for (i = 0; i < 9; i++, vptr += delta)
589 extern void gmtime_i8 (GFC_INTEGER_8 *, gfc_array_i8 *);
590 export_proto(gmtime_i8);
593 gmtime_i8 (GFC_INTEGER_8 * t, gfc_array_i8 * tarray)
600 /* Call helper function. */
604 /* Copy the values into the array. */
605 len = tarray->dim[0].ubound + 1 - tarray->dim[0].lbound;
607 delta = tarray->dim[0].stride;
612 for (i = 0; i < 9; i++, vptr += delta)
619 /* LTIME(STIME, TARRAY) - Non-standard
621 Description: Given a system time value STime, fills TArray with values
622 extracted from it appropriate to the local time zone using localtime(3).
624 The array elements are as follows:
626 1. Seconds after the minute, range 0-59 or 0-61 to allow for leap seconds
627 2. Minutes after the hour, range 0-59
628 3. Hours past midnight, range 0-23
629 4. Day of month, range 0-31
630 5. Number of months since January, range 0-11
632 7. Number of days since Sunday, range 0-6
633 8. Days since January 1
634 9. Daylight savings indicator: positive if daylight savings is in effect,
635 zero if not, and negative if the information isn't available. */
638 ltime_0 (const time_t * t, int x[9])
654 extern void ltime_i4 (GFC_INTEGER_4 *, gfc_array_i4 *);
655 export_proto(ltime_i4);
658 ltime_i4 (GFC_INTEGER_4 * t, gfc_array_i4 * tarray)
665 /* Call helper function. */
669 /* Copy the values into the array. */
670 len = tarray->dim[0].ubound + 1 - tarray->dim[0].lbound;
672 delta = tarray->dim[0].stride;
677 for (i = 0; i < 9; i++, vptr += delta)
681 extern void ltime_i8 (GFC_INTEGER_8 *, gfc_array_i8 *);
682 export_proto(ltime_i8);
685 ltime_i8 (GFC_INTEGER_8 * t, gfc_array_i8 * tarray)
692 /* Call helper function. */
696 /* Copy the values into the array. */
697 len = tarray->dim[0].ubound + 1 - tarray->dim[0].lbound;
699 delta = tarray->dim[0].stride;
704 for (i = 0; i < 9; i++, vptr += delta)