Subversion Repositories Kolibri OS

Rev

Rev 1906 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1906 serge 1
/*
2
 * mktime.c
3
 * Original Author:	G. Haley
4
 *
5
 * Converts the broken-down time, expressed as local time, in the structure
6
 * pointed to by tim_p into a calendar time value. The original values of the
7
 * tm_wday and tm_yday fields of the structure are ignored, and the original
8
 * values of the other fields have no restrictions. On successful completion
9
 * the fields of the structure are set to represent the specified calendar
10
 * time. Returns the specified calendar time. If the calendar time can not be
11
 * represented, returns the value (time_t) -1.
12
 *
13
 * Modifications:	Fixed tm_isdst usage - 27 August 2008 Craig Howland.
14
 */
15
 
16
/*
17
FUNCTION
18
<>---convert time to arithmetic representation
19
 
20
INDEX
21
	mktime
22
 
23
ANSI_SYNOPSIS
24
	#include 
25
	time_t mktime(struct tm *<[timp]>);
26
 
27
TRAD_SYNOPSIS
28
	#include 
29
	time_t mktime(<[timp]>)
30
	struct tm *<[timp]>;
31
 
32
DESCRIPTION
33
<> assumes the time at <[timp]> is a local time, and converts
34
its representation from the traditional representation defined by
35
<> into a representation suitable for arithmetic.
36
 
37
<> is the inverse of <>.
38
 
39
RETURNS
40
If the contents of the structure at <[timp]> do not form a valid
41
calendar time representation, the result is <<-1>>.  Otherwise, the
42
result is the time, converted to a <> value.
43
 
44
PORTABILITY
45
ANSI C requires <>.
46
 
47
<> requires no supporting OS subroutines.
48
*/
49
 
50
#include 
51
#include 
52
#include "local.h"
53
 
54
#define _SEC_IN_MINUTE 60L
55
#define _SEC_IN_HOUR 3600L
56
#define _SEC_IN_DAY 86400L
57
 
58
static _CONST int DAYS_IN_MONTH[12] =
59
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
60
 
61
#define _DAYS_IN_MONTH(x) ((x == 1) ? days_in_feb : DAYS_IN_MONTH[x])
62
 
