OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uC-libc/] [time/] [mktime.c] - Blame information for rev 1778

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
 
2
/* This is adapted from glibc */
3
/* Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc. */
4
 
5
 
6
/* Assume that leap seconds are possible, unless told otherwise.
7
   If the host has a `zic' command with a -L leapsecondfilename' option,
8
   then it supports leap seconds; otherwise it probably doesn't.  */
9
#ifndef LEAP_SECONDS_POSSIBLE
10
#define LEAP_SECONDS_POSSIBLE 1
11
#endif
12
 
13
#include <sys/types.h>          /* Some systems define `time_t' here.  */
14
#include <time.h>
15
 
16
#if __STDC__ || __GNU_LIBRARY__ || STDC_HEADERS
17
#include <limits.h>
18
#endif
19
 
20
#if DEBUG
21
#include <stdio.h>
22
#if __STDC__ || __GNU_LIBRARY__ || STDC_HEADERS
23
#include <stdlib.h>
24
#endif
25
/* Make it work even if the system's libc has its own mktime routine.  */
26
#define mktime my_mktime
27
#endif /* DEBUG */
28
 
29
#ifndef __P
30
#if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
31
#define __P(args) args
32
#else
33
#define __P(args) ()
34
#endif  /* GCC.  */
35
#endif  /* Not __P.  */
36
 
37
#ifndef CHAR_BIT
38
#define CHAR_BIT 8
39
#endif
40
 
41
#ifndef INT_MIN
42
#define INT_MIN (~0 << (sizeof (int) * CHAR_BIT - 1))
43
#endif
44
#ifndef INT_MAX
45
#define INT_MAX (~0 - INT_MIN)
46
#endif
47
 
48
#ifndef TIME_T_MIN
49
#define TIME_T_MIN (0 < (time_t) -1 ? (time_t) 0 \
50
                    : ~ (time_t) 0 << (sizeof (time_t) * CHAR_BIT - 1))
51
#endif
52
#ifndef TIME_T_MAX
53
#define TIME_T_MAX (~ (time_t) 0 - TIME_T_MIN)
54
#endif
55
 
56
#define TM_YEAR_BASE 1900
57
#define EPOCH_YEAR 1970
58
 
59
#ifndef __isleap
60
/* Nonzero if YEAR is a leap year (every 4 years,
61
   except every 100th isn't, and every 400th is).  */
62
#define __isleap(year)  \
63
  ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
64
#endif
65
 
