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>
28 #include "libgfortran.h"
30 #undef HAVE_NO_DATE_TIME
31 #if TIME_WITH_SYS_TIME
32 # include <sys/time.h>
36 # include <sys/time.h>
41 # define HAVE_NO_DATE_TIME
42 # endif /* HAVE_TIME_H */
43 # endif /* HAVE_SYS_TIME_H */
44 #endif /* TIME_WITH_SYS_TIME */
47 #define abs(x) ((x)>=0 ? (x) : -(x))
50 /* DATE_AND_TIME ([DATE, TIME, ZONE, VALUES])
52 Description: Returns data on the real-time clock and date in a form
53 compatible with the representations defined in ISO 8601:1988.
55 Class: Non-elemental subroutine.
59 DATE (optional) shall be scalar and of type default character, and
60 shall be of length at least 8 in order to contain the complete
61 value. It is an INTENT (OUT) argument. Its leftmost 8 characters
62 are assigned a value of the form CCYYMMDD, where CC is the century,
63 YY the year within the century, MM the month within the year, and
64 DD the day within the month. If there is no date available, they
67 TIME (optional) shall be scalar and of type default character, and
68 shall be of length at least 10 in order to contain the complete
69 value. It is an INTENT (OUT) argument. Its leftmost 10 characters
70 are assigned a value of the form hhmmss.sss, where hh is the hour
71 of the day, mm is the minutes of the hour, and ss.sss is the
72 seconds and milliseconds of the minute. If there is no clock
73 available, they are assigned blanks.
75 ZONE (optional) shall be scalar and of type default character, and
76 shall be of length at least 5 in order to contain the complete
77 value. It is an INTENT (OUT) argument. Its leftmost 5 characters
78 are assigned a value of the form ±hhmm, where hh and mm are the
79 time difference with respect to Coordinated Universal Time (UTC) in
80 hours and parts of an hour expressed in minutes, respectively. If
81 there is no clock available, they are assigned blanks.
83 VALUES (optional) shall be of type default integer and of rank
84 one. It is an INTENT (OUT) argument. Its size shall be at least
85 8. The values returned in VALUES are as follows:
87 VALUES (1) the year (for example, 2003), or HUGE (0) if there is
90 VALUES (2) the month of the year, or HUGE (0) if there
93 VALUES (3) the day of the month, or HUGE (0) if there is no date
96 VALUES (4) the time difference with respect to Coordinated
97 Universal Time (UTC) in minutes, or HUGE (0) if this information
100 VALUES (5) the hour of the day, in the range of 0 to 23, or HUGE
101 (0) if there is no clock;
103 VALUES (6) the minutes of the hour, in the range 0 to 59, or
104 HUGE (0) if there is no clock;
106 VALUES (7) the seconds of the minute, in the range 0 to 60, or
107 HUGE (0) if there is no clock;
109 VALUES (8) the milliseconds of the second, in the range 0 to
110 999, or HUGE (0) if there is no clock.
112 NULL pointer represent missing OPTIONAL arguments. All arguments
113 have INTENT(OUT). Because of the -i8 option, we must implement
114 VALUES for INTEGER(kind=4) and INTEGER(kind=8).
116 Based on libU77's date_time_.c.
119 - Check year boundaries.
120 - There is no STDC/POSIX way to get VALUES(8). A GNUish way may
124 extern void date_and_time (char *, char *, char *, gfc_array_i4
*,
125 GFC_INTEGER_4
, GFC_INTEGER_4
, GFC_INTEGER_4
);
126 export_proto(date_and_time
);
129 date_and_time (char *__date
,
132 gfc_array_i4
*__values
,
133 GFC_INTEGER_4 __date_len
,
134 GFC_INTEGER_4 __time_len
,
135 GFC_INTEGER_4 __zone_len
)
140 #define VALUES_SIZE 8
141 char date
[DATE_LEN
+ 1];
142 char timec
[TIME_LEN
+ 1];
143 char zone
[ZONE_LEN
+ 1];
144 GFC_INTEGER_4 values
[VALUES_SIZE
];
146 #ifndef HAVE_NO_DATE_TIME
147 time_t lt
= time (NULL
);
148 struct tm local_time
= *localtime (<
);
149 struct tm UTC_time
= *gmtime (<
);
151 /* All arguments can be derived from VALUES. */
152 values
[0] = 1900 + local_time
.tm_year
;
153 values
[1] = 1 + local_time
.tm_mon
;
154 values
[2] = local_time
.tm_mday
;
155 values
[3] = (local_time
.tm_min
- UTC_time
.tm_min
+
156 60 * (local_time
.tm_hour
- UTC_time
.tm_hour
+
157 24 * (local_time
.tm_yday
- UTC_time
.tm_yday
)));
158 values
[4] = local_time
.tm_hour
;
159 values
[5] = local_time
.tm_min
;
160 values
[6] = local_time
.tm_sec
;
161 #if HAVE_GETTIMEOFDAY
164 # if GETTIMEOFDAY_ONE_ARGUMENT
165 if (!gettimeofday (&tp
))
167 # if HAVE_STRUCT_TIMEZONE
170 /* Some systems such as HP-UX, do have struct timezone, but
171 gettimeofday takes void* as the 2nd arg. However, the
172 effect of passing anything other than a null pointer is
173 unspecified on HPUX. Configure checks if gettimeofday
174 actually fails with a non-NULL arg and pretends that
175 struct timezone is missing if it does fail. */
176 if (!gettimeofday (&tp
, &tzp
))
178 if (!gettimeofday (&tp
, (void *) 0))
179 # endif /* HAVE_STRUCT_TIMEZONE */
180 # endif /* GETTIMEOFDAY_ONE_ARGUMENT */
181 values
[7] = tp
.tv_usec
/ 1000;
184 values
[7] = GFC_INTEGER_4_HUGE
;
185 #endif /* HAVE_GETTIMEOFDAY */
190 snprintf (date
, DATE_LEN
+ 1, "%04d%02d%02d",
191 values
[0], values
[1], values
[2]);
193 sprintf (date
, "%04d%02d%02d",
194 values
[0], values
[1], values
[2]);
201 snprintf (timec
, TIME_LEN
+ 1, "%02d%02d%02d.%03d",
202 values
[4], values
[5], values
[6], values
[7]);
204 sprintf (timec
, "%02d%02d%02d.%03d",
205 values
[4], values
[5], values
[6], values
[7]);
212 snprintf (zone
, ZONE_LEN
+ 1, "%+03d%02d",
213 values
[3] / 60, abs (values
[3] % 60));
215 sprintf (zone
, "%+03d%02d",
216 values
[3] / 60, abs (values
[3] % 60));
219 #else /* if defined HAVE_NO_DATE_TIME */
220 /* 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 time
[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
;
236 #endif /* HAVE_NO_DATE_TIME */
238 /* Copy the values into the arguments. */
242 size_t len
, delta
, elt_size
;
244 elt_size
= GFC_DESCRIPTOR_SIZE (__values
);
245 len
= __values
->dim
[0].ubound
+ 1 - __values
->dim
[0].lbound
;
246 delta
= __values
->dim
[0].stride
;
250 assert (len
>= VALUES_SIZE
);
251 /* Cope with different type kinds. */
254 GFC_INTEGER_4
*vptr4
= __values
->data
;
256 for (i
= 0; i
< VALUES_SIZE
; i
++, vptr4
+= delta
)
261 else if (elt_size
== 8)
263 GFC_INTEGER_8
*vptr8
= (GFC_INTEGER_8
*)__values
->data
;
265 for (i
= 0; i
< VALUES_SIZE
; i
++, vptr8
+= delta
)
267 if (values
[i
] == GFC_INTEGER_4_HUGE
)
268 *vptr8
= GFC_INTEGER_8_HUGE
;
279 assert (__zone_len
>= ZONE_LEN
);
280 fstrcpy (__zone
, ZONE_LEN
, zone
, ZONE_LEN
);
285 assert (__time_len
>= TIME_LEN
);
286 fstrcpy (__time
, TIME_LEN
, timec
, TIME_LEN
);
291 assert (__date_len
>= DATE_LEN
);
292 fstrcpy (__date
, DATE_LEN
, date
, DATE_LEN
);