PR 47571 Fix HPUX bootstrap regression, cleanup
[official-gcc.git] / libgfortran / intrinsics / date_and_time.c
blobc58d11437b3e192a636a231952d254f15a1abb25
1 /* Implementation of the DATE_AND_TIME intrinsic.
2 Copyright (C) 2003, 2004, 2005, 2006, 2007, 2009, 2010, 2011
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"
28 #include <string.h>
29 #include <assert.h>
30 #include <stdlib.h>
32 #include "time_1.h"
34 #ifndef abs
35 #define abs(x) ((x)>=0 ? (x) : -(x))
36 #endif
39 /* If the re-entrant versions of localtime and gmtime are not
40 available, provide fallback implementations. On some targets where
41 the _r versions are not available, localtime and gmtime use
42 thread-local storage so they are threadsafe. */
44 #ifndef HAVE_LOCALTIME_R
45 /* If _POSIX is defined localtime_r gets defined by mingw-w64 headers. */
46 #ifdef localtime_r
47 #undef localtime_r
48 #endif
50 static struct tm *
51 localtime_r (const time_t * timep, struct tm * result)
53 *result = *localtime (timep);
54 return result;
56 #endif
58 #ifndef HAVE_GMTIME_R
59 /* If _POSIX is defined gmtime_r gets defined by mingw-w64 headers. */
60 #ifdef gmtime_r
61 #undef gmtime_r
62 #endif
64 static struct tm *
65 gmtime_r (const time_t * timep, struct tm * result)
67 *result = *gmtime (timep);
68 return result;
70 #endif
73 /* DATE_AND_TIME ([DATE, TIME, ZONE, VALUES])
75 Description: Returns data on the real-time clock and date in a form
76 compatible with the representations defined in ISO 8601:1988.
78 Class: Non-elemental subroutine.
80 Arguments:
82 DATE (optional) shall be scalar and of type default character.
83 It is an INTENT(OUT) argument. It is assigned a value of the
84 form CCYYMMDD, where CC is the century, YY the year within the
85 century, MM the month within the year, and DD the day within the
86 month. If there is no date available, they are assigned blanks.
88 TIME (optional) shall be scalar and of type default character.
89 It is an INTENT(OUT) argument. It is assigned a value of the
90 form hhmmss.sss, where hh is the hour of the day, mm is the
91 minutes of the hour, and ss.sss is the seconds and milliseconds
92 of the minute. If there is no clock available, they are assigned
93 blanks.
95 ZONE (optional) shall be scalar and of type default character.
96 It is an INTENT(OUT) argument. It is assigned a value of the
97 form [+-]hhmm, where hh and mm are the time difference with
98 respect to Coordinated Universal Time (UTC) in hours and parts
99 of an hour expressed in minutes, respectively. If there is no
100 clock available, they are assigned blanks.
102 VALUES (optional) shall be of type default integer and of rank
103 one. It is an INTENT(OUT) argument. Its size shall be at least
104 8. The values returned in VALUES are as follows:
106 VALUES(1) the year (for example, 2003), or -HUGE(0) if there is
107 no date available;
109 VALUES(2) the month of the year, or -HUGE(0) if there
110 is no date available;
112 VALUES(3) the day of the month, or -HUGE(0) if there is no date
113 available;
115 VALUES(4) the time difference with respect to Coordinated
116 Universal Time (UTC) in minutes, or -HUGE(0) if this information
117 is not available;
119 VALUES(5) the hour of the day, in the range of 0 to 23, or
120 -HUGE(0) if there is no clock;
122 VALUES(6) the minutes of the hour, in the range 0 to 59, or
123 -HUGE(0) if there is no clock;
125 VALUES(7) the seconds of the minute, in the range 0 to 60, or
126 -HUGE(0) if there is no clock;
128 VALUES(8) the milliseconds of the second, in the range 0 to
129 999, or -HUGE(0) if there is no clock.
131 NULL pointer represent missing OPTIONAL arguments. All arguments
132 have INTENT(OUT). Because of the -i8 option, we must implement
133 VALUES for INTEGER(kind=4) and INTEGER(kind=8).
135 Based on libU77's date_time_.c.
137 TODO :
138 - Check year boundaries.
140 #define DATE_LEN 8
141 #define TIME_LEN 10
142 #define ZONE_LEN 5
143 #define VALUES_SIZE 8
145 extern void date_and_time (char *, char *, char *, gfc_array_i4 *,
146 GFC_INTEGER_4, GFC_INTEGER_4, GFC_INTEGER_4);
147 export_proto(date_and_time);
149 void
150 date_and_time (char *__date, char *__time, char *__zone,
151 gfc_array_i4 *__values, GFC_INTEGER_4 __date_len,
152 GFC_INTEGER_4 __time_len, GFC_INTEGER_4 __zone_len)
154 int i;
155 char date[DATE_LEN + 1];
156 char timec[TIME_LEN + 1];
157 char zone[ZONE_LEN + 1];
158 GFC_INTEGER_4 values[VALUES_SIZE];
160 #ifndef HAVE_NO_DATE_TIME
161 time_t lt;
162 struct tm local_time;
163 struct tm UTC_time;
165 long usecs;
167 if (!gf_gettime (&lt, &usecs))
169 values[7] = usecs / 1000;
171 localtime_r (&lt, &local_time);
172 gmtime_r (&lt, &UTC_time);
174 /* All arguments can be derived from VALUES. */
175 values[0] = 1900 + local_time.tm_year;
176 values[1] = 1 + local_time.tm_mon;
177 values[2] = local_time.tm_mday;
178 values[3] = (local_time.tm_min - UTC_time.tm_min +
179 60 * (local_time.tm_hour - UTC_time.tm_hour +
180 24 * (local_time.tm_yday - UTC_time.tm_yday)));
181 values[4] = local_time.tm_hour;
182 values[5] = local_time.tm_min;
183 values[6] = local_time.tm_sec;
185 #if HAVE_SNPRINTF
186 if (__date)
187 snprintf (date, DATE_LEN + 1, "%04d%02d%02d",
188 values[0], values[1], values[2]);
189 if (__time)
190 snprintf (timec, TIME_LEN + 1, "%02d%02d%02d.%03d",
191 values[4], values[5], values[6], values[7]);
193 if (__zone)
194 snprintf (zone, ZONE_LEN + 1, "%+03d%02d",
195 values[3] / 60, abs (values[3] % 60));
196 #else
197 if (__date)
198 sprintf (date, "%04d%02d%02d", values[0], values[1], values[2]);
200 if (__time)
201 sprintf (timec, "%02d%02d%02d.%03d",
202 values[4], values[5], values[6], values[7]);
204 if (__zone)
205 sprintf (zone, "%+03d%02d",
206 values[3] / 60, abs (values[3] % 60));
207 #endif
209 else
211 memset (date, ' ', DATE_LEN);
212 date[DATE_LEN] = '\0';
214 memset (timec, ' ', TIME_LEN);
215 timec[TIME_LEN] = '\0';
217 memset (zone, ' ', ZONE_LEN);
218 zone[ZONE_LEN] = '\0';
220 for (i = 0; i < VALUES_SIZE; i++)
221 values[i] = - GFC_INTEGER_4_HUGE;
223 #else /* if defined HAVE_NO_DATE_TIME */
224 /* We really have *nothing* to return, so return blanks and HUGE(0). */
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;
237 #endif /* HAVE_NO_DATE_TIME */
239 /* Copy the values into the arguments. */
240 if (__values)
242 index_type len, delta, elt_size;
244 elt_size = GFC_DESCRIPTOR_SIZE (__values);
245 len = GFC_DESCRIPTOR_EXTENT(__values,0);
246 delta = GFC_DESCRIPTOR_STRIDE(__values,0);
247 if (delta == 0)
248 delta = 1;
250 if (unlikely (len < VALUES_SIZE))
251 runtime_error ("Incorrect extent in VALUE argument to"
252 " DATE_AND_TIME intrinsic: is %ld, should"
253 " be >=%ld", (long int) len, (long int) VALUES_SIZE);
255 /* Cope with different type kinds. */
256 if (elt_size == 4)
258 GFC_INTEGER_4 *vptr4 = __values->data;
260 for (i = 0; i < VALUES_SIZE; i++, vptr4 += delta)
261 *vptr4 = values[i];
263 else if (elt_size == 8)
265 GFC_INTEGER_8 *vptr8 = (GFC_INTEGER_8 *)__values->data;
267 for (i = 0; i < VALUES_SIZE; i++, vptr8 += delta)
269 if (values[i] == - GFC_INTEGER_4_HUGE)
270 *vptr8 = - GFC_INTEGER_8_HUGE;
271 else
272 *vptr8 = values[i];
275 else
276 abort ();
279 if (__zone)
280 fstrcpy (__zone, __zone_len, zone, ZONE_LEN);
282 if (__time)
283 fstrcpy (__time, __time_len, timec, TIME_LEN);
285 if (__date)
286 fstrcpy (__date, __date_len, date, DATE_LEN);
290 /* SECNDS (X) - Non-standard
292 Description: Returns the system time of day, or elapsed time, as a GFC_REAL_4
293 in seconds.
295 Class: Non-elemental subroutine.
297 Arguments:
299 X must be REAL(4) and the result is of the same type. The accuracy is system
300 dependent.
302 Usage:
304 T = SECNDS (X)
306 yields the time in elapsed seconds since X. If X is 0.0, T is the time in
307 seconds since midnight. Note that a time that spans midnight but is less than
308 24hours will be calculated correctly. */
310 extern GFC_REAL_4 secnds (GFC_REAL_4 *);
311 export_proto(secnds);
313 GFC_REAL_4
314 secnds (GFC_REAL_4 *x)
316 GFC_INTEGER_4 values[VALUES_SIZE];
317 GFC_REAL_4 temp1, temp2;
319 /* Make the INTEGER*4 array for passing to date_and_time. */
320 gfc_array_i4 *avalues = internal_malloc_size (sizeof (gfc_array_i4));
321 avalues->data = &values[0];
322 GFC_DESCRIPTOR_DTYPE (avalues) = ((BT_REAL << GFC_DTYPE_TYPE_SHIFT)
323 & GFC_DTYPE_TYPE_MASK) +
324 (4 << GFC_DTYPE_SIZE_SHIFT);
326 GFC_DIMENSION_SET(avalues->dim[0], 0, 7, 1);
328 date_and_time (NULL, NULL, NULL, avalues, 0, 0, 0);
330 free (avalues);
332 temp1 = 3600.0 * (GFC_REAL_4)values[4] +
333 60.0 * (GFC_REAL_4)values[5] +
334 (GFC_REAL_4)values[6] +
335 0.001 * (GFC_REAL_4)values[7];
336 temp2 = fmod (*x, 86400.0);
337 temp2 = (temp1 - temp2 >= 0.0) ? temp2 : (temp2 - 86400.0);
338 return temp1 - temp2;
343 /* ITIME(X) - Non-standard
345 Description: Returns the current local time hour, minutes, and seconds
346 in elements 1, 2, and 3 of X, respectively. */
348 static void
349 itime0 (int x[3])
351 #ifndef HAVE_NO_DATE_TIME
352 time_t lt;
353 struct tm local_time;
355 lt = time (NULL);
357 if (lt != (time_t) -1)
359 localtime_r (&lt, &local_time);
361 x[0] = local_time.tm_hour;
362 x[1] = local_time.tm_min;
363 x[2] = local_time.tm_sec;
365 #else
366 x[0] = x[1] = x[2] = -1;
367 #endif
370 extern void itime_i4 (gfc_array_i4 *);
371 export_proto(itime_i4);
373 void
374 itime_i4 (gfc_array_i4 *__values)
376 int x[3], i;
377 index_type len, delta;
378 GFC_INTEGER_4 *vptr;
380 /* Call helper function. */
381 itime0(x);
383 /* Copy the value into the array. */
384 len = GFC_DESCRIPTOR_EXTENT(__values,0);
385 assert (len >= 3);
386 delta = GFC_DESCRIPTOR_STRIDE(__values,0);
387 if (delta == 0)
388 delta = 1;
390 vptr = __values->data;
391 for (i = 0; i < 3; i++, vptr += delta)
392 *vptr = x[i];
396 extern void itime_i8 (gfc_array_i8 *);
397 export_proto(itime_i8);
399 void
400 itime_i8 (gfc_array_i8 *__values)
402 int x[3], i;
403 index_type len, delta;
404 GFC_INTEGER_8 *vptr;
406 /* Call helper function. */
407 itime0(x);
409 /* Copy the value into the array. */
410 len = GFC_DESCRIPTOR_EXTENT(__values,0);
411 assert (len >= 3);
412 delta = GFC_DESCRIPTOR_STRIDE(__values,0);
413 if (delta == 0)
414 delta = 1;
416 vptr = __values->data;
417 for (i = 0; i < 3; i++, vptr += delta)
418 *vptr = x[i];
423 /* IDATE(X) - Non-standard
425 Description: Fills TArray with the numerical values at the current
426 local time. The day (in the range 1-31), month (in the range 1-12),
427 and year appear in elements 1, 2, and 3 of X, respectively.
428 The year has four significant digits. */
430 static void
431 idate0 (int x[3])
433 #ifndef HAVE_NO_DATE_TIME
434 time_t lt;
435 struct tm local_time;
437 lt = time (NULL);
439 if (lt != (time_t) -1)
441 localtime_r (&lt, &local_time);
443 x[0] = local_time.tm_mday;
444 x[1] = 1 + local_time.tm_mon;
445 x[2] = 1900 + local_time.tm_year;
447 #else
448 x[0] = x[1] = x[2] = -1;
449 #endif
452 extern void idate_i4 (gfc_array_i4 *);
453 export_proto(idate_i4);
455 void
456 idate_i4 (gfc_array_i4 *__values)
458 int x[3], i;
459 index_type len, delta;
460 GFC_INTEGER_4 *vptr;
462 /* Call helper function. */
463 idate0(x);
465 /* Copy the value into the array. */
466 len = GFC_DESCRIPTOR_EXTENT(__values,0);
467 assert (len >= 3);
468 delta = GFC_DESCRIPTOR_STRIDE(__values,0);
469 if (delta == 0)
470 delta = 1;
472 vptr = __values->data;
473 for (i = 0; i < 3; i++, vptr += delta)
474 *vptr = x[i];
478 extern void idate_i8 (gfc_array_i8 *);
479 export_proto(idate_i8);
481 void
482 idate_i8 (gfc_array_i8 *__values)
484 int x[3], i;
485 index_type len, delta;
486 GFC_INTEGER_8 *vptr;
488 /* Call helper function. */
489 idate0(x);
491 /* Copy the value into the array. */
492 len = GFC_DESCRIPTOR_EXTENT(__values,0);
493 assert (len >= 3);
494 delta = GFC_DESCRIPTOR_STRIDE(__values,0);
495 if (delta == 0)
496 delta = 1;
498 vptr = __values->data;
499 for (i = 0; i < 3; i++, vptr += delta)
500 *vptr = x[i];
505 /* GMTIME(STIME, TARRAY) - Non-standard
507 Description: Given a system time value STime, fills TArray with values
508 extracted from it appropriate to the GMT time zone using gmtime_r(3).
510 The array elements are as follows:
512 1. Seconds after the minute, range 0-59 or 0-61 to allow for leap seconds
513 2. Minutes after the hour, range 0-59
514 3. Hours past midnight, range 0-23
515 4. Day of month, range 0-31
516 5. Number of months since January, range 0-11
517 6. Years since 1900
518 7. Number of days since Sunday, range 0-6
519 8. Days since January 1
520 9. Daylight savings indicator: positive if daylight savings is in effect,
521 zero if not, and negative if the information isn't available. */
523 static void
524 gmtime_0 (const time_t * t, int x[9])
526 struct tm lt;
528 gmtime_r (t, &lt);
529 x[0] = lt.tm_sec;
530 x[1] = lt.tm_min;
531 x[2] = lt.tm_hour;
532 x[3] = lt.tm_mday;
533 x[4] = lt.tm_mon;
534 x[5] = lt.tm_year;
535 x[6] = lt.tm_wday;
536 x[7] = lt.tm_yday;
537 x[8] = lt.tm_isdst;
540 extern void gmtime_i4 (GFC_INTEGER_4 *, gfc_array_i4 *);
541 export_proto(gmtime_i4);
543 void
544 gmtime_i4 (GFC_INTEGER_4 * t, gfc_array_i4 * tarray)
546 int x[9], i;
547 index_type len, delta;
548 GFC_INTEGER_4 *vptr;
549 time_t tt;
551 /* Call helper function. */
552 tt = (time_t) *t;
553 gmtime_0(&tt, x);
555 /* Copy the values into the array. */
556 len = GFC_DESCRIPTOR_EXTENT(tarray,0);
557 assert (len >= 9);
558 delta = GFC_DESCRIPTOR_STRIDE(tarray,0);
559 if (delta == 0)
560 delta = 1;
562 vptr = tarray->data;
563 for (i = 0; i < 9; i++, vptr += delta)
564 *vptr = x[i];
567 extern void gmtime_i8 (GFC_INTEGER_8 *, gfc_array_i8 *);
568 export_proto(gmtime_i8);
570 void
571 gmtime_i8 (GFC_INTEGER_8 * t, gfc_array_i8 * tarray)
573 int x[9], i;
574 index_type len, delta;
575 GFC_INTEGER_8 *vptr;
576 time_t tt;
578 /* Call helper function. */
579 tt = (time_t) *t;
580 gmtime_0(&tt, x);
582 /* Copy the values into the array. */
583 len = GFC_DESCRIPTOR_EXTENT(tarray,0);
584 assert (len >= 9);
585 delta = GFC_DESCRIPTOR_STRIDE(tarray,0);
586 if (delta == 0)
587 delta = 1;
589 vptr = tarray->data;
590 for (i = 0; i < 9; i++, vptr += delta)
591 *vptr = x[i];
597 /* LTIME(STIME, TARRAY) - Non-standard
599 Description: Given a system time value STime, fills TArray with values
600 extracted from it appropriate to the local time zone using localtime_r(3).
602 The array elements are as follows:
604 1. Seconds after the minute, range 0-59 or 0-61 to allow for leap seconds
605 2. Minutes after the hour, range 0-59
606 3. Hours past midnight, range 0-23
607 4. Day of month, range 0-31
608 5. Number of months since January, range 0-11
609 6. Years since 1900
610 7. Number of days since Sunday, range 0-6
611 8. Days since January 1
612 9. Daylight savings indicator: positive if daylight savings is in effect,
613 zero if not, and negative if the information isn't available. */
615 static void
616 ltime_0 (const time_t * t, int x[9])
618 struct tm lt;
620 localtime_r (t, &lt);
621 x[0] = lt.tm_sec;
622 x[1] = lt.tm_min;
623 x[2] = lt.tm_hour;
624 x[3] = lt.tm_mday;
625 x[4] = lt.tm_mon;
626 x[5] = lt.tm_year;
627 x[6] = lt.tm_wday;
628 x[7] = lt.tm_yday;
629 x[8] = lt.tm_isdst;
632 extern void ltime_i4 (GFC_INTEGER_4 *, gfc_array_i4 *);
633 export_proto(ltime_i4);
635 void
636 ltime_i4 (GFC_INTEGER_4 * t, gfc_array_i4 * tarray)
638 int x[9], i;
639 index_type len, delta;
640 GFC_INTEGER_4 *vptr;
641 time_t tt;
643 /* Call helper function. */
644 tt = (time_t) *t;
645 ltime_0(&tt, x);
647 /* Copy the values into the array. */
648 len = GFC_DESCRIPTOR_EXTENT(tarray,0);
649 assert (len >= 9);
650 delta = GFC_DESCRIPTOR_STRIDE(tarray,0);
651 if (delta == 0)
652 delta = 1;
654 vptr = tarray->data;
655 for (i = 0; i < 9; i++, vptr += delta)
656 *vptr = x[i];
659 extern void ltime_i8 (GFC_INTEGER_8 *, gfc_array_i8 *);
660 export_proto(ltime_i8);
662 void
663 ltime_i8 (GFC_INTEGER_8 * t, gfc_array_i8 * tarray)
665 int x[9], i;
666 index_type len, delta;
667 GFC_INTEGER_8 *vptr;
668 time_t tt;
670 /* Call helper function. */
671 tt = (time_t) * t;
672 ltime_0(&tt, x);
674 /* Copy the values into the array. */
675 len = GFC_DESCRIPTOR_EXTENT(tarray,0);
676 assert (len >= 9);
677 delta = GFC_DESCRIPTOR_STRIDE(tarray,0);
678 if (delta == 0)
679 delta = 1;
681 vptr = tarray->data;
682 for (i = 0; i < 9; i++, vptr += delta)
683 *vptr = x[i];