Subversion Repositories Kolibri OS

Rev

Rev 4874 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
4349 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
 
110
  if (tim_p->tm_mon < 0 || tim_p->tm_mon > 11)
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;
162
  int year, isdst=0;
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
 
181
  if (tim_p->tm_year > 10000 || tim_p->tm_year < -10000)
182
      return (time_t) -1;
183
 
184
  /* compute days in other years */
185
  if ((year = tim_p->tm_year) > 70)
186
    {
187
      for (year = 70; year < tim_p->tm_year; year++)
188
	days += _DAYS_IN_YEAR (year);
189
    }
190
  else if (year < 70)
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
 
200
  TZ_LOCK;
201
 
6099 serge 202
  _tzset_unlocked ();
203
 
4349 Serge 204
  if (_daylight)
205
    {
206
      int tm_isdst;
207
      int y = tim_p->tm_year + YEAR_BASE;
6099 serge 208
      /* Convert user positive into 1 */
209
      tm_isdst = tim_p->tm_isdst > 0  ?  1 : tim_p->tm_isdst;
210
      isdst = tm_isdst;
4349 Serge 211
 
212
      if (y == tz->__tzyear || __tzcalc_limits (y))
213
	{
214
	  /* calculate start of dst in dst local time and
215
	     start of std in both std local time and dst local time */
216
          time_t startdst_dst = tz->__tzrule[0].change
217
	    - (time_t) tz->__tzrule[1].offset;
218
	  time_t startstd_dst = tz->__tzrule[1].change
219
	    - (time_t) tz->__tzrule[1].offset;
220
	  time_t startstd_std = tz->__tzrule[1].change
221
	    - (time_t) tz->__tzrule[0].offset;
222
	  /* if the time is in the overlap between dst and std local times */
223
	  if (tim >= startstd_std && tim < startstd_dst)
224
	    ; /* we let user decide or leave as -1 */
225
          else
226
	    {
227
	      isdst = (tz->__tznorth
228
		       ? (tim >= startdst_dst && tim < startstd_std)
229
		       : (tim >= startdst_dst || tim < startstd_std));
230
 	      /* if user committed and was wrong, perform correction, but not
231
 	       * if the user has given a negative value (which
232
 	       * asks mktime() to determine if DST is in effect or not) */
233
 	      if (tm_isdst >= 0  &&  (isdst ^ tm_isdst) == 1)
234
		{
235
		  /* we either subtract or add the difference between
236
		     time zone offsets, depending on which way the user got it
237
		     wrong. The diff is typically one hour, or 3600 seconds,
238
		     and should fit in a 16-bit int, even though offset
239
		     is a long to accomodate 12 hours. */
240
		  int diff = (int) (tz->__tzrule[0].offset
241
				    - tz->__tzrule[1].offset);
242
		  if (!isdst)
243
		    diff = -diff;
244
		  tim_p->tm_sec += diff;
245
		  tim += diff;  /* we also need to correct our current time calculation */
246
		  int mday = tim_p->tm_mday;
247
		  validate_structure (tim_p);
248
		  mday = tim_p->tm_mday - mday;
249
		  /* roll over occurred */
250
		  if (mday) {
251
		    /* compensate for month roll overs */
252
		    if (mday > 1)
253
			  mday = -1;
254
		    else if (mday < -1)
255
			  mday = 1;
256
		    /* update days for wday calculation */
257
		    days += mday;
258
		    /* handle yday */
259
		    if ((tim_p->tm_yday += mday) < 0) {
260
			  --year;
261
			  tim_p->tm_yday = _DAYS_IN_YEAR(year) - 1;
262
		    } else {
263
			  mday = _DAYS_IN_YEAR(year);
264
			  if (tim_p->tm_yday > (mday - 1))
265
				tim_p->tm_yday -= mday;
266
		    }
267
		  }
268
		}
269
	    }
270
	}
271
    }
272
 
273
  /* add appropriate offset to put time in gmt format */
274
  if (isdst == 1)
275
    tim += (time_t) tz->__tzrule[1].offset;
276
  else /* otherwise assume std time */
277
    tim += (time_t) tz->__tzrule[0].offset;
278
 
279
  TZ_UNLOCK;
280
 
281
  /* reset isdst flag to what we have calculated */
282
  tim_p->tm_isdst = isdst;
283
 
284
  /* compute day of the week */
285
  if ((tim_p->tm_wday = (days + 4) % 7) < 0)
286
    tim_p->tm_wday += 7;
287
 
288
  return tim;
289
}