OSDN Git Service

* check.c (gfc_check_second_sub, gfc_check_irand, gfc_check_rand
[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 "libgfortran.h"
27
28 #include <stdio.h>
29 #include <stdlib.h>
30
31 #undef HAVE_NO_DATE_TIME
32 #if TIME_WITH_SYS_TIME
33 #  include <sys/time.h>
34 #  include <time.h>
35 #else
36 #  if HAVE_SYS_TIME_H
37 #    include <sys/time.h>
38 #  else
39 #    ifdef HAVE_TIME_H
40 #      include <time.h>
41 #    else
42 #      define HAVE_NO_DATE_TIME
43 #    endif  /* HAVE_TIME_H  */
44 #  endif  /* HAVE_SYS_TIME_H  */
45 #endif  /* TIME_WITH_SYS_TIME  */
46
47 #ifndef abs
48 #define abs(x) ((x)>=0 ? (x) : -(x))
49 #endif
50
51 /* DATE_AND_TIME ([DATE, TIME, ZONE, VALUES])
52
53    Description: Returns data on the real-time clock and date in a form
54    compatible with the representations defined in ISO 8601:1988.
55
56    Class: Non-elemental subroutine.
57
58    Arguments:
59
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
66    are assigned blanks.
67
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.
75
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.
83
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:
87
88       VALUES (1) the year (for example, 2003), or HUGE (0) if there is
89       no date available;
90
91       VALUES (2) the month of the year, or HUGE (0) if there
92       is no date available;
93
94       VALUES (3) the day of the month, or HUGE (0) if there is no date
95       available;
96
97       VALUES (4) the time difference with respect to Coordinated
98       Universal Time (UTC) in minutes, or HUGE (0) if this information
99       is not available;
100
101       VALUES (5) the hour of the day, in the range of 0 to 23, or HUGE
102       (0) if there is no clock;
103
104       VALUES (6) the minutes of the hour, in the range 0 to 59, or
105       HUGE (0) if there is no clock;
106
107       VALUES (7) the seconds of the minute, in the range 0 to 60, or
108       HUGE (0) if there is no clock;
109
110       VALUES (8) the milliseconds of the second, in the range 0 to
111       999, or HUGE (0) if there is no clock.
112
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).
116
117    Based on libU77's date_time_.c.
118
119    TODO :
120    - Check year boundaries.
121    - There is no STDC/POSIX way to get VALUES(8).  A GNUish way may
122      be to use ftime.
123 */
124
125 void
126 date_and_time (char *__date,
127                char *__time,
128                char *__zone,
129                gfc_array_i4 *__values,
130                GFC_INTEGER_4 __date_len,
131                GFC_INTEGER_4 __time_len,
132                GFC_INTEGER_4 __zone_len)
133 {
134 #define DATE_LEN 8
135 #define TIME_LEN 10   
136 #define ZONE_LEN 5
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];
142
143 #ifndef HAVE_NO_DATE_TIME
144   time_t lt = time (NULL);
145   struct tm local_time = *localtime (&lt);
146   struct tm UTC_time = *gmtime (&lt);
147
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
159     {
160       struct timeval tp;
161 #  if GETTIMEOFDAY_ONE_ARGUMENT
162       if (!gettimeofday (&tp))
163 #  else
164 #    if HAVE_STRUCT_TIMEZONE
165       struct timezone tzp;
166
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))
174 #    else
175       if (!gettimeofday (&tp, (void *) 0))
176 #    endif /* HAVE_STRUCT_TIMEZONE  */
177 #  endif /* GETTIMEOFDAY_ONE_ARGUMENT  */
178         values[7] = tp.tv_usec / 1000;
179     }
180 #else
181    values[7] = GFC_INTEGER_4_HUGE;
182 #endif /* HAVE_GETTIMEOFDAY */
183
184   if (__date)
185     {
186       snprintf (date, DATE_LEN + 1, "%04d%02d%02d",
187                 values[0], values[1], values[2]);
188     }
189
190   if (__time)
191     {
192       snprintf (timec, TIME_LEN + 1, "%02d%02d%02d.%03d",
193                 values[4], values[5], values[6], values[7]);
194     }
195
196   if (__zone)
197     {
198       snprintf (zone, ZONE_LEN + 1, "%+03d%02d",
199                 values[3] / 60, abs (values[3] % 60));
200     }
201 #else /* if defined HAVE_NO_DATE_TIME  */
202   /* We really have *nothing* to return, so return blanks and HUGE(0).  */
203     {
204       int i;
205
206       memset (date, ' ', DATE_LEN);
207       date[DATE_LEN] = '\0';
208
209       memset (timec, ' ', TIME_LEN);
210       time[TIME_LEN] = '\0';
211
212       memset (zone, ' ', ZONE_LEN);
213       zone[ZONE_LEN] = '\0';
214
215       for (i = 0; i < VALUES_SIZE; i++)
216         values[i] = GFC_INTEGER_4_HUGE;
217     }
218 #endif  /* HAVE_NO_DATE_TIME  */
219
220   /* Copy the values into the arguments.  */
221   if (__values)
222     {
223       int i;
224       size_t len, delta, elt_size;
225
226       elt_size = GFC_DESCRIPTOR_SIZE (__values);
227       len = __values->dim[0].ubound + 1 - __values->dim[0].lbound;
228       delta = __values->dim[0].stride;
229       if (delta == 0)
230         delta = 1;
231
232       assert (len >= VALUES_SIZE);
233       /* Cope with different type kinds.  */
234       if (elt_size == 4)
235         {
236           GFC_INTEGER_4 *vptr4 = __values->data;
237
238           for (i = 0; i < VALUES_SIZE; i++, vptr4 += delta)
239             {
240               *vptr4 = values[i];
241             }
242         }
243       else if (elt_size == 8)
244         {
245           GFC_INTEGER_8 *vptr8 = (GFC_INTEGER_8 *)__values->data;
246
247           for (i = 0; i < VALUES_SIZE; i++, vptr8 += delta)
248             {
249               if (values[i] == GFC_INTEGER_4_HUGE)
250                 *vptr8 = GFC_INTEGER_8_HUGE;
251               else
252                 *vptr8 = values[i];
253             }
254         }
255       else 
256         abort ();
257     }
258
259   if (__zone)
260     {
261       assert (__zone_len >= ZONE_LEN);
262       fstrcpy (__zone, ZONE_LEN, zone, ZONE_LEN);
263     }
264
265   if (__time)
266     {
267       assert (__time_len >= TIME_LEN);
268       fstrcpy (__time, TIME_LEN, timec, TIME_LEN);
269     }
270
271   if (__date)
272     {
273       assert (__date_len >= DATE_LEN);
274       fstrcpy (__date, DATE_LEN, date, DATE_LEN);
275     }
276 #undef DATE_LEN
277 #undef TIME_LEN   
278 #undef ZONE_LEN
279 #undef VALUES_SIZE
280 }