66
/* How many days come before each month (0-12).  */
67
const unsigned short int __mon_yday[2][13] =
68
  {
69
    /* Normal years.  */
70
    { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
71
    /* Leap years.  */
72
    { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
73
  };
74
 
75
static time_t ydhms_tm_diff __P ((int, int, int, int, int, const struct tm *));
76
time_t __mktime_internal __P ((struct tm *,
77
                               struct tm *(*) (const time_t *, struct tm *),
78
                               time_t *));
79
 
80
/* Yield the difference between (YEAR-YDAY HOUR:MIN:SEC) and (*TP),
81
   measured in seconds, ignoring leap seconds.
82
   YEAR uses the same numbering as TM->tm_year.
83
   All values are in range, except possibly YEAR.
84
   If overflow occurs, yield the low order bits of the correct answer.  */
85
static time_t
86
ydhms_tm_diff (year, yday, hour, min, sec, tp)
87
     int year, yday, hour, min, sec;
88
     const struct tm *tp;
89
{
90
  /* Compute intervening leap days correctly even if year is negative.
91
     Take care to avoid int overflow.  time_t overflow is OK, since
92
     only the low order bits of the correct time_t answer are needed.
93
     Don't convert to time_t until after all divisions are done, since
94
     time_t might be unsigned.  */
95
  int a4 = (year >> 2) + (TM_YEAR_BASE >> 2) - ! (year & 3);
96
  int b4 = (tp->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (tp->tm_year & 3);
97
  int a100 = a4 / 25 - (a4 % 25 < 0);
98
  int b100 = b4 / 25 - (b4 % 25 < 0);
99
  int a400 = a100 >> 2;
100
  int b400 = b100 >> 2;
101
  int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
102
  time_t years = year - (time_t) tp->tm_year;
103
  time_t days = (365 * years + intervening_leap_days
104
                 + (yday - tp->tm_yday));
105
  return (60 * (60 * (24 * days + (hour - tp->tm_hour))
106
                + (min - tp->tm_min))
107
          + (sec - tp->tm_sec));
108
}
109
 
110
 
111
static time_t localtime_offset;
112
 
113
 
114
/* Convert *TP to a time_t value.  */
115
time_t
116
mktime (tp)
117
     struct tm *tp;
118
{
119
#ifdef _LIBC
120
  /* POSIX.1 8.1.1 requires that whenever mktime() is called, the
121
     time zone names contained in the external variable `tzname' shall
122
     be set as if the tzset() function had been called.  */
123
  __tzset ();
124
#endif
125
 
126
  return __mktime_internal (tp, localtime_r, &localtime_offset);
127
}
128
 
129
/* Convert *TP to a time_t value, inverting
130
   the monotonic and mostly-unit-linear conversion function CONVERT.
131
   Use *OFFSET to keep track of a guess at the offset of the result,
132
   compared to what the result would be for UTC without leap seconds.
133
   If *OFFSET's guess is correct, only one CONVERT call is needed.  */
134
time_t
135
__mktime_internal (tp, convert, offset)
136
     struct tm *tp;
137
     struct tm *(*convert) __P ((const time_t *, struct tm *));
138
     time_t *offset;
139
{
140
  time_t t, dt, t0;
141
  struct tm tm;
142
 
143
  /* The maximum number of probes (calls to CONVERT) should be enough
144
     to handle any combinations of time zone rule changes, solar time,
145
     and leap seconds.  Posix.1 prohibits leap seconds, but some hosts
146
     have them anyway.  */
147
  int remaining_probes = 4;
148
 
149
  /* Time requested.  Copy it in case CONVERT modifies *TP; this can
150
     occur if TP is localtime's returned value and CONVERT is localtime.  */
151
  int sec = tp->tm_sec;
152
  int min = tp->tm_min;
153
  int hour = tp->tm_hour;
154
  int mday = tp->tm_mday;
155
  int mon = tp->tm_mon;
156
  int year_requested = tp->tm_year;
157
  int isdst = tp->tm_isdst;
158
 
159
  /* Ensure that mon is in range, and set year accordingly.  */
160
  int mon_remainder = mon % 12;
161
  int negative_mon_remainder = mon_remainder < 0;
162
  int mon_years = mon / 12 - negative_mon_remainder;
163
  int year = year_requested + mon_years;
164
 
165
  /* The other values need not be in range:
166
     the remaining code handles minor overflows correctly,
167
     assuming int and time_t arithmetic wraps around.
168
     Major overflows are caught at the end.  */
169
 
170
  /* Calculate day of year from year, month, and day of month.
171
     The result need not be in range.  */
172
  int yday = ((__mon_yday[__isleap (year + TM_YEAR_BASE)]
173
               [mon_remainder + 12 * negative_mon_remainder])
174
              + mday - 1);
175
 
176
#if LEAP_SECONDS_POSSIBLE
177
  /* Handle out-of-range seconds specially,
178
     since ydhms_tm_diff assumes every minute has 60 seconds.  */
179
  int sec_requested = sec;
180
  if (sec < 0)
181
    sec = 0;
182
  if (59 < sec)
183
    sec = 59;
184
#endif
185
 
186
  /* Invert CONVERT by probing.  First assume the same offset as last time.
187
     Then repeatedly use the error to improve the guess.  */
188
 
189
  tm.tm_year = EPOCH_YEAR - TM_YEAR_BASE;
190
  tm.tm_yday = tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
191
  t0 = ydhms_tm_diff (year, yday, hour, min, sec, &tm);
192
 
193
  for (t = t0 + *offset;
194
       (dt = ydhms_tm_diff (year, yday, hour, min, sec, (*convert) (&t, &tm)));
195
       t += dt)
196
    if (--remaining_probes == 0)
197
      return -1;
198
 
199
  /* Check whether tm.tm_isdst has the requested value, if any.  */
200
  if (0 <= isdst && 0 <= tm.tm_isdst)
201
    {
202
      int dst_diff = (isdst != 0) - (tm.tm_isdst != 0);
203
      if (dst_diff)
204
        {
205
          /* Move two hours in the direction indicated by the disagreement,
206
             probe some more, and switch to a new time if found.
207
             The largest known fallback due to daylight savings is two hours:
208
             once, in Newfoundland, 1988-10-30 02:00 -> 00:00.  */
209
          time_t ot = t - 2 * 60 * 60 * dst_diff;
210
          while (--remaining_probes != 0)
211
            {
212
              struct tm otm;
213
              if (! (dt = ydhms_tm_diff (year, yday, hour, min, sec,
214
                                         (*convert) (&ot, &otm))))
215
                {
216
                  t = ot;
217
                  tm = otm;
218
                  break;
219
                }
220
              if ((ot += dt) == t)
221
                break;  /* Avoid a redundant probe.  */
222
            }
223
        }
224
    }
225
 
226
  *offset = t - t0;
227
 
228
#if LEAP_SECONDS_POSSIBLE
229
  if (sec_requested != tm.tm_sec)
230
    {
231
      /* Adjust time to reflect the tm_sec requested, not the normalized value.
232
         Also, repair any damage from a false match due to a leap second.  */
233
      t += sec_requested - sec + (sec == 0 && tm.tm_sec == 60);
234
      (*convert) (&t, &tm);
235
    }
236
#endif
237
 
238
#if 0
239
  if (TIME_T_MAX / INT_MAX / 366 / 24 / 60 / 60 < 3)
240
    {
241
      /* time_t isn't large enough to rule out overflows in ydhms_tm_diff,
242
         so check for major overflows.  A gross check suffices,
243
         since if t has overflowed, it is off by a multiple of
244
         TIME_T_MAX - TIME_T_MIN + 1.  So ignore any component of
245
         the difference that is bounded by a small value.  */
246
 
247
      double dyear = (double) year_requested + mon_years - tm.tm_year;
248
      double dday = 366 * dyear + mday;
249
      double dsec = 60 * (60 * (24 * dday + hour) + min) + sec_requested;
250
 
251
      if (TIME_T_MAX / 3 - TIME_T_MIN / 3 < (dsec < 0 ? - dsec : dsec))
252
        return -1;
253
    }
254
#endif
255
 
256
  *tp = tm;
257
  return t;
258
}
259
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.