diff options
Diffstat (limited to 'private/crt32/time/localtim.c')
-rw-r--r-- | private/crt32/time/localtim.c | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/private/crt32/time/localtim.c b/private/crt32/time/localtim.c new file mode 100644 index 000000000..59727b1ba --- /dev/null +++ b/private/crt32/time/localtim.c @@ -0,0 +1,252 @@ +/*** +*localtim.c - Convert time_t value to time structure +* +* Copyright (c) 1985-1993, Microsoft Corporation. All rights reserved. +* +*Purpose: +* Converts time stored as a time_t value to a structure of type +* struct tm expressed as local time. +* +*Revision History: +* 01-??-84 RLB Module created +* 05-??-84 DCW split off from the rest of the ctime routines +* 02-18-87 JCR made localtime work when gmtime returns null +* 03-31-87 JCR fixed bug pertaining to uninitialized _isindst(tb) +* 04-10-87 JCR changed long declaration to time_t and added const +* 11-10-87 SKS Removed IBMC20 switch +* 11-18-87 SKS Change tzset() to __tzset() +* 12-11-87 JCR Added "_LOAD_DS" to declaration +* 11-06-89 KRS Added (unsigned) to handle years 2040-2099 correctly. +* 03-20-90 GJF Replaced _LOAD_DS with _CALLTYPE1, added #include +* <cruntime.h>, removed #include <register.h> and +* fixed the copyright. Also, cleaned up the formatting +* a bit. +* 10-04-90 GJF New-style function declarator. Also, rewrote expr. +* to avoid using cast as lvalue. +* 01-21-91 GJF ANSI naming. +* 08-10-92 PBS Posix support (TZ stuff). +* 03-24-93 GJF Ported C8-16 version and adapted for exotic Daylight +* Savings Time conversions which are legal under POSIX. +* 07-15-93 GJF Replaced _tzset() call with __tzset() call. +* +*******************************************************************************/ + +#include <cruntime.h> +#include <limits.h> +#include <time.h> +#include <stddef.h> +#include <ctime.h> +#include <internal.h> + +/*** +*struct tm *localtime(ptime) - convert time_t value to tm structure +* +*Purpose: +* Convert a value in internal (time_t) format to a tm struct +* containing the corresponding local time. +* +* NOTES: +* (1) gmtime must be called before _isindst to ensure that the tb time +* structure is initialized. +* (2) gmtime and localtime use a single statically allocated buffer. +* Each call to one of these routines destroys the contents of the +* previous call. +* (3) It is assumed that time_t is a 32-bit long integer representing +* the number of seconds since 00:00:00, 01-01-70 (UTC) (i.e., the +* Posix/Unix Epoch. Only non-negative values are supported. +* (4) It is assumed that the maximum adjustment for local time is +* less than three days (include Daylight Savings Time adjustment). +* This only a concern in Posix where the specification of the TZ +* environment restricts the combined offset for time zone and +* Daylight Savings Time to 2 * (24:59:59), just under 50 hours. +* +*Entry: +* time_t *ptime - pointer to a long time value +* +*Exit: +* If *ptime is non-negative, returns a pointer to the tm structure. +* Otherwise, returns NULL. +* +*Exceptions: +* See items (3) and (4) in the NOTES above. If these assumptions are +* violated, behavior is undefined. +* +*******************************************************************************/ + +struct tm * _CRTAPI1 localtime ( + const time_t *ptime + ) +{ + REG1 struct tm *ptm; + long ltime; + + /* + * Check for illegal time_t value + */ + if ( (long)*ptime < 0L ) + return( NULL ); + +#ifdef _POSIX_ + tzset(); +#else + __tzset(); +#endif + + if ( (*ptime > 3 * _DAY_SEC) && (*ptime < LONG_MAX - 3 * _DAY_SEC) ) { + /* + * The date does not fall within the first three, or last + * three, representable days of the Epoch. Therefore, there + * is no possibility of overflowing or underflowing the + * time_t representation as we compensate for timezone and + * Daylight Savings Time. + */ + + ltime = (long)*ptime - _timezone; + ptm = gmtime( <ime ); + + /* + * Check and adjust for Daylight Saving Time. + */ + if ( _daylight && _isindst( ptm ) ) { +#ifdef _POSIX_ + ltime -= _dstoffset - _timezone; +#else + ltime += 3600L; +#endif + ptm = gmtime( (time_t *)<ime ); + ptm->tm_isdst = 1; + } + } + else { + ptm = gmtime( ptime ); + /* + * The date falls with the first three, or last three days + * of the Epoch. It is possible the time_t representation + * would overflow or underflow while compensating for + * timezone and Daylight Savings Time. Therefore, make the + * timezone and Daylight Savings Time adjustments directly + * in the tm structure. The beginning of the Epoch is + * 00:00:00, 01-01-70 (UTC) and the last representable second + * in theEpoch is 03:14:07, 01-19-2038 (UTC). This will be + * used in the calculations below. + * + * First, adjust for the timezone. + */ + ltime = (long)ptm->tm_sec - _timezone; + ptm->tm_sec = (int)(ltime % 60); + if ( ptm->tm_sec < 0 ) { + ptm->tm_sec += 60; + ltime -= 60; + } + + ltime = (long)ptm->tm_min + ltime/60; + ptm->tm_min = (int)(ltime % 60); + if ( ptm->tm_min < 0 ) { + ptm->tm_min += 60; + ltime -= 60; + } + + ltime = (long)ptm->tm_hour + ltime/60; + ptm->tm_hour = (int)(ltime % 24); + if ( ptm->tm_hour < 0 ) { + ptm->tm_hour += 24; + ltime -=24; + } + + ltime /= 24; + + if ( ltime > 0L ) { + /* + * There is no possibility of overflowing the tm_mday + * and tm_yday fields since the date can be no later + * than January 19. + */ + ptm->tm_wday = (ptm->tm_wday + ltime) % 7; + ptm->tm_mday += ltime; + ptm->tm_yday += ltime; + } + else if ( ltime < 0L ) { + /* + * It is possible to underflow the tm_mday and tm_yday + * fields. If this happens, then adjusted date must + * lie in December 1969. + */ + ptm->tm_wday = (ptm->tm_wday + 7 + ltime) % 7; + if ( (ptm->tm_mday += ltime) <= 0 ) { + ptm->tm_mday += 31; + ptm->tm_yday = 365; + ptm->tm_mon = 11; + ptm->tm_year--; + } + else { + ptm->tm_yday += ltime; + } + } + +#ifdef _POSIX_ + /* + * In Posix, it is possible either the first or last three + * days of the Epoch might lie with Daylight Savings Time in + * certain time zones. + */ + if ( _isindst(ptm) ) { + + ltime = (long)ptm->tm_sec + _dstoffset; + ptm->tm_sec = (int)(ltime % 60); + if ( ptm->tm_sec < 0 ) { + ptm->tm_sec += 60; + ltime -= 60; + } + + ltime = (long)ptm->tm_min + ltime/60; + ptm->tm_min = (int)(ltime % 60); + if ( ptm->tm_min < 0 ) { + ptm->tm_min += 60; + ltime -= 60; + } + + ltime = (long)ptm->tm_hour + ltime/60; + ptm->tm_hour = (int)(ltime % 24); + if ( ptm->tm_hour < 0 ) { + ptm->tm_hour += 24; + ltime -=24; + } + + ltime /= 24; + + if ( ltime > 0L ) { + /* + * There is no possibility of overflowing the + * tm_mday and tm_yday fields since the date + * can be no later than January 19. + */ + ptm->tm_wday = (ptm->tm_wday + ltime) % 7; + ptm->tm_mday += ltime; + ptm->tm_yday += ltime; + } + else if ( ltime < 0L ) { + /* + * It is possible to underflow the tm_mday + * and tm_yday fields. If this happens, then + * adjusted date must lie in December 1969. + */ + ptm->tm_wday = (ptm->tm_wday + 7 + ltime) % 7; + if ( (ptm->tm_mday += ltime) <= 0 ) { + ptm->tm_mday += 31; + ptm->tm_yday = 365; + ptm->tm_mon = 12; + ptm->tm_year--; + } + else { + ptm->tm_yday += ltime; + } + } + } + +#endif + + } + + + return(ptm); +} |