1 #define INSIDE_GIGABASE
2
3 #include <winbase.h>
4 #include "wince_time.h"
5
6 /* non-zero if daylight savings time is used */
7 _CRTIMP int _daylight;
8
9 /* offset for Daylight Saving Time */
10 _CRTIMP long _dstbias;
11
12 /* difference in seconds between GMT and local time */
13 _CRTIMP long _timezone;
14
15 /* standard/daylight savings time zone names */
16 _CRTIMP char * _tzname[2];
17
18
19 struct __lc_time_data {
20 char *wday_abbr[7];
21 char *wday[7];
22 char *month_abbr[12];
23 char *month[12];
24 char *ampm[2];
25 char *ww_sdatefmt;
26 char *ww_ldatefmt;
27 char *ww_timefmt;
28 };
29
30
31 static int _lpdays[] = {
32 -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
33 };
34
35 static int _days[] = {
36 -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364
37 };
38
39 /*
40 * Flag indicating that time zone information came from GetTimeZoneInformation
41 * API call.
42 */
43 static int tzapiused;
44
45 static TIME_ZONE_INFORMATION tzinfo;
46
47 /* Prototypes for local routines */
48 static void __cdecl _expandtime (char specifier, const struct tm *tmptr,
49 char **out, size_t *count, struct __lc_time_data *lc_time);
50 static void __cdecl _store_str (char *in, char **out, size_t *count);
51 static void __cdecl _store_num (int num, int digits, char **out, size_t *count);
52 static void __cdecl _store_number (int num, char **out, size_t *count);
53 static void __cdecl _store_winword (const char *format, const struct tm *tmptr, char **out, size_t *count, struct __lc_time_data *lc_time);
54
55 time_t __cdecl __loctotime_t (
56 int yr, /* 0 based */
57 int mo, /* 1 based */
58 int dy, /* 1 based */
59 int hr,
60 int mn,
61 int sc,
62 int dstflag );
63 int __cdecl _isindst(struct tm *);
64 void __cdecl __tzset(void);
65
66 /*
67 * DST start and end structs.
68 */
69 static transitiondate dststart = { -1, 0, 0L };
70 static transitiondate dstend = { -1, 0, 0L };
71
72 /*
73 * Code page.
74 */
75 UINT __lc_codepage = _CLOCALECP; /* CP_ACP */
76
77
78 /*
79 time_t __cdecl time(time_t *pTime)
80 {
81 // what a mess for getting a simple time!
82 SYSTEMTIME lTime;
83 FILETIME lFileTime;
84
85 ::GetLocalTime(&lTime);
86 SystemTimeToFileTime(&lTime, &lFileTime);
87 ULARGE_INTEGER lNTime = *(ULARGE_INTEGER*)&lFileTime;
88 if (0l != pTime)
89 *pTime = *(time_t*)&lNTime;
90 return *(time_t*)&lNTime;
91 }
92 */
93
94 /* LC_TIME data for local "C" */
95
96 __declspec(selectany) struct __lc_time_data __lc_time_c = {
97
98 {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"},
99
100 {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
101 "Friday", "Saturday", },
102
103 {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
104 "Sep", "Oct", "Nov", "Dec"},
105
106 {"January", "February", "March", "April", "May", "June",
107 "July", "August", "September", "October",
108 "November", "December"},
109
110 {"AM", "PM"}
111
112 , { "M/d/yy" }
113 , { "dddd, MMMM dd, yyyy" }
114 , { "H:mm:ss" }
115 };
116
117 /* Pointer to the current LC_TIME data structure. */
118
119 struct __lc_time_data *__lc_time_curr = &__lc_time_c;
120
121
122 /* Flags */
123 static unsigned __alternate_form;
124 static unsigned __no_lead_zeros;
125
126
mktime(struct tm * lTms)127 time_t __cdecl mktime(struct tm * lTms)
128 {
129 SYSTEMTIME lSTime;
130 lSTime.wYear = lTms->tm_year + 1900;
131 lSTime.wMonth = lTms->tm_mon + 1;
132 lSTime.wDay = lTms->tm_mday;
133 lSTime.wDayOfWeek = lTms->tm_wday;
134 lSTime.wHour = lTms->tm_hour;
135 lSTime.wMinute = lTms->tm_min;
136 lSTime.wSecond = lTms->tm_sec;
137 lSTime.wMilliseconds = 0;
138
139 FILETIME lFileTime;
140
141 SystemTimeToFileTime(&lSTime, &lFileTime);
142 ULARGE_INTEGER lNTime = *(ULARGE_INTEGER*)&lFileTime;
143
144 //TODO: update the values of wDay and yDay in the
145 // original structure.
146 return *(time_t*)&lNTime;
147 }
148
149 /*
150 struct tm * __cdecl localtime(const time_t* pTime)
151 {
152 FILETIME lFileTime = *(FILETIME *)&pTime;
153 FILETIME lLocalFileTime;
154
155 ::FileTimeToLocalFileTime(&lFileTime, &lLocalFileTime);
156
157 SYSTEMTIME lSTime;
158 if (::FileTimeToSystemTime(&lLocalFimeTime, &lSTime) != 0)
159 {
160 struct tm* lTms = new struct tm;
161
162 lTms->tm_year = lSTime.wYear - 1900;
163 lTms->tm_mon = lSTime.wMonth - 1;
164 lTms->tm_mday = lSTime.wDay;
165 lTms->tm_wday = lSTime.wDayOfWeek;
166 lTms->tm_hour = lSTime.wHour;
167 lTms->tm_min = lSTime.wMinute;
168 lTms->tm_sec = lSTime.wSecond;
169
170 return lTms;
171 }
172 return 0l;
173 }
174
175 size_t __cdecl wcsftime(wchar_t *pDest, size_t maxsize, const wchar_t *pFormat,
176 const struct tm *pTime)
177 {
178
179 }
180 */
181
182 /***
183 *size_t _Strftime(string, maxsize, format,
184 * timeptr, lc_time) - Format a time string for a given locale
185 *
186 *Purpose:
187 * Place characters into the user's output buffer expanding time
188 * format directives as described in the user's control string.
189 * Use the supplied 'tm' structure for time data when expanding
190 * the format directives. use the locale information at lc_time.
191 * [ANSI]
192 *
193 *Entry:
194 * char *string = pointer to output string
195 * size_t maxsize = max length of string
196 * const char *format = format control string
197 * const struct tm *timeptr = pointer to tb data structure
198 * struct __lc_time_data *lc_time = pointer to locale-specific info
199 * (passed as void * to avoid type mismatch with C++)
200 *
201 *Exit:
202 * !0 = If the total number of resulting characters including the
203 * terminating null is not more than 'maxsize', then return the
204 * number of chars placed in the 'string' array (not including the
205 * null terminator).
206 *
207 * 0 = Otherwise, return 0 and the contents of the string are
208 * indeterminate.
209 *
210 *Exceptions:
211 *
212 *******************************************************************************/
213
_Strftime(char * string,size_t maxsize,const char * format,const struct tm * timeptr,void * lc_time_arg)214 size_t __cdecl _Strftime (
215 char *string,
216 size_t maxsize,
217 const char *format,
218 const struct tm *timeptr,
219 void *lc_time_arg
220 )
221 {
222 struct __lc_time_data *lc_time;
223
224 size_t left; /* space left in output string */
225
226 /* Copy maxsize into temp. */
227 left = maxsize;
228
229 /* Defer initialization until the crtitical section has been entered */
230 lc_time = lc_time_arg == 0 ? __lc_time_curr : (struct __lc_time_data *)lc_time_arg;
231
232 /* Copy the input string to the output string expanding the format
233 designations appropriately. Stop copying when one of the following
234 is true: (1) we hit a null char in the input stream, or (2) there's
235 no room left in the output stream. */
236
237 while (left > 0)
238 {
239 switch(*format)
240 {
241
242 case('\0'):
243
244 /* end of format input string */
245 goto done;
246
247 case('%'):
248
249 /* Format directive. Take appropriate action based
250 on format control character. */
251
252 format++; /* skip over % char */
253
254 /* process flags */
255 __alternate_form = 0;
256 if (*format == '#')
257 {
258 __alternate_form = 1;
259 format++;
260 }
261 _expandtime(*format, timeptr, &string, &left,
262 lc_time);
263 format++; /* skip format char */
264 break;
265
266
267 default:
268
269 /* store character, bump pointers, dec the char count */
270 if (isleadbyte((int)(*format)) && left > 1)
271 {
272 *string++ = *format++;
273 left--;
274 }
275 *string++ = *format++;
276 left--;
277 break;
278 }
279 }
280
281
282 /* All done. See if we terminated because we hit a null char or because
283 we ran out of space */
284
285 done:
286
287 if (left > 0) {
288
289 /* Store a terminating null char and return the number of chars
290 we stored in the output string. */
291
292 *string = '\0';
293 return(maxsize-left);
294 }
295
296 else
297 return(0);
298
299 }
300
301
302 /***
303 *_expandtime() - Expand the conversion specifier
304 *
305 *Purpose:
306 * Expand the given strftime conversion specifier using the time struct
307 * and store it in the supplied buffer.
308 *
309 * The expansion is locale-dependent.
310 *
311 * *** For internal use with strftime() only ***
312 *
313 *Entry:
314 * char specifier = strftime conversion specifier to expand
315 * const struct tm *tmptr = pointer to time/date structure
316 * char **string = address of pointer to output string
317 * size_t *count = address of char count (space in output area)
318 * struct __lc_time_data *lc_time = pointer to locale-specific info
319 *
320 *Exit:
321 * none
322 *
323 *Exceptions:
324 *
325 *******************************************************************************/
326
_expandtime(char specifier,const struct tm * timeptr,char ** string,size_t * left,struct __lc_time_data * lc_time)327 static void __cdecl _expandtime (
328 char specifier,
329 const struct tm *timeptr,
330 char **string,
331 size_t *left,
332 struct __lc_time_data *lc_time
333 )
334 {
335 unsigned temp; /* temps */
336 int wdaytemp;
337
338 /* Use a copy of the appropriate __lc_time_data pointer. This
339 should prevent the necessity of locking/unlocking in mthread
340 code (if we can guarantee that the various __lc_time data
341 structures are always in the same segment). contents of time
342 strings structure can now change, so thus we do use locking */
343
344 switch(specifier) { /* switch on specifier */
345
346 case('a'): /* abbreviated weekday name */
347 _store_str((char *)(lc_time->wday_abbr[timeptr->tm_wday]),
348 string, left);
349 break;
350
351 case('A'): /* full weekday name */
352 _store_str((char *)(lc_time->wday[timeptr->tm_wday]),
353 string, left);
354 break;
355
356 case('b'): /* abbreviated month name */
357 _store_str((char *)(lc_time->month_abbr[timeptr->tm_mon]),
358 string, left);
359 break;
360
361 case('B'): /* full month name */
362 _store_str((char *)(lc_time->month[timeptr->tm_mon]),
363 string, left);
364 break;
365
366 case('c'): /* date and time display */
367 if (__alternate_form)
368 {
369 __alternate_form = FALSE;
370 _store_winword(lc_time->ww_ldatefmt, timeptr, string, left, lc_time);
371 if (*left == 0)
372 return;
373 *(*string)++=' ';
374 (*left)--;
375 _store_winword(lc_time->ww_timefmt, timeptr, string, left, lc_time);
376 }
377 else {
378 _store_winword(lc_time->ww_sdatefmt, timeptr, string, left, lc_time);
379 if (*left == 0)
380 return;
381 *(*string)++=' ';
382 (*left)--;
383 _store_winword(lc_time->ww_timefmt, timeptr, string, left, lc_time);
384 }
385 break;
386
387 case('d'): /* mday in decimal (01-31) */
388 __no_lead_zeros = __alternate_form;
389 _store_num(timeptr->tm_mday, 2, string, left);
390 break;
391
392 case('H'): /* 24-hour decimal (00-23) */
393 __no_lead_zeros = __alternate_form;
394 _store_num(timeptr->tm_hour, 2, string, left);
395 break;
396
397 case('I'): /* 12-hour decimal (01-12) */
398 __no_lead_zeros = __alternate_form;
399 if (!(temp = timeptr->tm_hour%12))
400 temp=12;
401 _store_num(temp, 2, string, left);
402 break;
403
404 case('j'): /* yday in decimal (001-366) */
405 __no_lead_zeros = __alternate_form;
406 _store_num(timeptr->tm_yday+1, 3, string, left);
407 break;
408
409 case('m'): /* month in decimal (01-12) */
410 __no_lead_zeros = __alternate_form;
411 _store_num(timeptr->tm_mon+1, 2, string, left);
412 break;
413
414 case('M'): /* minute in decimal (00-59) */
415 __no_lead_zeros = __alternate_form;
416 _store_num(timeptr->tm_min, 2, string, left);
417 break;
418
419 case('p'): /* AM/PM designation */
420 if (timeptr->tm_hour <= 11)
421 _store_str((char *)(lc_time->ampm[0]), string, left);
422 else
423 _store_str((char *)(lc_time->ampm[1]), string, left);
424 break;
425
426 case('S'): /* secs in decimal (00-59) */
427 __no_lead_zeros = __alternate_form;
428 _store_num(timeptr->tm_sec, 2, string, left);
429 break;
430
431 case('U'): /* sunday week number (00-53) */
432 __no_lead_zeros = __alternate_form;
433 wdaytemp = timeptr->tm_wday;
434 goto weeknum; /* join common code */
435
436 case('w'): /* week day in decimal (0-6) */
437 __no_lead_zeros = __alternate_form;
438 _store_num(timeptr->tm_wday, 1, string, left);
439 break;
440
441 case('W'): /* monday week number (00-53) */
442 __no_lead_zeros = __alternate_form;
443 if (timeptr->tm_wday == 0) /* monday based */
444 wdaytemp = 6;
445 else
446 wdaytemp = timeptr->tm_wday-1;
447 weeknum:
448 if (timeptr->tm_yday < wdaytemp)
449 temp=0;
450 else {
451 temp = timeptr->tm_yday/7;
452 if ((timeptr->tm_yday%7) >= wdaytemp)
453 temp++;
454 }
455 _store_num(temp, 2, string, left);
456 break;
457
458 case('x'): /* date display */
459 if (__alternate_form)
460 {
461 __alternate_form = FALSE;
462 _store_winword(lc_time->ww_ldatefmt, timeptr, string, left, lc_time);
463 }
464 else
465 {
466 _store_winword(lc_time->ww_sdatefmt, timeptr, string, left, lc_time);
467 }
468 break;
469
470 case('X'): /* time display */
471 __alternate_form = FALSE;
472 _store_winword(lc_time->ww_timefmt, timeptr, string, left, lc_time);
473 break;
474
475 case('y'): /* year w/o century (00-99) */
476 __no_lead_zeros = __alternate_form;
477 temp = timeptr->tm_year%100;
478 _store_num(temp, 2, string, left);
479 break;
480
481 case('Y'): /* year w/ century */
482 __no_lead_zeros = __alternate_form;
483 temp = (((timeptr->tm_year/100)+19)*100) +
484 (timeptr->tm_year%100);
485 _store_num(temp, 4, string, left);
486 break;
487
488 case('Z'): /* time zone name, if any */
489 case('z'): /* time zone name, if any */
490 __tzset(); /* Set time zone info */
491 _store_str(_tzname[((timeptr->tm_isdst)?1:0)],
492 string, left);
493 break;
494
495 case('%'): /* percent sign */
496 *(*string)++ = '%';
497 (*left)--;
498 break;
499
500 default: /* unknown format directive */
501 /* ignore the directive and continue */
502 /* [ANSI: Behavior is undefined.] */
503 break;
504
505 } /* end % switch */
506 }
507
508
509 /*
510 * Cache holding the last time (GMT) for which the Daylight time status was
511 * determined by an API call.
512 */
513 static SYSTEMTIME gmt_cache;
514
515 /*
516 * Three values of dstflag_cache and dstflag (local variable in code
517 * below)
518 */
519 #define DAYLIGHT_TIME 1
520 #define STANDARD_TIME 0
521 #define UNKNOWN_TIME -1
522
523 static int dstflag_cache;
524
525 /***
526 *time_t time(timeptr) - Get current system time and convert to time_t value.
527 *
528 *Purpose:
529 * Gets the current date and time and stores it in internal (time_t)
530 * format. The time is returned and stored via the pointer passed in
531 * timeptr. If timeptr == NULL, the time is only returned, not stored in
532 * *timeptr. The internal (time_t) format is the number of seconds since
533 * 00:00:00, Jan 1 1970 (UTC).
534 *
535 * Note: We cannot use GetSystemTime since its return is ambiguous. In
536 * Windows NT, in return UTC. In Win32S, probably also Win32C, it
537 * returns local time.
538 *
539 *Entry:
540 * time_t *timeptr - pointer to long to store time in.
541 *
542 *Exit:
543 * returns the current time.
544 *
545 *Exceptions:
546 *
547 *******************************************************************************/
548
time(time_t * timeptr)549 time_t __cdecl time (
550 time_t *timeptr
551 )
552 {
553 time_t tim;
554
555 SYSTEMTIME loct, gmt;
556 TIME_ZONE_INFORMATION tzinfo;
557 DWORD tzstate;
558 int dstflag;
559
560 /*
561 * Get local time from Win32
562 */
563 GetLocalTime( &loct );
564
565 /*
566 * Determine whether or not the local time is a Daylight Saving
567 * Time. On Windows NT, the GetTimeZoneInformation API is *VERY*
568 * expensive. The scheme below is intended to avoid this API call in
569 * many important case by caching the GMT value and dstflag.In a
570 * subsequent call to time(), the cached value of dstflag is used
571 * unless the new GMT differs from the cached value at least in the
572 * minutes place.
573 */
574 GetSystemTime( &gmt );
575
576 if ( (gmt.wMinute == gmt_cache.wMinute) &&
577 (gmt.wHour == gmt_cache.wHour) &&
578 (gmt.wDay == gmt_cache.wDay) &&
579 (gmt.wMonth == gmt_cache.wMonth) &&
580 (gmt.wYear == gmt_cache.wYear) )
581 {
582 dstflag = dstflag_cache;
583 }
584 else
585 {
586 if ( (tzstate = GetTimeZoneInformation( &tzinfo )) != 0xFFFFFFFF )
587 {
588 /*
589 * Must be very careful in determining whether or not DST is
590 * really in effect.
591 */
592 if ( (tzstate == TIME_ZONE_ID_DAYLIGHT) &&
593 (tzinfo.DaylightDate.wMonth != 0) &&
594 (tzinfo.DaylightBias != 0) )
595 dstflag = DAYLIGHT_TIME;
596 else
597 /*
598 * When in doubt, assume standard time
599 */
600 dstflag = STANDARD_TIME;
601 }
602 else
603 dstflag = UNKNOWN_TIME;
604
605 dstflag_cache = dstflag;
606 gmt_cache = gmt;
607 }
608
609 /* convert using our private routine */
610
611 tim = __loctotime_t( (int)loct.wYear,
612 (int)loct.wMonth,
613 (int)loct.wDay,
614 (int)loct.wHour,
615 (int)loct.wMinute,
616 (int)loct.wSecond,
617 dstflag );
618
619 if (timeptr)
620 *timeptr = tim; /* store time if requested */
621
622 return tim;
623 }
624
625
626 /***
627 *time_t __loctotime_t(yr, mo, dy, hr, mn, sc, dstflag) - converts OS local
628 * time to internal time format (i.e., a time_t value)
629 *
630 *Purpose:
631 * Converts a local time value, obtained in a broken down format from
632 * the host OS, to time_t format (i.e., the number elapsed seconds since
633 * 01-01-70, 00:00:00, UTC).
634 *
635 *Entry:
636 * int yr, mo, dy - date
637 * int hr, mn, sc - time
638 * int dstflag - 1 if Daylight Time, 0 if Standard Time, -1 if
639 * not specified.
640 *
641 *Exit:
642 * Returns calendar time value.
643 *
644 *Exceptions:
645 *
646 *******************************************************************************/
647
__loctotime_t(int yr,int mo,int dy,int hr,int mn,int sc,int dstflag)648 time_t __cdecl __loctotime_t (
649 int yr, /* 0 based */
650 int mo, /* 1 based */
651 int dy, /* 1 based */
652 int hr,
653 int mn,
654 int sc,
655 int dstflag )
656 {
657 int tmpdays;
658 long tmptim;
659 struct tm tb;
660
661 /*
662 * Do a quick range check on the year and convert it to a delta
663 * off of 1900.
664 */
665 if ( ((long)(yr -= 1900) < _BASE_YEAR) || ((long)yr > _MAX_YEAR) )
666 return (time_t)(-1);
667
668 /*
669 * Compute the number of elapsed days in the current year. Note the
670 * test for a leap year would fail in the year 2100, if this was in
671 * range (which it isn't).
672 */
673 tmpdays = dy + _days[mo - 1];
674 if ( !(yr & 3) && (mo > 2) )
675 tmpdays++;
676
677 /*
678 * Compute the number of elapsed seconds since the Epoch. Note the
679 * computation of elapsed leap years would break down after 2100
680 * if such values were in range (fortunately, they aren't).
681 */
682 tmptim = /* 365 days for each year */
683 (((long)yr - _BASE_YEAR) * 365L
684
685 /* one day for each elapsed leap year */
686 + (long)((yr - 1) >> 2) - _LEAP_YEAR_ADJUST
687
688 /* number of elapsed days in yr */
689 + tmpdays)
690
691 /* convert to hours and add in hr */
692 * 24L + hr;
693
694 tmptim = /* convert to minutes and add in mn */
695 (tmptim * 60L + mn)
696
697 /* convert to seconds and add in sec */
698 * 60L + sc;
699 /*
700 * Account for time zone.
701 */
702 __tzset();
703 tmptim += _timezone;
704
705 /*
706 * Fill in enough fields of tb for _isindst(), then call it to
707 * determine DST.
708 */
709 tb.tm_yday = tmpdays;
710 tb.tm_year = yr;
711 tb.tm_mon = mo - 1;
712 tb.tm_hour = hr;
713 if ( (dstflag == 1) || ((dstflag == -1) && _daylight &&
714 _isindst(&tb)) )
715 tmptim += _dstbias;
716 return(tmptim);
717 }
718
719 /***
720 *static void cvtdate( trantype, datetype, year, month, week, dayofweek,
721 * date, hour, min, second, millisec ) - convert
722 * transition date format
723 *
724 *Purpose:
725 * Convert the format of a transition date specification to a value of
726 * a transitiondate structure.
727 *
728 *Entry:
729 * int trantype - 1, if it is the start of DST
730 * 0, if is the end of DST (in which case the date is
731 * is a DST date)
732 * int datetype - 1, if a day-in-month format is specified.
733 * 0, if an absolute date is specified.
734 * int year - year for which the date is being converted (70 ==
735 * 1970)
736 * int month - month (0 == January)
737 * int week - week of month, if datetype == 1 (note that 5== last
738 * week of month),
739 * 0, otherwise.
740 * int dayofweek - day of week (0 == Sunday), if datetype == 1.
741 * 0, otherwise.
742 * int date - date of month (1 - 31)
743 * int hour - hours (0 - 23)
744 * int min - minutes (0 - 59)
745 * int sec - seconds (0 - 59)
746 * int msec - milliseconds (0 - 999)
747 *
748 *Exit:
749 * dststart or dstend is filled in with the converted date.
750 *
751 *******************************************************************************/
752
cvtdate(int trantype,int datetype,int year,int month,int week,int dayofweek,int date,int hour,int min,int sec,int msec)753 static void __cdecl cvtdate (
754 int trantype,
755 int datetype,
756 int year,
757 int month,
758 int week,
759 int dayofweek,
760 int date,
761 int hour,
762 int min,
763 int sec,
764 int msec
765 )
766 {
767 int yearday;
768 int monthdow;
769
770 if ( datetype == 1 ) {
771
772 /*
773 * Transition day specified in day-in-month format.
774 */
775
776 /*
777 * Figure the year-day of the start of the month.
778 */
779 yearday = 1 + (IS_LEAP_YEAR(year) ? _lpdays[month - 1] :
780 _days[month - 1]);
781
782 /*
783 * Figure the day of the week of the start of the month.
784 */
785 monthdow = (yearday + ((year - 70) * 365) + ((year - 1) >> 2) -
786 _LEAP_YEAR_ADJUST + _BASE_DOW) % 7;
787
788 /*
789 * Figure the year-day of the transition date
790 */
791 if ( monthdow <= dayofweek )
792 yearday += (dayofweek - monthdow) + (week - 1) * 7;
793 else
794 yearday += (dayofweek - monthdow) + week * 7;
795
796 /*
797 * May have to adjust the calculation above if week == 5 (meaning
798 * the last instance of the day in the month). Check if year falls
799 * beyond after month and adjust accordingly.
800 */
801 if ( (week == 5) &&
802 (yearday > (IS_LEAP_YEAR(year) ? _lpdays[month] :
803 _days[month])) )
804 {
805 yearday -= 7;
806 }
807 }
808 else {
809 /*
810 * Transition day specified as an absolute day
811 */
812 yearday = IS_LEAP_YEAR(year) ? _lpdays[month - 1] :
813 _days[month - 1];
814
815 yearday += date;
816 }
817
818 if ( trantype == 1 ) {
819 /*
820 * Converted date was for the start of DST
821 */
822 dststart.yd = yearday;
823 dststart.ms = (long)msec +
824 (1000L * (sec + 60L * (min + 60L * hour)));
825 /*
826 * Set year field of dststart so that unnecessary calls to
827 * cvtdate() may be avoided.
828 */
829 dststart.yr = year;
830 }
831 else {
832 /*
833 * Converted date was for the end of DST
834 */
835 dstend.yd = yearday;
836 dstend.ms = (long)msec +
837 (1000L * (sec + 60L * (min + 60L * hour)));
838 /*
839 * The converted date is still a DST date. Must convert to a
840 * standard (local) date while being careful the millisecond field
841 * does not overflow or underflow.
842 */
843 if ( (dstend.ms += (_dstbias * 1000L)) < 0 ) {
844 dstend.ms += DAY_MILLISEC;
845 dstend.yd--;
846 }
847 else if ( dstend.ms >= DAY_MILLISEC ) {
848 dstend.ms -= DAY_MILLISEC;
849 dstend.yd++;
850 }
851
852 /*
853 * Set year field of dstend so that unnecessary calls to cvtdate()
854 * may be avoided.
855 */
856 dstend.yr = year;
857 }
858
859 return;
860 }
861
862 /***
863 *int _isindst(tb) - determine if broken-down time falls in DST
864 *
865 *Purpose:
866 * Determine if the given broken-down time falls within daylight saving
867 * time (DST). The DST rules are either obtained from Win32 (tzapiused !=
868 * TRUE) or assumed to be USA rules, post 1986.
869 *
870 * If the DST rules are obtained from Win32's GetTimeZoneInformation API,
871 * the transition dates to/from DST can be specified in either of two
872 * formats. First, a day-in-month format, similar to the way USA rules
873 * are specified, can be used. The transition date is given as the n-th
874 * occurence of a specified day of the week in a specified month. Second,
875 * an absolute date can be specified. The two cases are distinguished by
876 * the value of wYear field in the SYSTEMTIME structure (0 denotes a
877 * day-in-month format).
878 *
879 * USA rules for DST are that a time is in DST iff it is on or after
880 * 02:00 on the first Sunday in April, and before 01:00 on the last
881 * Sunday in October.
882 *
883 *Entry:
884 * struct tm *tb - structure holding broken-down time value
885 *
886 *Exit:
887 * 1, if time represented is in DST
888 * 0, otherwise
889 *
890 *******************************************************************************/
891
_isindst(struct tm * tb)892 int __cdecl _isindst (
893 struct tm *tb
894 )
895 {
896 long ms;
897
898 if ( _daylight == 0 )
899 return 0;
900
901 /*
902 * Compute (recompute) the transition dates for daylight saving time
903 * if necessary.The yr (year) fields of dststart and dstend is
904 * compared to the year of interest to determine necessity.
905 */
906 if ( (tb->tm_year != dststart.yr) || (tb->tm_year != dstend.yr) ) {
907 if ( tzapiused ) {
908 /*
909 * Convert the start of daylight saving time to dststart.
910 */
911 if ( tzinfo.DaylightDate.wYear == 0 )
912 cvtdate( 1,
913 1, /* day-in-month format */
914 tb->tm_year,
915 tzinfo.DaylightDate.wMonth,
916 tzinfo.DaylightDate.wDay,
917 tzinfo.DaylightDate.wDayOfWeek,
918 0,
919 tzinfo.DaylightDate.wHour,
920 tzinfo.DaylightDate.wMinute,
921 tzinfo.DaylightDate.wSecond,
922 tzinfo.DaylightDate.wMilliseconds );
923 else
924 cvtdate( 1,
925 0, /* absolute date */
926 tb->tm_year,
927 tzinfo.DaylightDate.wMonth,
928 0,
929 0,
930 tzinfo.DaylightDate.wDay,
931 tzinfo.DaylightDate.wHour,
932 tzinfo.DaylightDate.wMinute,
933 tzinfo.DaylightDate.wSecond,
934 tzinfo.DaylightDate.wMilliseconds );
935 /*
936 * Convert start of standard time to dstend.
937 */
938 if ( tzinfo.StandardDate.wYear == 0 )
939 cvtdate( 0,
940 1, /* day-in-month format */
941 tb->tm_year,
942 tzinfo.StandardDate.wMonth,
943 tzinfo.StandardDate.wDay,
944 tzinfo.StandardDate.wDayOfWeek,
945 0,
946 tzinfo.StandardDate.wHour,
947 tzinfo.StandardDate.wMinute,
948 tzinfo.StandardDate.wSecond,
949 tzinfo.StandardDate.wMilliseconds );
950 else
951 cvtdate( 0,
952 0, /* absolute date */
953 tb->tm_year,
954 tzinfo.StandardDate.wMonth,
955 0,
956 0,
957 tzinfo.StandardDate.wDay,
958 tzinfo.StandardDate.wHour,
959 tzinfo.StandardDate.wMinute,
960 tzinfo.StandardDate.wSecond,
961 tzinfo.StandardDate.wMilliseconds );
962
963 }
964 else {
965 /*
966 * GetTimeZoneInformation API was NOT used, or failed. USA
967 * daylight saving time rules are assumed.
968 */
969 cvtdate( 1,
970 1,
971 tb->tm_year,
972 4, /* April */
973 1, /* first... */
974 0, /* ...Sunday */
975 0,
976 2, /* 02:00 (2 AM) */
977 0,
978 0,
979 0 );
980
981 cvtdate( 0,
982 1,
983 tb->tm_year,
984 10, /* October */
985 5, /* last... */
986 0, /* ...Sunday */
987 0,
988 2, /* 02:00 (2 AM) */
989 0,
990 0,
991 0 );
992 }
993 }
994
995 /*
996 * Handle simple cases first.
997 */
998 if ( dststart.yd < dstend.yd ) {
999 /*
1000 * Northern hemisphere ordering
1001 */
1002 if ( (tb->tm_yday < dststart.yd) || (tb->tm_yday > dstend.yd) )
1003 return 0;
1004 if ( (tb->tm_yday > dststart.yd) && (tb->tm_yday < dstend.yd) )
1005 return 1;
1006 }
1007 else {
1008 /*
1009 * Southern hemisphere ordering
1010 */
1011 if ( (tb->tm_yday < dstend.yd) || (tb->tm_yday > dststart.yd) )
1012 return 1;
1013 if ( (tb->tm_yday > dstend.yd) && (tb->tm_yday < dststart.yd) )
1014 return 0;
1015 }
1016
1017 ms = 1000L * (tb->tm_sec + 60L * tb->tm_min + 3600L * tb->tm_hour);
1018
1019 if ( tb->tm_yday == dststart.yd ) {
1020 if ( ms >= dststart.ms )
1021 return 1;
1022 else
1023 return 0;
1024 }
1025 else {
1026 /*
1027 * tb->tm_yday == dstend.yd
1028 */
1029 if ( ms < dstend.ms )
1030 return 1;
1031 else
1032 return 0;
1033 }
1034
1035 }
1036
1037 /***
1038 *_store_num() - Convert a number to ascii and copy it
1039 *
1040 *Purpose:
1041 * Convert the supplied number to decimal and store
1042 * in the output buffer. Update both the count and
1043 * buffer pointers.
1044 *
1045 * *** For internal use with strftime() only ***
1046 *
1047 *Entry:
1048 * int num = pointer to integer value
1049 * int digits = # of ascii digits to put into string
1050 * char **out = address of pointer to output string
1051 * size_t *count = address of char count (space in output area)
1052 *
1053 *Exit:
1054 * none
1055 *Exceptions:
1056 *
1057 *******************************************************************************/
1058
_store_num(int num,int digits,char ** out,size_t * count)1059 static void __cdecl _store_num (
1060 int num,
1061 int digits,
1062 char **out,
1063 size_t *count
1064 )
1065 {
1066 int temp=0;
1067
1068 if (__no_lead_zeros) {
1069 _store_number (num, out, count);
1070 return;
1071 }
1072
1073 if ((size_t)digits < *count) {
1074 for (digits--; (digits+1); digits--) {
1075 (*out)[digits] = (char)('0' + num % 10);
1076 num /= 10;
1077 temp++;
1078 }
1079 *out += temp;
1080 *count -= temp;
1081 }
1082 else
1083 *count = 0;
1084 }
1085
1086 /***
1087 *_store_str() - Copy a time string
1088 *
1089 *Purpose:
1090 * Copy the supplied time string into the output string until
1091 * (1) we hit a null in the time string, or (2) the given count
1092 * goes to 0.
1093 *
1094 * *** For internal use with strftime() only ***
1095 *
1096 *Entry:
1097 * char *in = pointer to null terminated time string
1098 * char **out = address of pointer to output string
1099 * size_t *count = address of char count (space in output area)
1100 *
1101 *Exit:
1102 * none
1103 *Exceptions:
1104 *
1105 *******************************************************************************/
1106
_store_str(char * in,char ** out,size_t * count)1107 static void __cdecl _store_str (
1108 char *in,
1109 char **out,
1110 size_t *count
1111 )
1112 {
1113
1114 while ((*count != 0) && (*in != '\0')) {
1115 *(*out)++ = *in++;
1116 (*count)--;
1117 }
1118 }
1119
1120 /***
1121 *_store_winword() - Store date/time in WinWord format
1122 *
1123 *Purpose:
1124 * Format the date/time in the supplied WinWord format
1125 * and store it in the supplied buffer.
1126 *
1127 * *** For internal use with strftime() only ***
1128 *
1129 * The WinWord format is converted token by token to
1130 * strftime conversion specifiers. _expandtime is then called to
1131 * do the work. The WinWord format is expected to be a
1132 * character string (not wide-chars).
1133 *
1134 *Entry:
1135 * const char **format = address of pointer to WinWord format
1136 * const struct tm *tmptr = pointer to time/date structure
1137 * char **out = address of pointer to output string
1138 * size_t *count = address of char count (space in output area)
1139 * struct __lc_time_data *lc_time = pointer to locale-specific info
1140 *
1141 *Exit:
1142 * none
1143 *
1144 *Exceptions:
1145 *
1146 *******************************************************************************/
1147
_store_winword(const char * format,const struct tm * tmptr,char ** out,size_t * count,struct __lc_time_data * lc_time)1148 static void __cdecl _store_winword (
1149 const char *format,
1150 const struct tm *tmptr,
1151 char **out,
1152 size_t *count,
1153 struct __lc_time_data *lc_time
1154 )
1155 {
1156 char specifier;
1157 const char *p;
1158 int repeat;
1159 char *ampmstr;
1160
1161 while (*format && *count != 0)
1162 {
1163 specifier = 0; /* indicate no match */
1164 __no_lead_zeros = 0; /* default is print leading zeros */
1165
1166 /* count the number of repetitions of this character */
1167 for (repeat=0, p=format; *p++ == *format; repeat++);
1168 /* leave p pointing to the beginning of the next token */
1169 p--;
1170
1171 /* switch on ascii format character and determine specifier */
1172 switch (*format)
1173 {
1174 case 'M':
1175 switch (repeat)
1176 {
1177 case 1: __no_lead_zeros = 1; /* fall thru */
1178 case 2: specifier = 'm'; break;
1179 case 3: specifier = 'b'; break;
1180 case 4: specifier = 'B'; break;
1181 } break;
1182 case 'd':
1183 switch (repeat)
1184 {
1185 case 1: __no_lead_zeros = 1; /* fall thru */
1186 case 2: specifier = 'd'; break;
1187 case 3: specifier = 'a'; break;
1188 case 4: specifier = 'A'; break;
1189 } break;
1190 case 'y':
1191 switch (repeat)
1192 {
1193 case 2: specifier = 'y'; break;
1194 case 4: specifier = 'Y'; break;
1195 } break;
1196 case 'h':
1197 switch (repeat)
1198 {
1199 case 1: __no_lead_zeros = 1; /* fall thru */
1200 case 2: specifier = 'I'; break;
1201 } break;
1202 case 'H':
1203 switch (repeat)
1204 {
1205 case 1: __no_lead_zeros = 1; /* fall thru */
1206 case 2: specifier = 'H'; break;
1207 } break;
1208 case 'm':
1209 switch (repeat)
1210 {
1211 case 1: __no_lead_zeros = 1; /* fall thru */
1212 case 2: specifier = 'M'; break;
1213 } break;
1214 case 's': /* for compatibility; not strictly WinWord */
1215 switch (repeat)
1216 {
1217 case 1: __no_lead_zeros = 1; /* fall thru */
1218 case 2: specifier = 'S'; break;
1219 } break;
1220 case 'A':
1221 case 'a':
1222 if (!_stricmp(format, "am/pm"))
1223 p = format + 5;
1224 else if (!_stricmp(format, "a/p"))
1225 p = format + 3;
1226 specifier = 'p';
1227 break;
1228 case 't': /* t or tt time marker suffix */
1229 if ( tmptr->tm_hour <= 11 )
1230 ampmstr = lc_time->ampm[0];
1231 else
1232 ampmstr = lc_time->ampm[1];
1233
1234 while ( (repeat > 0) && (*count > 0) )
1235 {
1236 if ( isleadbyte((int)*ampmstr) &&
1237 (*count > 1) )
1238 {
1239 *(*out)++ = *ampmstr++;
1240 (*count)--;
1241 }
1242 *(*out)++ = *ampmstr++;
1243 (*count)--;
1244 repeat--;
1245 }
1246 format = p;
1247 continue;
1248
1249 case '\'': /* literal string */
1250 if (repeat & 1) /* odd number */
1251 {
1252 format += repeat;
1253 while (*format && *count != 0)
1254 {
1255 if (*format == '\'')
1256 {
1257 format++;
1258 break;
1259 }
1260 if ( isleadbyte((int)*format) &&
1261 (*count > 1) )
1262 {
1263 *(*out)++ = *format++;
1264 (*count)--;
1265 }
1266 *(*out)++ = *format++;
1267 (*count)--;
1268 }
1269 }
1270 else { /* even number */
1271 format += repeat;
1272 }
1273 continue;
1274
1275 default: /* non-control char, print it */
1276 break;
1277 } /* switch */
1278
1279 /* expand specifier, or copy literal if specifier not found */
1280 if (specifier)
1281 {
1282 _expandtime(specifier, tmptr, out, count, lc_time);
1283 format = p; /* bump format up to the next token */
1284 } else {
1285 if (isleadbyte((int)*format))
1286 {
1287 *(*out)++ = *format++;
1288 (*count)--;
1289 }
1290 *(*out)++ = *format++;
1291 (*count)--;
1292 }
1293 } /* while */
1294 }
1295
1296 /***
1297 *_store_number() - Convert positive integer to string
1298 *
1299 *Purpose:
1300 * Convert positive integer to a string and store it in the output
1301 * buffer with no null terminator. Update both the count and
1302 * buffer pointers.
1303 *
1304 * Differs from _store_num in that the precision is not specified,
1305 * and no leading zeros are added.
1306 *
1307 * *** For internal use with strftime() only ***
1308 *
1309 * Created from xtoi.c
1310 *
1311 *Entry:
1312 * int num = pointer to integer value
1313 * char **out = address of pointer to output string
1314 * size_t *count = address of char count (space in output area)
1315 *
1316 *Exit:
1317 * none
1318 *
1319 *Exceptions:
1320 * The buffer is filled until it is out of space. There is no
1321 * way to tell beforehand (as in _store_num) if the buffer will
1322 * run out of space.
1323 *
1324 *******************************************************************************/
1325
_store_number(int num,char ** out,size_t * count)1326 static void __cdecl _store_number (
1327 int num,
1328 char **out,
1329 size_t *count
1330 )
1331 {
1332 char *p; /* pointer to traverse string */
1333 char *firstdig; /* pointer to first digit */
1334 char temp; /* temp char */
1335
1336 p = *out;
1337
1338 /* put the digits in the buffer in reverse order */
1339 if (*count > 1)
1340 {
1341 do {
1342 *p++ = (char) (num % 10 + '0');
1343 (*count)--;
1344 } while ((num/=10) > 0 && *count > 1);
1345 }
1346
1347 firstdig = *out; /* firstdig points to first digit */
1348 *out = p; /* return pointer to next space */
1349 p--; /* p points to last digit */
1350
1351 /* reverse the buffer */
1352 do {
1353 temp = *p;
1354 *p-- = *firstdig;
1355 *firstdig++ = temp; /* swap *p and *firstdig */
1356 } while (firstdig < p); /* repeat until halfway */
1357 }
1358
1359 /***
1360 *void tzset() - sets timezone information and calc if in daylight time
1361 *
1362 *Purpose:
1363 * Sets the timezone information from the TZ environment variable
1364 * and then sets _timezone, _daylight, and _tzname. If we're in daylight
1365 * time is automatically calculated.
1366 *
1367 *Entry:
1368 * None, reads TZ environment variable.
1369 *
1370 *Exit:
1371 * sets _daylight, _timezone, and _tzname global vars, no return value
1372 *
1373 *Exceptions:
1374 *
1375 *******************************************************************************/
1376
1377
__tzset(void)1378 void __cdecl __tzset(void)
1379 {
1380 int defused;
1381 int negdiff = 0;
1382
1383 /*
1384 * Clear the flag indicated whether GetTimeZoneInformation was used.
1385 */
1386 tzapiused = 0;
1387
1388 /*
1389 * Set year fields of dststart and dstend structures to -1 to ensure
1390 * they are recomputed as after this
1391 */
1392 dststart.yr = dstend.yr = -1;
1393
1394 /*
1395 * Fetch the value of the TZ environment variable.
1396 */
1397 if ( 1 /*(TZ = _getenv_lk("TZ")) == NULL */) {
1398
1399 /*
1400 * There is no TZ environment variable, try to use the time zone
1401 * information from the system.
1402 */
1403
1404 if ( GetTimeZoneInformation( &tzinfo ) != 0xFFFFFFFF ) {
1405 /*
1406 * Note that the API was used.
1407 */
1408 tzapiused = 1;
1409
1410 /*
1411 * Derive _timezone value from Bias and StandardBias fields.
1412 */
1413 _timezone = tzinfo.Bias * 60L;
1414
1415 if ( tzinfo.StandardDate.wMonth != 0 )
1416 _timezone += (tzinfo.StandardBias * 60L);
1417
1418 /*
1419 * Check to see if there is a daylight time bias. Since the
1420 * StandardBias has been added into _timezone, it must be
1421 * compensated for in the value computed for _dstbias.
1422 */
1423 if ( (tzinfo.DaylightDate.wMonth != 0) &&
1424 (tzinfo.DaylightBias != 0) )
1425 {
1426 _daylight = 1;
1427 _dstbias = (tzinfo.DaylightBias - tzinfo.StandardBias) *
1428 60L;
1429 }
1430 else {
1431 _daylight = 0;
1432
1433 /*
1434 * Set daylight bias to 0 because GetTimeZoneInformation
1435 * may return TIME_ZONE_ID_DAYLIGHT even though there is
1436 * no DST (in NT 3.51, just turn off the automatic DST
1437 * adjust in the control panel)!
1438 */
1439 _dstbias = 0;
1440 }
1441
1442 /*
1443 * Try to grab the name strings for both the time zone and the
1444 * daylight zone. Note the wide character strings in tzinfo
1445 * must be converted to multibyte characters strings. The
1446 * locale codepage, __lc_codepage, is used for this. Note that
1447 * if setlocale() with LC_ALL or LC_CTYPE has not been called,
1448 * then __lc_codepage will be 0 (_CLOCALECP), which is CP_ACP
1449 * (which means use the host's default ANSI codepage).
1450 */
1451 if ( (WideCharToMultiByte( __lc_codepage,
1452 WC_COMPOSITECHECK |
1453 WC_SEPCHARS,
1454 tzinfo.StandardName,
1455 -1,
1456 _tzname[0],
1457 63,
1458 NULL,
1459 &defused ) != 0) &&
1460 (!defused) )
1461 _tzname[0][63] = '\0';
1462 else
1463 _tzname[0][0] = '\0';
1464
1465 if ( (WideCharToMultiByte( __lc_codepage,
1466 WC_COMPOSITECHECK |
1467 WC_SEPCHARS,
1468 tzinfo.DaylightName,
1469 -1,
1470 _tzname[1],
1471 63,
1472 NULL,
1473 &defused ) != 0) &&
1474 (!defused) )
1475 _tzname[1][63] = '\0';
1476 else
1477 _tzname[1][0] = '\0';
1478
1479 }
1480
1481 /*
1482 * Time zone information is unavailable, just return.
1483 */
1484 return;
1485 }
1486 }
1487
1488 /***
1489 *struct tm *localtime(ptime) - convert time_t value to tm structure
1490 *
1491 *Purpose:
1492 * Convert a value in internal (time_t) format to a tm struct
1493 * containing the corresponding local time.
1494 *
1495 * NOTES:
1496 * (1) gmtime must be called before _isindst to ensure that the tb time
1497 * structure is initialized.
1498 * (2) gmtime and localtime use a single statically allocated buffer.
1499 * Each call to one of these routines destroys the contents of the
1500 * previous call.
1501 * (3) It is assumed that time_t is a 32-bit long integer representing
1502 * the number of seconds since 00:00:00, 01-01-70 (UTC) (i.e., the
1503 * Posix/Unix Epoch. Only non-negative values are supported.
1504 * (4) It is assumed that the maximum adjustment for local time is
1505 * less than three days (include Daylight Savings Time adjustment).
1506 * This only a concern in Posix where the specification of the TZ
1507 * environment restricts the combined offset for time zone and
1508 * Daylight Savings Time to 2 * (24:59:59), just under 50 hours.
1509 *
1510 *Entry:
1511 * time_t *ptime - pointer to a long time value
1512 *
1513 *Exit:
1514 * If *ptime is non-negative, returns a pointer to the tm structure.
1515 * Otherwise, returns NULL.
1516 *
1517 *Exceptions:
1518 * See items (3) and (4) in the NOTES above. If these assumptions are
1519 * violated, behavior is undefined.
1520 *
1521 *******************************************************************************/
localtime(const time_t * ptime)1522 struct tm * __cdecl localtime (
1523 const time_t *ptime
1524 )
1525 {
1526 struct tm *ptm;
1527 long ltime;
1528
1529 /*
1530 * Check for illegal time_t value
1531 */
1532 if ( (long)*ptime < 0L )
1533 return( NULL );
1534
1535 #ifdef _WIN32
1536 __tzset();
1537 #else /* _WIN32 */
1538 #if defined (_M_MPPC) || defined (_M_M68K)
1539 _tzset();
1540 #endif /* defined (_M_MPPC) || defined (_M_M68K) */
1541 #endif /* _WIN32 */
1542
1543 if ( (*ptime > 3 * _DAY_SEC) && (*ptime < LONG_MAX - 3 * _DAY_SEC) ) {
1544 /*
1545 * The date does not fall within the first three, or last
1546 * three, representable days of the Epoch. Therefore, there
1547 * is no possibility of overflowing or underflowing the
1548 * time_t representation as we compensate for timezone and
1549 * Daylight Savings Time.
1550 */
1551
1552 ltime = (long)*ptime - _timezone;
1553 ptm = gmtime( (time_t *)<ime );
1554
1555 /*
1556 * Check and adjust for Daylight Saving Time.
1557 */
1558 if ( _daylight && _isindst( ptm ) ) {
1559 ltime -= _dstbias;
1560 ptm = gmtime( (time_t *)<ime );
1561 ptm->tm_isdst = 1;
1562 }
1563 }
1564 else {
1565 ptm = gmtime( ptime );
1566
1567 /*
1568 * The date falls with the first three, or last three days
1569 * of the Epoch. It is possible the time_t representation
1570 * would overflow or underflow while compensating for
1571 * timezone and Daylight Savings Time. Therefore, make the
1572 * timezone and Daylight Savings Time adjustments directly
1573 * in the tm structure. The beginning of the Epoch is
1574 * 00:00:00, 01-01-70 (UTC) and the last representable second
1575 * in the Epoch is 03:14:07, 01-19-2038 (UTC). This will be
1576 * used in the calculations below.
1577 *
1578 * First, adjust for the timezone.
1579 */
1580 if ( _isindst(ptm) )
1581 ltime = (long)ptm->tm_sec - (_timezone + _dstbias);
1582 else
1583 ltime = (long)ptm->tm_sec - _timezone;
1584 ptm->tm_sec = (int)(ltime % 60);
1585 if ( ptm->tm_sec < 0 ) {
1586 ptm->tm_sec += 60;
1587 ltime -= 60;
1588 }
1589
1590 ltime = (long)ptm->tm_min + ltime/60;
1591 ptm->tm_min = (int)(ltime % 60);
1592 if ( ptm->tm_min < 0 ) {
1593 ptm->tm_min += 60;
1594 ltime -= 60;
1595 }
1596
1597 ltime = (long)ptm->tm_hour + ltime/60;
1598 ptm->tm_hour = (int)(ltime % 24);
1599 if ( ptm->tm_hour < 0 ) {
1600 ptm->tm_hour += 24;
1601 ltime -=24;
1602 }
1603
1604 ltime /= 24;
1605
1606 if ( ltime > 0L ) {
1607 /*
1608 * There is no possibility of overflowing the tm_mday
1609 * and tm_yday fields since the date can be no later
1610 * than January 19.
1611 */
1612 ptm->tm_wday = (ptm->tm_wday + ltime) % 7;
1613 ptm->tm_mday += ltime;
1614 ptm->tm_yday += ltime;
1615 }
1616 else if ( ltime < 0L ) {
1617 /*
1618 * It is possible to underflow the tm_mday and tm_yday
1619 * fields. If this happens, then adjusted date must
1620 * lie in December 1969.
1621 */
1622 ptm->tm_wday = (ptm->tm_wday + 7 + ltime) % 7;
1623 if ( (ptm->tm_mday += ltime) <= 0 ) {
1624 ptm->tm_mday += 31;
1625 ptm->tm_yday = 364;
1626 ptm->tm_mon = 11;
1627 ptm->tm_year--;
1628 }
1629 else {
1630 ptm->tm_yday += ltime;
1631 }
1632 }
1633
1634
1635 }
1636
1637
1638 return(ptm);
1639 }
1640
1641 static struct tm tb = { 0 }; /* time block */
1642
1643 /***
1644 *struct tm *gmtime(timp) - convert *timp to a structure (UTC)
1645 *
1646 *Purpose:
1647 * Converts the calendar time value, in internal format (time_t), to
1648 * broken-down time (tm structure) with the corresponding UTC time.
1649 *
1650 *Entry:
1651 * const time_t *timp - pointer to time_t value to convert
1652 *
1653 *Exit:
1654 * returns pointer to filled-in tm structure.
1655 * returns NULL if *timp < 0L
1656 *
1657 *Exceptions:
1658 *
1659 *******************************************************************************/
1660
gmtime(const time_t * timp)1661 struct tm * __cdecl gmtime (
1662 const time_t *timp
1663 )
1664 {
1665
1666 long caltim = *timp; /* calendar time to convert */
1667 int islpyr = 0; /* is-current-year-a-leap-year flag */
1668 int tmptim;
1669 int *mdays; /* pointer to days or lpdays */
1670
1671 struct tm *ptb = &tb;
1672
1673 if ( caltim < 0L )
1674 return(NULL);
1675
1676 /*
1677 * Determine years since 1970. First, identify the four-year interval
1678 * since this makes handling leap-years easy (note that 2000 IS a
1679 * leap year and 2100 is out-of-range).
1680 */
1681 tmptim = (int)(caltim / _FOUR_YEAR_SEC);
1682 caltim -= ((long)tmptim * _FOUR_YEAR_SEC);
1683
1684 /*
1685 * Determine which year of the interval
1686 */
1687 tmptim = (tmptim * 4) + 70; /* 1970, 1974, 1978,...,etc. */
1688
1689 if ( caltim >= _YEAR_SEC ) {
1690
1691 tmptim++; /* 1971, 1975, 1979,...,etc. */
1692 caltim -= _YEAR_SEC;
1693
1694 if ( caltim >= _YEAR_SEC ) {
1695
1696 tmptim++; /* 1972, 1976, 1980,...,etc. */
1697 caltim -= _YEAR_SEC;
1698
1699 /*
1700 * Note, it takes 366 days-worth of seconds to get past a leap
1701 * year.
1702 */
1703 if ( caltim >= (_YEAR_SEC + _DAY_SEC) ) {
1704
1705 tmptim++; /* 1973, 1977, 1981,...,etc. */
1706 caltim -= (_YEAR_SEC + _DAY_SEC);
1707 }
1708 else {
1709 /*
1710 * In a leap year after all, set the flag.
1711 */
1712 islpyr++;
1713 }
1714 }
1715 }
1716
1717 /*
1718 * tmptim now holds the value for tm_year. caltim now holds the
1719 * number of elapsed seconds since the beginning of that year.
1720 */
1721 ptb->tm_year = tmptim;
1722
1723 /*
1724 * Determine days since January 1 (0 - 365). This is the tm_yday value.
1725 * Leave caltim with number of elapsed seconds in that day.
1726 */
1727 ptb->tm_yday = (int)(caltim / _DAY_SEC);
1728 caltim -= (long)(ptb->tm_yday) * _DAY_SEC;
1729
1730 /*
1731 * Determine months since January (0 - 11) and day of month (1 - 31)
1732 */
1733 if ( islpyr )
1734 mdays = _lpdays;
1735 else
1736 mdays = _days;
1737
1738
1739 for ( tmptim = 1 ; mdays[tmptim] < ptb->tm_yday ; tmptim++ ) ;
1740
1741 ptb->tm_mon = --tmptim;
1742
1743 ptb->tm_mday = ptb->tm_yday - mdays[tmptim];
1744
1745 /*
1746 * Determine days since Sunday (0 - 6)
1747 */
1748 ptb->tm_wday = ((int)(*timp / _DAY_SEC) + _BASE_DOW) % 7;
1749
1750 /*
1751 * Determine hours since midnight (0 - 23), minutes after the hour
1752 * (0 - 59), and seconds after the minute (0 - 59).
1753 */
1754 ptb->tm_hour = (int)(caltim / 3600);
1755 caltim -= (long)ptb->tm_hour * 3600L;
1756
1757 ptb->tm_min = (int)(caltim / 60);
1758 ptb->tm_sec = (int)(caltim - (ptb->tm_min) * 60);
1759
1760 ptb->tm_isdst = 0;
1761 return( (struct tm *)ptb );
1762
1763 }
1764
abort()1765 int abort() { return 0; }
1766