OSDN Git Service

PR target/16135
[pf3gnuchains/gcc-fork.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 #if HAVE_SNPRINTF
186       snprintf (date, DATE_LEN + 1, "%04d%02d%02d",
187                 values[0], values[1], values[2]);
188 #else
189       sprintf (date, "%04d%02d%02d",
190                values[0], values[1], values[2]);
191 #endif
192     }
193
194   if (__time)
195     {
196 #if HAVE_SNPRINTF
197       snprintf (timec, TIME_LEN + 1, "%02d%02d%02d.%03d",
198                 values[4], values[5], values[6], values[7]);
199 #else
200       sprintf (timec, "%02d%02d%02d.%03d",
201                values[4], values[5], values[6], values[7]);
202 #endif
203     }
204
205   if (__zone)
206     {
207 #if HAVE_SNPRINTF
208       snprintf (zone, ZONE_LEN + 1, "%+03d%02d",
209                 values[3] / 60, abs (values[3] % 60));
210 #else
211       sprintf (zone, "%+03d%02d",
212                values[3] / 60, abs (values[3] % 60));
213 #endif
214     }
215 #else /* if defined HAVE_NO_DATE_TIME  */
216   /* We really have *nothing* to return, so return blanks and HUGE(0).  */
217     {
218       int i;
219
220       memset (date, ' ', DATE_LEN);
221       date[DATE_LEN] = '\0';
222
223       memset (timec, ' ', TIME_LEN);
224       time[TIME_LEN] = '\0';
225
226       memset (zone, ' ', ZONE_LEN);
227       zone[ZONE_LEN] = '\0';
228
229       for (i = 0; i < VALUES_SIZE; i++)
230         values[i] = GFC_INTEGER_4_HUGE;
231     }
232 #endif  /* HAVE_NO_DATE_TIME  */
233
234   /* Copy the values into the arguments.  */
235   if (__values)
236     {
237       int i;
238       size_t len, delta, elt_size;
239
240       elt_size = GFC_DESCRIPTOR_SIZE (__values);
241       len = __values->dim[0].ubound + 1 - __values->dim[0].lbound;
242       delta = __values->dim[0].stride;
243       if (delta == 0)
244         delta = 1;
245
246       assert (len >= VALUES_SIZE);
247       /* Cope with different type kinds.  */
248       if (elt_size == 4)
249         {
250           GFC_INTEGER_4 *vptr4 = __values->data;
251
252           for (i = 0; i < VALUES_SIZE; i++, vptr4 += delta)
253             {
254               *vptr4 = values[i];
255             }
256         }
257       else if (elt_size == 8)
258         {
259           GFC_INTEGER_8 *vptr8 = (GFC_INTEGER_8 *)__values->data;
260
261           for (i = 0; i < VALUES_SIZE; i++, vptr8 += delta)
262             {
263               if (values[i] == GFC_INTEGER_4_HUGE)
264                 *vptr8 = GFC_INTEGER_8_HUGE;
265               else
266                 *vptr8 = values[i];
267             }
268         }
269       else 
270         abort ();
271     }
272
273   if (__zone)
274     {
275       assert (__zone_len >= ZONE_LEN);
276       fstrcpy (__zone, ZONE_LEN, zone, ZONE_LEN);
277     }
278
279   if (__time)
280     {
281       assert (__time_len >= TIME_LEN);
282       fstrcpy (__time, TIME_LEN, timec, TIME_LEN);
283     }
284
285   if (__date)
286     {
287       assert (__date_len >= DATE_LEN);
288       fstrcpy (__date, DATE_LEN, date, DATE_LEN);
289     }
290 #undef DATE_LEN
291 #undef TIME_LEN   
292 #undef ZONE_LEN
293 #undef VALUES_SIZE
294 }