Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | 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
 
110
  if (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, tm_isdst;
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
182
      || tim_p->tm_year < -10000)
183
    {
184
      return (time_t) -1;
185
    }
186
 
187
  /* compute days in other years */
188
  if (tim_p->tm_year > 70)
189
    {
190
      for (year = 70; year < tim_p->tm_year; year++)
191
	days += _DAYS_IN_YEAR (year);
192
    }
193
  else if (tim_p->tm_year < 70)
194
    {
195
      for (year = 69; year > tim_p->tm_year; year--)
196
	days -= _DAYS_IN_YEAR (year);
197
      days -= _DAYS_IN_YEAR (year);
198
    }
199
 
200
  /* compute day of the week */
201
  if ((tim_p->tm_wday = (days + 4) % 7) < 0)
202
    tim_p->tm_wday += 7;
203
 
204
  /* compute total seconds */
205
  tim += (days * _SEC_IN_DAY);
206
 
207
  /* Convert user positive into 1 */
208
  tm_isdst = tim_p->tm_isdst > 0  ?  1 : tim_p->tm_isdst;
209
  isdst = tm_isdst;
210
 
211
  if (_daylight)
212
    {
213
      int y = tim_p->tm_year + YEAR_BASE;
214
      if (y == tz->__tzyear || __tzcalc_limits (y))
215
	{
216
	  /* calculate start of dst in dst local time and
217
	     start of std in both std local time and dst local time */
218
          time_t startdst_dst = tz->__tzrule[0].change
219
	    - (time_t) tz->__tzrule[1].offset;
220
	  time_t startstd_dst = tz->__tzrule[1].change
221
	    - (time_t) tz->__tzrule[1].offset;
222
	  time_t startstd_std = tz->__tzrule[1].change
223
	    - (time_t) tz->__tzrule[0].offset;
224
	  /* if the time is in the overlap between dst and std local times */
225
	  if (tim >= startstd_std && tim < startstd_dst)
226
	    ; /* we let user decide or leave as -1 */
227
          else
228
	    {
229
	      isdst = (tz->__tznorth
230
		       ? (tim >= startdst_dst && tim < startstd_std)
231
		       : (tim >= startdst_dst || tim < startstd_std));
232
 	      /* if user committed and was wrong, perform correction, but not
233
 	       * if the user has given a negative value (which
234
 	       * asks mktime() to determine if DST is in effect or not) */
235
 	      if (tm_isdst >= 0  &&  (isdst ^ tm_isdst) == 1)
236
		{
237
		  /* we either subtract or add the difference between
238
		     time zone offsets, depending on which way the user got it
239
		     wrong. The diff is typically one hour, or 3600 seconds,
240
		     and should fit in a 16-bit int, even though offset
241
		     is a long to accomodate 12 hours. */
242
		  int diff = (int) (tz->__tzrule[0].offset
243
				    - tz->__tzrule[1].offset);
244
		  if (!isdst)
245
		    diff = -diff;
246
		  tim_p->tm_sec += diff;
247
		  validate_structure (tim_p);
248
		  tim += diff;  /* we also need to correct our current time calculation */
249
		}
250
	    }
251
	}
252
    }
253
 
254
  /* add appropriate offset to put time in gmt format */
255
  if (isdst == 1)
256
    tim += (time_t) tz->__tzrule[1].offset;
257
  else /* otherwise assume std time */
258
    tim += (time_t) tz->__tzrule[0].offset;
259
 
260
  /* reset isdst flag to what we have calculated */
261
  tim_p->tm_isdst = isdst;
262
 
263
  return tim;
264
}