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.
133 #define VALUES_SIZE 8
135 extern void date_and_time (char *, char *, char *, gfc_array_i4 *,
136 GFC_INTEGER_4, GFC_INTEGER_4, GFC_INTEGER_4);
137 export_proto(date_and_time);
140 date_and_time (char *__date, char *__time, char *__zone,
141 gfc_array_i4 *__values, GFC_INTEGER_4 __date_len,
142 GFC_INTEGER_4 __time_len, GFC_INTEGER_4 __zone_len)
145 char date[DATE_LEN + 1];
146 char timec[TIME_LEN + 1];
147 char zone[ZONE_LEN + 1];
148 GFC_INTEGER_4 values[VALUES_SIZE];
150 #ifndef HAVE_NO_DATE_TIME
152 struct tm local_time;
155 #if HAVE_GETTIMEOFDAY
159 if (!gettimeofday (&tp, NULL))
162 values[7] = tp.tv_usec / 1000;
173 #endif /* HAVE_GETTIMEOFDAY */
175 if (lt != (time_t) -1)
177 local_time = *localtime (<);
178 UTC_time = *gmtime (<);
180 /* All arguments can be derived from VALUES. */
181 values[0] = 1900 + local_time.tm_year;
182 values[1] = 1 + local_time.tm_mon;
183 values[2] = local_time.tm_mday;
184 values[3] = (local_time.tm_min - UTC_time.tm_min +
185 60 * (local_time.tm_hour - UTC_time.tm_hour +
186 24 * (local_time.tm_yday - UTC_time.tm_yday)));
187 values[4] = local_time.tm_hour;
188 values[5] = local_time.tm_min;
189 values[6] = local_time.tm_sec;
193 snprintf (date, DATE_LEN + 1, "%04d%02d%02d",
194 values[0], values[1], values[2]);
196 snprintf (timec, TIME_LEN + 1, "%02d%02d%02d.%03d",
197 values[4], values[5], values[6], values[7]);
200 snprintf (zone, ZONE_LEN + 1, "%+03d%02d",
201 values[3] / 60, abs (values[3] % 60));
204 sprintf (date, "%04d%02d%02d", values[0], values[1], values[2]);
207 sprintf (timec, "%02d%02d%02d.%03d",
208 values[4], values[5], values[6], values[7]);
211 sprintf (zone, "%+03d%02d",
212 values[3] / 60, abs (values[3] % 60));
217 memset (date, ' ', DATE_LEN);
218 date[DATE_LEN] = '\0';
220 memset (timec, ' ', TIME_LEN);
221 timec[TIME_LEN] = '\0';
223 memset (zone, ' ', ZONE_LEN);
224 zone[ZONE_LEN] = '\0';
226 for (i = 0; i < VALUES_SIZE; i++)
227 values[i] = - GFC_INTEGER_4_HUGE;
229 #else /* if defined HAVE_NO_DATE_TIME */
230 /* We really have *nothing* to return, so return blanks and HUGE(0). */
232 memset (date, ' ', DATE_LEN);
233 date[DATE_LEN] = '\0';
235 memset (timec, ' ', TIME_LEN);
236 timec[TIME_LEN] = '\0';
238 memset (zone, ' ', ZONE_LEN);
239 zone[ZONE_LEN] = '\0';
241 for (i = 0; i < VALUES_SIZE; i++)
242 values[i] = - GFC_INTEGER_4_HUGE;
243 #endif /* HAVE_NO_DATE_TIME */
245 /* Copy the values into the arguments. */
248 size_t len, delta, elt_size;
250 elt_size = GFC_DESCRIPTOR_SIZE (__values);
251 len = __values->dim[0].ubound + 1 - __values->dim[0].lbound;
252 delta = __values->dim[0].stride;
256 assert (len >= VALUES_SIZE);
257 /* Cope with different type kinds. */
260 GFC_INTEGER_4 *vptr4 = __values->data;
262 for (i = 0; i < VALUES_SIZE; i++, vptr4 += delta)
265 else if (elt_size == 8)
267 GFC_INTEGER_8 *vptr8 = (GFC_INTEGER_8 *)__values->data;
269 for (i = 0; i < VALUES_SIZE; i++, vptr8 += delta)
271 if (values[i] == - GFC_INTEGER_4_HUGE)
272 *vptr8 = - GFC_INTEGER_8_HUGE;
283 assert (__zone_len >= ZONE_LEN);
284 fstrcpy (__zone, ZONE_LEN, zone, ZONE_LEN);
289 assert (__time_len >= TIME_LEN);
290 fstrcpy (__time, TIME_LEN, timec, TIME_LEN);
295 assert (__date_len >= DATE_LEN);
296 fstrcpy (__date, DATE_LEN, date, DATE_LEN);
301 /* SECNDS (X) - Non-standard
303 Description: Returns the system time of day, or elapsed time, as a GFC_REAL_4
306 Class: Non-elemental subroutine.
310 X must be REAL(4) and the result is of the same type. The accuracy is system
317 yields the time in elapsed seconds since X. If X is 0.0, T is the time in
318 seconds since midnight. Note that a time that spans midnight but is less than
319 24hours will be calculated correctly. */
321 extern GFC_REAL_4 secnds (GFC_REAL_4 *);
322 export_proto(secnds);
325 secnds (GFC_REAL_4 *x)
327 GFC_INTEGER_4 values[VALUES_SIZE];
328 GFC_REAL_4 temp1, temp2;
330 /* Make the INTEGER*4 array for passing to date_and_time. */
331 gfc_array_i4 *avalues = internal_malloc_size (sizeof (gfc_array_i4));
332 avalues->data = &values[0];
333 GFC_DESCRIPTOR_DTYPE (avalues) = ((GFC_DTYPE_REAL << GFC_DTYPE_TYPE_SHIFT)
334 & GFC_DTYPE_TYPE_MASK) +
335 (4 << GFC_DTYPE_SIZE_SHIFT);
337 avalues->dim[0].ubound = 7;
338 avalues->dim[0].lbound = 0;
339 avalues->dim[0].stride = 1;
341 date_and_time (NULL, NULL, NULL, avalues, 0, 0, 0);
345 temp1 = 3600.0 * (GFC_REAL_4)values[4] +
346 60.0 * (GFC_REAL_4)values[5] +
347 (GFC_REAL_4)values[6] +
348 0.001 * (GFC_REAL_4)values[7];
349 temp2 = fmod (*x, 86400.0);
350 temp2 = (temp1 - temp2 >= 0.0) ? temp2 : (temp2 - 86400.0);
351 return temp1 - temp2;
356 /* ITIME(X) - Non-standard
358 Description: Returns the current local time hour, minutes, and seconds
359 in elements 1, 2, and 3 of X, respectively. */
364 #ifndef HAVE_NO_DATE_TIME
366 struct tm local_time;
370 if (lt != (time_t) -1)
372 local_time = *localtime (<);
374 x[0] = local_time.tm_hour;
375 x[1] = local_time.tm_min;
376 x[2] = local_time.tm_sec;
379 x[0] = x[1] = x[2] = -1;
383 extern void itime_i4 (gfc_array_i4 *);
384 export_proto(itime_i4);
387 itime_i4 (gfc_array_i4 *__values)
393 /* Call helper function. */
396 /* Copy the value into the array. */
397 len = __values->dim[0].ubound + 1 - __values->dim[0].lbound;
399 delta = __values->dim[0].stride;
403 vptr = __values->data;
404 for (i = 0; i < 3; i++, vptr += delta)
409 extern void itime_i8 (gfc_array_i8 *);
410 export_proto(itime_i8);
413 itime_i8 (gfc_array_i8 *__values)
419 /* Call helper function. */
422 /* Copy the value into the array. */
423 len = __values->dim[0].ubound + 1 - __values->dim[0].lbound;
425 delta = __values->dim[0].stride;
429 vptr = __values->data;
430 for (i = 0; i < 3; i++, vptr += delta)
436 /* IDATE(X) - Non-standard
438 Description: Fills TArray with the numerical values at the current
439 local time. The day (in the range 1-31), month (in the range 1-12),
440 and year appear in elements 1, 2, and 3 of X, respectively.
441 The year has four significant digits. */
446 #ifndef HAVE_NO_DATE_TIME
448 struct tm local_time;
452 if (lt != (time_t) -1)
454 local_time = *localtime (<);
456 x[0] = local_time.tm_mday;
457 x[1] = 1 + local_time.tm_mon;
458 x[2] = 1900 + local_time.tm_year;
461 x[0] = x[1] = x[2] = -1;
465 extern void idate_i4 (gfc_array_i4 *);
466 export_proto(idate_i4);
469 idate_i4 (gfc_array_i4 *__values)
475 /* Call helper function. */
478 /* Copy the value into the array. */
479 len = __values->dim[0].ubound + 1 - __values->dim[0].lbound;
481 delta = __values->dim[0].stride;
485 vptr = __values->data;
486 for (i = 0; i < 3; i++, vptr += delta)
491 extern void idate_i8 (gfc_array_i8 *);
492 export_proto(idate_i8);
495 idate_i8 (gfc_array_i8 *__values)
501 /* Call helper function. */
504 /* Copy the value into the array. */
505 len = __values->dim[0].ubound + 1 - __values->dim[0].lbound;
507 delta = __values->dim[0].stride;
511 vptr = __values->data;
512 for (i = 0; i < 3; i++, vptr += delta)
518 /* GMTIME(STIME, TARRAY) - Non-standard
520 Description: Given a system time value STime, fills TArray with values
521 extracted from it appropriate to the GMT time zone using gmtime(3).
523 The array elements are as follows:
525 1. Seconds after the minute, range 0-59 or 0-61 to allow for leap seconds
526 2. Minutes after the hour, range 0-59
527 3. Hours past midnight, range 0-23
528 4. Day of month, range 0-31
529 5. Number of months since January, range 0-11
531 7. Number of days since Sunday, range 0-6
532 8. Days since January 1
533 9. Daylight savings indicator: positive if daylight savings is in effect,
534 zero if not, and negative if the information isn't available. */
537 gmtime_0 (const time_t * t, int x[9])
553 extern void gmtime_i4 (GFC_INTEGER_4 *, gfc_array_i4 *);
554 export_proto(gmtime_i4);
557 gmtime_i4 (GFC_INTEGER_4 * t, gfc_array_i4 * tarray)
564 /* Call helper function. */
568 /* Copy the values into the array. */
569 len = tarray->dim[0].ubound + 1 - tarray->dim[0].lbound;
571 delta = tarray->dim[0].stride;
576 for (i = 0; i < 9; i++, vptr += delta)
580 extern void gmtime_i8 (GFC_INTEGER_8 *, gfc_array_i8 *);
581 export_proto(gmtime_i8);
584 gmtime_i8 (GFC_INTEGER_8 * t, gfc_array_i8 * tarray)
591 /* Call helper function. */
595 /* Copy the values into the array. */
596 len = tarray->dim[0].ubound + 1 - tarray->dim[0].lbound;
598 delta = tarray->dim[0].stride;
603 for (i = 0; i < 9; i++, vptr += delta)
610 /* LTIME(STIME, TARRAY) - Non-standard
612 Description: Given a system time value STime, fills TArray with values
613 extracted from it appropriate to the local time zone using localtime(3).
615 The array elements are as follows:
617 1. Seconds after the minute, range 0-59 or 0-61 to allow for leap seconds
618 2. Minutes after the hour, range 0-59
619 3. Hours past midnight, range 0-23
620 4. Day of month, range 0-31
621 5. Number of months since January, range 0-11
623 7. Number of days since Sunday, range 0-6
624 8. Days since January 1
625 9. Daylight savings indicator: positive if daylight savings is in effect,
626 zero if not, and negative if the information isn't available. */
629 ltime_0 (const time_t * t, int x[9])
645 extern void ltime_i4 (GFC_INTEGER_4 *, gfc_array_i4 *);
646 export_proto(ltime_i4);
649 ltime_i4 (GFC_INTEGER_4 * t, gfc_array_i4 * tarray)
656 /* Call helper function. */
660 /* Copy the values into the array. */
661 len = tarray->dim[0].ubound + 1 - tarray->dim[0].lbound;
663 delta = tarray->dim[0].stride;
668 for (i = 0; i < 9; i++, vptr += delta)
672 extern void ltime_i8 (GFC_INTEGER_8 *, gfc_array_i8 *);
673 export_proto(ltime_i8);
676 ltime_i8 (GFC_INTEGER_8 * t, gfc_array_i8 * tarray)
683 /* Call helper function. */
687 /* Copy the values into the array. */
688 len = tarray->dim[0].ubound + 1 - tarray->dim[0].lbound;
690 delta = tarray->dim[0].stride;
695 for (i = 0; i < 9; i++, vptr += delta)