63
static _CONST int _DAYS_BEFORE_MONTH[12] =
64
{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
65
 
66
#define _ISLEAP(y) (((y) % 4) == 0 && (((y) % 100) != 0 || (((y)+1900) % 400) == 0))
67
#define _DAYS_IN_YEAR(year) (_ISLEAP(year) ? 366 : 365)
68
 
69
static void
70
_DEFUN(validate_structure, (tim_p),
71
     struct tm *tim_p)
72
{
73
  div_t res;
74
  int days_in_feb = 28;
75
 
76
  /* calculate time & date to account for out of range values */
77
  if (tim_p->tm_sec < 0 || tim_p->tm_sec > 59)
78
    {
79
      res = div (tim_p->tm_sec, 60);
80
      tim_p->tm_min += res.quot;
81
      if ((tim_p->tm_sec = res.rem) < 0)
82
	{
83
	  tim_p->tm_sec += 60;
84
	  --tim_p->tm_min;
85
	}
86
    }
87
 
88
  if (tim_p->tm_min < 0 || tim_p->tm_min > 59)
89
    {
90
      res = div (tim_p->tm_min, 60);
91
      tim_p->tm_hour += res.quot;
92
      if ((tim_p->tm_min = res.rem) < 0)
93
	{
94
	  tim_p->tm_min += 60;
95
	  --tim_p->tm_hour;
96
        }
97
    }
98
 
99
  if (tim_p->tm_hour < 0 || tim_p->tm_hour > 23)
100
    {
101
      res = div (tim_p->tm_hour, 24);
102
      tim_p->tm_mday += res.quot;
103
      if ((tim_p->tm_hour = res.rem) < 0)
104
	{
105
	  tim_p->tm_hour += 24;
106
	  --tim_p->tm_mday;
107
        }
108
    }
109
 
3065 serge 110
  if (tim_p->tm_mon < 0 || tim_p->tm_mon > 11)
1906 serge 111
    {
112
      res = div (tim_p->tm_mon, 12);
113
      tim_p->tm_year += res.quot;
114
      if ((tim_p->tm_mon = res.rem) < 0)
115
        {
116
	  tim_p->tm_mon += 12;
117
	  --tim_p->tm_year;
118
        }
119
    }
120
 
121
  if (_DAYS_IN_YEAR (tim_p->tm_year) == 366)
122
    days_in_feb = 29;
123
 
124
  if (tim_p->tm_mday <= 0)
125
    {
126
      while (tim_p->tm_mday <= 0)
127
	{
128
	  if (--tim_p->tm_mon == -1)
129
	    {
130
	      tim_p->tm_year--;
131
	      tim_p->tm_mon = 11;
132
	      days_in_feb =
133
		((_DAYS_IN_YEAR (tim_p->tm_year) == 366) ?
134
		 29 : 28);
135
	    }
136
	  tim_p->tm_mday += _DAYS_IN_MONTH (tim_p->tm_mon);
137
	}
138
    }
139
  else
140
    {
141
      while (tim_p->tm_mday > _DAYS_IN_MONTH (tim_p->tm_mon))
142
	{
143
	  tim_p->tm_mday -= _DAYS_IN_MONTH (tim_p->tm_mon);
144
	  if (++tim_p->tm_mon == 12)
145
	    {
146
	      tim_p->tm_year++;
147
	      tim_p->tm_mon = 0;
148
	      days_in_feb =
149
		((_DAYS_IN_YEAR (tim_p->tm_year) == 366) ?
150
		 29 : 28);
151
	    }
152
	}
153
    }
154
}
155
 
156
time_t
157
_DEFUN(mktime, (tim_p),
158
     struct tm *tim_p)
159
{
160
  time_t tim = 0;
161
  long days = 0;
3065 serge 162
  int year, isdst=0;
1906 serge 163
  __tzinfo_type *tz = __gettzinfo ();
164
 
165
  /* validate structure */
166
  validate_structure (tim_p);
167
 
168
  /* compute hours, minutes, seconds */
169
  tim += tim_p->tm_sec + (tim_p->tm_min * _SEC_IN_MINUTE) +
170
    (tim_p->tm_hour * _SEC_IN_HOUR);
171
 
172
  /* compute days in year */
173
  days += tim_p->tm_mday - 1;
174
  days += _DAYS_BEFORE_MONTH[tim_p->tm_mon];
175
  if (tim_p->tm_mon > 1 && _DAYS_IN_YEAR (tim_p->tm_year) == 366)
176
    days++;
177
 
178
  /* compute day of the year */
179
  tim_p->tm_yday = days;
180
 
3065 serge 181
  if (tim_p->tm_year > 10000 || tim_p->tm_year < -10000)
1906 serge 182
      return (time_t) -1;
183
 
184
  /* compute days in other years */
3065 serge 185
  if ((year = tim_p->tm_year) > 70)
1906 serge 186
    {
187
      for (year = 70; year < tim_p->tm_year; year++)
188
	days += _DAYS_IN_YEAR (year);
189
    }
3065 serge 190
  else if (year < 70)
1906 serge 191
    {
192
      for (year = 69; year > tim_p->tm_year; year--)
193
	days -= _DAYS_IN_YEAR (year);
194
      days -= _DAYS_IN_YEAR (year);
195
    }
196
 
197
  /* compute total seconds */
198
  tim += (days * _SEC_IN_DAY);
199
 
3065 serge 200
  TZ_LOCK;
201
 
202
  if (_daylight)
203
    {
204
      int tm_isdst;
205
      int y = tim_p->tm_year + YEAR_BASE;
1906 serge 206
  /* Convert user positive into 1 */
207
  tm_isdst = tim_p->tm_isdst > 0  ?  1 : tim_p->tm_isdst;
208
  isdst = tm_isdst;
209
 
210
      if (y == tz->__tzyear || __tzcalc_limits (y))
211
	{
212
	  /* calculate start of dst in dst local time and
213
	     start of std in both std local time and dst local time */
214
          time_t startdst_dst = tz->__tzrule[0].change
215
	    - (time_t) tz->__tzrule[1].offset;
216
	  time_t startstd_dst = tz->__tzrule[1].change
217
	    - (time_t) tz->__tzrule[1].offset;
218
	  time_t startstd_std = tz->__tzrule[1].change
219
	    - (time_t) tz->__tzrule[0].offset;
220
	  /* if the time is in the overlap between dst and std local times */
221
	  if (tim >= startstd_std && tim < startstd_dst)
222
	    ; /* we let user decide or leave as -1 */
223
          else
224
	    {
225
	      isdst = (tz->__tznorth
226
		       ? (tim >= startdst_dst && tim < startstd_std)
227
		       : (tim >= startdst_dst || tim < startstd_std));
228
 	      /* if user committed and was wrong, perform correction, but not
229
 	       * if the user has given a negative value (which
230
 	       * asks mktime() to determine if DST is in effect or not) */
231
 	      if (tm_isdst >= 0  &&  (isdst ^ tm_isdst) == 1)
232
		{
233
		  /* we either subtract or add the difference between
234
		     time zone offsets, depending on which way the user got it
235
		     wrong. The diff is typically one hour, or 3600 seconds,
236
		     and should fit in a 16-bit int, even though offset
237
		     is a long to accomodate 12 hours. */
238
		  int diff = (int) (tz->__tzrule[0].offset
239
				    - tz->__tzrule[1].offset);
240
		  if (!isdst)
241
		    diff = -diff;
242
		  tim_p->tm_sec += diff;
3065 serge 243
		  tim += diff;  /* we also need to correct our current time calculation */
244
		  int mday = tim_p->tm_mday;
1906 serge 245
		  validate_structure (tim_p);
3065 serge 246
		  mday = tim_p->tm_mday - mday;
247
		  /* roll over occurred */
248
		  if (mday) {
249
		    /* compensate for month roll overs */
250
		    if (mday > 1)
251
			  mday = -1;
252
		    else if (mday < -1)
253
			  mday = 1;
254
		    /* update days for wday calculation */
255
		    days += mday;
256
		    /* handle yday */
257
		    if ((tim_p->tm_yday += mday) < 0) {
258
			  --year;
259
			  tim_p->tm_yday = _DAYS_IN_YEAR(year) - 1;
260
		    } else {
261
			  mday = _DAYS_IN_YEAR(year);
262
			  if (tim_p->tm_yday > (mday - 1))
263
				tim_p->tm_yday -= mday;
264
		    }
265
		  }
1906 serge 266
		}
267
	    }
268
	}
269
    }
270
 
271
  /* add appropriate offset to put time in gmt format */
272
  if (isdst == 1)
273
    tim += (time_t) tz->__tzrule[1].offset;
274
  else /* otherwise assume std time */
275
    tim += (time_t) tz->__tzrule[0].offset;
276
 
3065 serge 277
  TZ_UNLOCK;
278
 
1906 serge 279
  /* reset isdst flag to what we have calculated */
280
  tim_p->tm_isdst = isdst;
281
 
3065 serge 282
  /* compute day of the week */
283
  if ((tim_p->tm_wday = (days + 4) % 7) < 0)
284
    tim_p->tm_wday += 7;
285
 
1906 serge 286
  return tim;
287
}