summaryrefslogtreecommitdiffstats
path: root/private/crt32/time/localtim.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/crt32/time/localtim.c')
-rw-r--r--private/crt32/time/localtim.c252
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( &ltime );
+
+ /*
+ * Check and adjust for Daylight Saving Time.
+ */
+ if ( _daylight && _isindst( ptm ) ) {
+#ifdef _POSIX_
+ ltime -= _dstoffset - _timezone;
+#else
+ ltime += 3600L;
+#endif
+ ptm = gmtime( (time_t *)&ltime );
+ 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);
+}