abort.c ("libgfortran.h"): Move.
[gcc.git] / libgfortran / intrinsics / date_and_time.c
1 /* Implementation of the DATE_AND_TIME intrinsic.
2 Copyright (C) 2003, 2004 Free Software Foundation, Inc.
3 Contributed by Steven Bosscher.
4
5 This file is part of the GNU Fortran 95 runtime library (libgfor).
6
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.
11
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.
16
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. */
21
22 #include "config.h"
23 #include <sys/types.h>
24 #include <string.h>
25 #include <assert.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include "libgfortran.h"
29
30 #undef HAVE_NO_DATE_TIME
31 #if TIME_WITH_SYS_TIME
32 # include <sys/time.h>
33 # include <time.h>
34 #else
35 # if HAVE_SYS_TIME_H
36 # include <sys/time.h>
37 # else
38 # ifdef HAVE_TIME_H
39 # include <time.h>
40 # else
41 # define HAVE_NO_DATE_TIME
42 # endif /* HAVE_TIME_H */
43 # endif /* HAVE_SYS_TIME_H */
44 #endif /* TIME_WITH_SYS_TIME */
45
46 #ifndef abs
47 #define abs(x) ((x)>=0 ? (x) : -(x))
48 #endif
49
50 /* DATE_AND_TIME ([DATE, TIME, ZONE, VALUES])
51
52 Description: Returns data on the real-time clock and date in a form
53 compatible with the representations defined in ISO 8601:1988.
54
55 Class: Non-elemental subroutine.
56
57 Arguments:
58
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
65 are assigned blanks.
66
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.
74
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.
82
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:
86
87 VALUES (1) the year (for example, 2003), or HUGE (0) if there is
88 no date available;
89
90 VALUES (2) the month of the year, or HUGE (0) if there
91 is no date available;
92
93 VALUES (3) the day of the month, or HUGE (0) if there is no date
94 available;
95
96 VALUES (4) the time difference with respect to Coordinated
97 Universal Time (UTC) in minutes, or HUGE (0) if this information
98 is not available;
99
100 VALUES (5) the hour of the day, in the range of 0 to 23, or HUGE
101 (0) if there is no clock;
102
103 VALUES (6) the minutes of the hour, in the range 0 to 59, or
104 HUGE (0) if there is no clock;
105
106 VALUES (7) the seconds of the minute, in the range 0 to 60, or
107 HUGE (0) if there is no clock;
108
109 VALUES (8) the milliseconds of the second, in the range 0 to
110 999, or HUGE (0) if there is no clock.
111
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).
115
116 Based on libU77's date_time_.c.
117
118 TODO :
119 - Check year boundaries.
120 - There is no STDC/POSIX way to get VALUES(8). A GNUish way may
121 be to use ftime.
122 */
123
124 void
125 date_and_time (char *__date,
126 char *__time,
127 char *__zone,
128 gfc_array_i4 *__values,
129 GFC_INTEGER_4 __date_len,
130 GFC_INTEGER_4 __time_len,
131 GFC_INTEGER_4 __zone_len)
132 {
133 #define DATE_LEN 8
134 #define TIME_LEN 10
135 #define ZONE_LEN 5
136 #define VALUES_SIZE 8
137 char date[DATE_LEN + 1];
138 char timec[TIME_LEN + 1];
139 char zone[ZONE_LEN + 1];
140 GFC_INTEGER_4 values[VALUES_SIZE];
141
142 #ifndef HAVE_NO_DATE_TIME
143 time_t lt = time (NULL);
144 struct tm local_time = *localtime (&lt);
145 struct tm UTC_time = *gmtime (&lt);
146
147 /* All arguments can be derived from VALUES. */
148 values[0] = 1900 + local_time.tm_year;
149 values[1] = 1 + local_time.tm_mon;
150 values[2] = local_time.tm_mday;
151 values[3] = (local_time.tm_min - UTC_time.tm_min +
152 60 * (local_time.tm_hour - UTC_time.tm_hour +
153 24 * (local_time.tm_yday - UTC_time.tm_yday)));
154 values[4] = local_time.tm_hour;
155 values[5] = local_time.tm_min;
156 values[6] = local_time.tm_sec;
157 #if HAVE_GETTIMEOFDAY
158 {
159 struct timeval tp;
160 # if GETTIMEOFDAY_ONE_ARGUMENT
161 if (!gettimeofday (&tp))
162 # else
163 # if HAVE_STRUCT_TIMEZONE
164 struct timezone tzp;
165
166 /* Some systems such as HP-UX, do have struct timezone, but
167 gettimeofday takes void* as the 2nd arg. However, the
168 effect of passing anything other than a null pointer is
169 unspecified on HPUX. Configure checks if gettimeofday
170 actually fails with a non-NULL arg and pretends that
171 struct timezone is missing if it does fail. */
172 if (!gettimeofday (&tp, &tzp))
173 # else
174 if (!gettimeofday (&tp, (void *) 0))
175 # endif /* HAVE_STRUCT_TIMEZONE */
176 # endif /* GETTIMEOFDAY_ONE_ARGUMENT */
177 values[7] = tp.tv_usec / 1000;
178 }
179 #else
180 values[7] = GFC_INTEGER_4_HUGE;
181 #endif /* HAVE_GETTIMEOFDAY */
182
183 if (__date)
184 {
185 snprintf (date, DATE_LEN + 1, "%04d%02d%02d",
186 values[0], values[1], values[2]);
187 }
188
189 if (__time)
190 {
191 snprintf (timec, TIME_LEN + 1, "%02d%02d%02d.%03d",
192 values[4], values[5], values[6], values[7]);
193 }
194
195 if (__zone)
196 {
197 snprintf (zone, ZONE_LEN + 1, "%+03d%02d",
198 values[3] / 60, abs (values[3] % 60));
199 }
200 #else /* if defined HAVE_NO_DATE_TIME */
201 /* We really have *nothing* to return, so return blanks and HUGE(0). */
202 {
203 int i;
204
205 memset (date, ' ', DATE_LEN);
206 date[DATE_LEN] = '\0';
207
208 memset (timec, ' ', TIME_LEN);
209 time[TIME_LEN] = '\0';
210
211 memset (zone, ' ', ZONE_LEN);
212 zone[ZONE_LEN] = '\0';
213
214 for (i = 0; i < VALUES_SIZE; i++)
215 values[i] = GFC_INTEGER_4_HUGE;
216 }
217 #endif /* HAVE_NO_DATE_TIME */
218
219 /* Copy the values into the arguments. */
220 if (__values)
221 {
222 int i;
223 size_t len, delta, elt_size;
224
225 elt_size = GFC_DESCRIPTOR_SIZE (__values);
226 len = __values->dim[0].ubound + 1 - __values->dim[0].lbound;
227 delta = __values->dim[0].stride;
228 if (delta == 0)
229 delta = 1;
230
231 assert (len >= VALUES_SIZE);
232 /* Cope with different type kinds. */
233 if (elt_size == 4)
234 {
235 GFC_INTEGER_4 *vptr4 = __values->data;
236
237 for (i = 0; i < VALUES_SIZE; i++, vptr4 += delta)
238 {
239 *vptr4 = values[i];
240 }
241 }
242 else if (elt_size == 8)
243 {
244 GFC_INTEGER_8 *vptr8 = (GFC_INTEGER_8 *)__values->data;
245
246 for (i = 0; i < VALUES_SIZE; i++, vptr8 += delta)
247 {
248 if (values[i] == GFC_INTEGER_4_HUGE)
249 *vptr8 = GFC_INTEGER_8_HUGE;
250 else
251 *vptr8 = values[i];
252 }
253 }
254 else
255 abort ();
256 }
257
258 if (__zone)
259 {
260 assert (__zone_len >= ZONE_LEN);
261 fstrcpy (__zone, ZONE_LEN, zone, ZONE_LEN);
262 }
263
264 if (__time)
265 {
266 assert (__time_len >= TIME_LEN);
267 fstrcpy (__time, TIME_LEN, timec, TIME_LEN);
268 }
269
270 if (__date)
271 {
272 assert (__date_len >= DATE_LEN);
273 fstrcpy (__date, DATE_LEN, date, DATE_LEN);
274 }
275 #undef DATE_LEN
276 #undef TIME_LEN
277 #undef ZONE_LEN
278 #undef VALUES_SIZE
279 }