1 /* Implementation of the DATE_AND_TIME intrinsic.
2 Copyright (C) 2003, 2004 Free Software Foundation, Inc.
3 Contributed by Steven Bosscher.
5 This file is part of the GNU Fortran 95 runtime library (libgfor).
7 Libgfor is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
12 Libgfor 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 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with libgfor; see the file COPYING.LIB. If not,
19 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
23 #include <sys/types.h>
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 HUGE
102 (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.
121 - There is no STDC/POSIX way to get VALUES(8). A GNUish way may
126 date_and_time (char *__date
,
129 gfc_array_i4
*__values
,
130 GFC_INTEGER_4 __date_len
,
131 GFC_INTEGER_4 __time_len
,
132 GFC_INTEGER_4 __zone_len
)
137 #define VALUES_SIZE 8
138 char date
[DATE_LEN
+ 1];
139 char timec
[TIME_LEN
+ 1];
140 char zone
[ZONE_LEN
+ 1];
141 GFC_INTEGER_4 values
[VALUES_SIZE
];
143 #ifndef HAVE_NO_DATE_TIME
144 time_t lt
= time (NULL
);
145 struct tm local_time
= *localtime (<
);
146 struct tm UTC_time
= *gmtime (<
);
148 /* All arguments can be derived from VALUES. */
149 values
[0] = 1900 + local_time
.tm_year
;
150 values
[1] = 1 + local_time
.tm_mon
;
151 values
[2] = local_time
.tm_mday
;
152 values
[3] = (local_time
.tm_min
- UTC_time
.tm_min
+
153 60 * (local_time
.tm_hour
- UTC_time
.tm_hour
+
154 24 * (local_time
.tm_yday
- UTC_time
.tm_yday
)));
155 values
[4] = local_time
.tm_hour
;
156 values
[5] = local_time
.tm_min
;
157 values
[6] = local_time
.tm_sec
;
158 #if HAVE_GETTIMEOFDAY
161 # if GETTIMEOFDAY_ONE_ARGUMENT
162 if (!gettimeofday (&tp
))
164 # if HAVE_STRUCT_TIMEZONE
167 /* Some systems such as HP-UX, do have struct timezone, but
168 gettimeofday takes void* as the 2nd arg. However, the
169 effect of passing anything other than a null pointer is
170 unspecified on HPUX. Configure checks if gettimeofday
171 actually fails with a non-NULL arg and pretends that
172 struct timezone is missing if it does fail. */
173 if (!gettimeofday (&tp
, &tzp
))
175 if (!gettimeofday (&tp
, (void *) 0))
176 # endif /* HAVE_STRUCT_TIMEZONE */
177 # endif /* GETTIMEOFDAY_ONE_ARGUMENT */
178 values
[7] = tp
.tv_usec
/ 1000;
181 values
[7] = GFC_INTEGER_4_HUGE
;
182 #endif /* HAVE_GETTIMEOFDAY */
186 snprintf (date
, DATE_LEN
+ 1, "%04d%02d%02d",
187 values
[0], values
[1], values
[2]);
192 snprintf (timec
, TIME_LEN
+ 1, "%02d%02d%02d.%03d",
193 values
[4], values
[5], values
[6], values
[7]);
198 snprintf (zone
, ZONE_LEN
+ 1, "%+03d%02d",
199 values
[3] / 60, abs (values
[3] % 60));
201 #else /* if defined HAVE_NO_DATE_TIME */
202 /* We really have *nothing* to return, so return blanks and HUGE(0). */
206 memset (date
, ' ', DATE_LEN
);
207 date
[DATE_LEN
] = '\0';
209 memset (timec
, ' ', TIME_LEN
);
210 time
[TIME_LEN
] = '\0';
212 memset (zone
, ' ', ZONE_LEN
);
213 zone
[ZONE_LEN
] = '\0';
215 for (i
= 0; i
< VALUES_SIZE
; i
++)
216 values
[i
] = GFC_INTEGER_4_HUGE
;
218 #endif /* HAVE_NO_DATE_TIME */
220 /* Copy the values into the arguments. */
224 size_t len
, delta
, elt_size
;
226 elt_size
= GFC_DESCRIPTOR_SIZE (__values
);
227 len
= __values
->dim
[0].ubound
+ 1 - __values
->dim
[0].lbound
;
228 delta
= __values
->dim
[0].stride
;
232 assert (len
>= VALUES_SIZE
);
233 /* Cope with different type kinds. */
236 GFC_INTEGER_4
*vptr4
= __values
->data
;
238 for (i
= 0; i
< VALUES_SIZE
; i
++, vptr4
+= delta
)
243 else if (elt_size
== 8)
245 GFC_INTEGER_8
*vptr8
= (GFC_INTEGER_8
*)__values
->data
;
247 for (i
= 0; i
< VALUES_SIZE
; i
++, vptr8
+= delta
)
249 if (values
[i
] == GFC_INTEGER_4_HUGE
)
250 *vptr8
= GFC_INTEGER_8_HUGE
;
261 assert (__zone_len
>= ZONE_LEN
);
262 fstrcpy (__zone
, ZONE_LEN
, zone
, ZONE_LEN
);
267 assert (__time_len
>= TIME_LEN
);
268 fstrcpy (__time
, TIME_LEN
, timec
, TIME_LEN
);
273 assert (__date_len
>= DATE_LEN
);
274 fstrcpy (__date
, DATE_LEN
, date
, DATE_LEN
);