summaryrefslogtreecommitdiffstats
path: root/private/crt32/time/tzset.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/crt32/time/tzset.c')
-rw-r--r--private/crt32/time/tzset.c927
1 files changed, 927 insertions, 0 deletions
diff --git a/private/crt32/time/tzset.c b/private/crt32/time/tzset.c
new file mode 100644
index 000000000..d5b5c711e
--- /dev/null
+++ b/private/crt32/time/tzset.c
@@ -0,0 +1,927 @@
+/***
+*tzset.c - set timezone information and see if we're in daylight time
+*
+* Copyright (c) 1985-1993, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* defines _tzset() - set timezone and daylight saving time vars
+*
+*Revision History:
+* 03-??-84 RLB initial version
+* 03-26-86 TC added minus capability to time difference w.r.t GMT
+* 03-27-86 TC fixed daylight davings time calculation, off by a day
+* error
+* 12-03-86 SKS daylight savings time is different starting april 1987
+* Fixed off-by-1 errors when either Apr 30 or Oct 31 is
+* Sat. Simplified leap year check: this works for
+* 1970-2099 only!
+* 11-19-87 SKS Add __tzset() which calls tzset only the first time
+* Made _isindst() a near procedure
+* 11-25-87 WAJ Added calls to _lock and _unlock
+* 12-11-87 JCR Added "_LOAD_DS" to declaration
+* 01-27-88 SKS Made _isindst() and _dtoxtime() are no longer near (for
+* QC)
+* 05-24-88 PHG Merged DLL and normal versions
+* 03-20-90 GJF Made calling type _CALLTYPE1, added #include
+* <cruntime.h>, removed #include <register.h>, removed
+* some leftover 16-bit support and fixed the copyright.
+* Also, cleaned up the formatting a bit.
+* 03-23-90 GJF Made static functions _CALLTYPE4.
+* 07-30-90 SBM Added void to empty function arg lists to create
+* prototypes
+* 10-04-90 GJF New-style function declarators.
+* 01-21-91 GJF ANSI naming.
+* 08-10-92 PBS Posix Support (TZ stuff).
+* 03-30-93 GJF Ported C8-16 version to Win32.
+* 06-28-93 GJF Limited support for system's notion of time zone
+* in Windows NT.
+* 07-15-93 GJF Resurrected __tzset().
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#include <ctype.h>
+#include <ctime.h>
+#include <time.h>
+#include <stdlib.h>
+#include <internal.h>
+#ifdef _POSIX_
+#include <limits.h>
+#else
+#include <os2dll.h>
+#include <windows.h>
+#endif
+#include <string.h>
+
+#ifndef _POSIX_
+/*
+ * Pointer to a saved copy of the TZ value obtained in the previous call
+ * to tzset() set (if any).
+ */
+static char * lastTZ = NULL;
+#endif
+
+
+/***
+*void tzset() - sets timezone information and calc if in daylight time
+*
+*Purpose:
+* Sets the timezone information from the TZ environment variable
+* and then sets _timezone, _daylight, and _tzname. If we're in daylight
+* time is automatically calculated.
+*
+*Entry:
+* None, reads TZ environment variable.
+*
+*Exit:
+* sets _daylight, _timezone, and _tzname global vars, no return value
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+#ifndef _POSIX_
+
+#ifdef MTHREAD
+static void _CRTAPI3 _tzset_lk(void);
+#else
+#define _tzset_lk _tzset
+#endif
+
+void _CRTAPI1 __tzset(void)
+{
+ static int first_time;
+
+ if ( !first_time ) {
+
+ _mlock( _TIME_LOCK );
+
+ if ( !first_time ) {
+ _tzset_lk();
+ first_time++;
+ }
+
+ _munlock(_TIME_LOCK );
+
+ }
+}
+
+
+#ifdef MTHREAD /* multi-thread; define both tzset and _tzset_lk */
+void _CRTAPI1 _tzset (
+ void
+ )
+{
+ _mlock( _TIME_LOCK );
+
+ _tzset_lk();
+
+ _munlock( _TIME_LOCK );
+}
+
+
+static void _CRTAPI3 _tzset_lk (
+
+#else /* non multi-thread; only define tzset */
+
+void _CRTAPI1 _tzset (
+
+#endif /* rejoin common code */
+
+ void
+ )
+{
+ REG1 char *TZ;
+ REG2 int negdiff = 0;
+
+ _mlock(_ENV_LOCK);
+
+ /*
+ * Fetch the value of the TZ environment variable.
+ */
+ if ( (TZ = _getenv_lk("TZ")) == NULL ) {
+ /*
+ * If there is no TZ environment variable, try to use the
+ * time zone information from the system.
+ */
+ TIME_ZONE_INFORMATION tzinfo;
+
+ if ( GetTimeZoneInformation( &tzinfo ) != 0xffffffff ) {
+ /*
+ * Derive _timezone value from Bias and StandardBias fields.
+ */
+ _timezone = tzinfo.Bias * 60L;
+
+ if ( tzinfo.StandardDate.wMonth != 0 )
+ _timezone += (tzinfo.StandardBias * 60L);
+
+ /*
+ * Check to see if there is a daylight time bias. If so, we
+ * ASSUME it is USA daylight saving time (that is all we
+ * support for rev. one).
+ */
+ if ( (tzinfo.DaylightDate.wMonth != 0) &&
+ (tzinfo.DaylightBias != 0) )
+ _daylight = 1;
+ else
+ _daylight = 0;
+
+ /*
+ * Remove the default names, but don't try to determine
+ * suitable replacements (NT does not enforce any standard
+ * or convention for timezone naming).
+ */
+ *_tzname[0] = '\0';
+ *_tzname[1] = '\0';
+ }
+
+ /*
+ * Time zone information is unavailable, just return.
+ */
+ _munlock(_ENV_LOCK);
+ return;
+ }
+
+
+ if ( (*TZ == '\0') || ((lastTZ != NULL) && (strcmp(TZ, lastTZ) == 0)) )
+ {
+ /*
+ * Either TZ is NULL, pointing to '\0', or is the unchanged
+ * from a earlier call (to this function). In any case, there
+ * is no work to do, so just return
+ */
+ _munlock(_ENV_LOCK);
+ return;
+ }
+
+ /*
+ * Update lastTZ
+ */
+ if (lastTZ != NULL) {
+ free(lastTZ);
+ }
+ lastTZ = strdup(TZ);
+
+ _munlock(_ENV_LOCK);
+
+ /*
+ * Process TZ value and update _tzname, _timezone and _daylight.
+ */
+
+ strncpy(_tzname[0], TZ, 3);
+
+ /*
+ * time difference is of the form:
+ *
+ * [+|-]hh[:mm[:ss]]
+ *
+ * check minus sign first.
+ */
+ if ( *(TZ += 3) == '-' ) {
+ negdiff++;
+ TZ++;
+ }
+
+ /*
+ * process, then skip over, the hours
+ */
+ _timezone = atol(TZ) * 3600L;
+
+ while ( (*TZ == '+') || ((*TZ >= '0') && (*TZ <= '9')) ) TZ++;
+
+ /*
+ * check if minutes were specified
+ */
+ if ( *TZ == ':' ) {
+ /*
+ * process, then skip over, the minutes
+ */
+ _timezone += atol(++TZ) * 60L;
+ while ( (*TZ >= '0') && (*TZ <= '9') ) TZ++;
+
+ /*
+ * check if seconds were specified
+ */
+ if ( *TZ == ':' ) {
+ /*
+ * process, then skip over, the seconds
+ */
+ _timezone += atol(++TZ);
+ while ( (*TZ >= '0') && (*TZ <= '9') ) TZ++;
+ }
+ }
+
+ if ( negdiff )
+ _timezone = -_timezone;
+
+ /*
+ * finally, check for a DST zone suffix
+ */
+ if ( _daylight = *TZ )
+ strncpy(_tzname[1], TZ, 3);
+ else
+ *_tzname[1] = '\0';
+
+}
+
+
+/***
+*int _isindst(tb) - determine if broken-down time falls in DST
+*
+*Purpose:
+* Determine if the given broken-down time falls within DST. Only
+* modern, summer-time DST is handled (USA, post 1967).
+*
+* This is the rule for years before 1987:
+* a time is in DST iff it is on or after 02:00:00 on the last Sunday
+* in April and before 01:00:00 on the last Sunday in October.
+* This is the rule for years starting with 1987:
+* a time is in DST iff it is on or after 02:00:00 on the first Sunday
+* in April and before 01:00:00 on the last Sunday in October.
+*
+*Entry:
+* struct tm *tb - structure holding broken-down time value
+*
+*Exit:
+* 1, if time represented is in DST
+* 0, otherwise
+*
+*******************************************************************************/
+
+int _CRTAPI1 _isindst (
+ REG1 struct tm *tb
+ )
+{
+ int mdays;
+ REG2 int yr;
+ int critsun;
+
+ /*
+ * Handle easy cases.
+ *
+ * Modern DST was put into effect by Congress in 1967. Also, if the
+ * month is before April or after October, it cannot be DST.
+ */
+ if ( (tb->tm_year < 67) || (tb->tm_mon < 3) || (tb->tm_mon > 9) )
+ return(0);
+
+ /*
+ * If the month is after April and before October, it must be DST.
+ */
+ if ( (tb->tm_mon > 3) && (tb->tm_mon < 9) )
+ return(1);
+
+ /*
+ * Now for the hard part. Month is April or October; see if date
+ * falls between appropriate Sundays.
+ */
+
+ /*
+ * The objective for years before 1987 (after 1986) is to determine
+ * if the day is on or after 2:00 am on the last (first) Sunday in
+ * April, or before 1:00 am on the last Sunday in October.
+ *
+ * We know the year-day (0..365) of the current time structure. We must
+ * determine the year-day of the last (first) Sunday in this month,
+ * April or October, and then do the comparison.
+ *
+ * To determine the year-day of the last Sunday, we do the following:
+ * 1. Get the year-day of the last day of the current month (Apr
+ * or Oct)
+ * 2. Determine the week-day number of #1,
+ * which is defined as 0 = Sun, 1 = Mon, ... 6 = Sat
+ * 3. Subtract #2 from #1
+ *
+ * To determine the year-day of the first Sunday, we do the following:
+ * 1. Get the year-day of the 7th day of the current month
+ * (April)
+ * 2. Determine the week-day number of #1,
+ * which is defined as 0 = Sun, 1 = Mon, ... 6 = Sat
+ * 3. Subtract #2 from #1
+ */
+
+ /*
+ * First we get #1. The year-days for each month are stored in _days[]
+ * they're all off by -1
+ */
+ if ( ((yr = tb->tm_year) > 86) && (tb->tm_mon == 3) )
+ mdays = 7 + _days[tb->tm_mon];
+ else
+ mdays = _days[tb->tm_mon+1];
+
+ /*
+ * if this is a leap-year, add an extra day
+ */
+ if ( !(yr & 3) )
+ mdays++;
+
+ /*
+ * mdays now has #1
+ */
+
+ /* Now get #2. We know the week-day number of January 1, 1970, which is
+ * defined as the constant _BASE_DOW. Add to this the number of elapsed
+ * days since then, take the result mod 7, and we have our day number.
+ *
+ * To obtain #3, we just subtract this from mdays.
+ */
+
+ critsun = mdays - ((mdays + 365 * (yr - 70) + ((yr - 1) >> 2) -
+ _LEAP_YEAR_ADJUST + _BASE_DOW) % 7);
+
+ /* Now we know 1 and 3; we're golden: */
+
+ return ( (tb->tm_mon == 3)
+ ? ((tb->tm_yday > critsun) ||
+ ((tb->tm_yday == critsun) && (tb->tm_hour >= 2)))
+ : ((tb->tm_yday < critsun) ||
+ ((tb->tm_yday == critsun) && (tb->tm_hour < 1))) );
+}
+
+
+#else /* _POSIX_ */
+
+/*
+ * The following is an implementation of the TZ grammar specified in the
+ * document:
+ *
+ * 8.1.1 Extension to Time Functions
+ * IEEE Std 1003.1 - 1990
+ * Page 152 - 153
+ *
+ * The TZ grammar looks like:
+ *
+ * stdoffset[dst[offset][,start[/time],end[/time]]]
+ *
+ * Variables used in code:
+ *
+ * tzname[0] ==> std
+ * _timezone ==> offset(the one after 'std')
+ * tzname[1] ==> dst
+ * _dstoffset ==> offset(the one after 'dst')
+ * _startdate ==> start
+ * _starttime ==> time(the one after 'start')
+ * _enddate ==> end
+ * _endtime ==> time(the one after 'end')
+ *
+ */
+
+/*
+ * Refer to the document for the detailed description of fields of _DSTDATE.
+ * Two of Jn, n, and Mm are -1, indicating the one(not -1) is a vaild value.
+ */
+
+typedef struct _DSTDATE {
+ int Jn; /* -1 or [1, 365](year day and leap day shall not be counted) */
+ int n; /* -1 or [0, 365](year day and leap day shall be counted) */
+ int Mm; /* -1 or [1, 12](month) */
+ int Mn; /* [1, 5] if Mm != -1 (week) */
+ int Md; /* [0, 6] if Mm != -1 (weekday, Sunday == 0) */
+} DSTDATE, *PDSTDATE;
+
+#define SEC_PER_HOUR (60 * 60)
+#define SEC_PER_DAY (SEC_PER_HOUR * 24)
+
+
+/*
+ * The default TZ in tzset() should look like:
+ *
+ * TZ = "PST8PDT,M4.1.0/2:00,M10.5.0/2:00";
+ */
+
+/* Day light saving start/end date and default vaules */
+static DSTDATE _startdate = { -1, -1, 4, 1, 0};
+static DSTDATE _enddate = {-1, -1, 10, 5, 0};
+
+
+/* Seconds since midnight on _startdate/_enddate with default values.
+ * _endtime is 1am instead of 2am because the DST end time is 2am
+ * local time, which by default is 1am standard time.
+ */
+long _starttime = 7200L, _endtime = 7200L;
+
+/*
+ * If we are only interested in years between 1901 and 2099, we could use this:
+ *
+ * #define IS_LEAP_YEAR(y) (y % 4 == 0)
+ */
+
+#define IS_LEAP_YEAR(y) ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0)
+
+
+/*
+ * ParsePosixStdOrDst - parse the std or dst element in TZ.
+ *
+ * ENTRY pch - beginning of the substring in TZ.
+ *
+ * RETURN pointer to one position after the std or dst element parsed,
+ * or NULL if failed.
+ */
+
+
+static char * _CRTAPI3
+ParsePosixStdOrDst(
+ REG1 char *pch
+ )
+{
+#define UNWANTED(x) (isdigit(x) || x=='\0' || x==',' || x=='-' || x=='+')
+ int i;
+
+ /*
+ * Check against the rule.
+ */
+
+ if(*pch == ':' || UNWANTED(*pch)) {
+ return NULL;
+ }
+
+ /*
+ * Get a valid std or dst(i.e. 3 <= lenth_of(std | dst) <= TZNAME_MAX).
+ */
+
+ for(i=1, ++pch; (i < TZNAME_MAX) && !UNWANTED(*pch); i++, pch++) {
+ ;
+ }
+
+ /*
+ * pch now point to 1 position after the valid std or dst.
+ */
+
+ return (i >= 3) ? pch : NULL;
+}
+
+
+/*
+ * ParsePosixOffset - parse the offset element in TZ. The format of time is:
+ *
+ * [- | +]hh[:mm[:ss]]
+ *
+ * ENTRY pch - beginning of the substring in TZ.
+ *
+ * ptime - pointer to a variable(_timezone or _dstoffset) storing the
+ * time(in seconds) parsed.
+ *
+ * RETURN pointer to one position after the end of the offset element parsed.
+ */
+
+
+static char * _CRTAPI3
+ParsePosixOffset(
+ REG1 char *pch,
+ REG2 long *poffset
+ )
+{
+ int fNegative;
+ long offset;
+
+ if((fNegative = (*pch == '-')) || *pch == '+') {
+ pch++;
+ }
+
+ offset = atol(pch)*3600L; /* hh */
+
+ while(*pch && isdigit(*pch)) {
+ pch++;
+ }
+
+ if(*pch == ':') {
+ offset += atol(++pch)*60L; /* mm */
+ while(*pch && isdigit(*pch)) {
+ pch++;
+ }
+
+ if(*pch == ':') {
+ offset += atol(++pch); /* ss */
+ while(*pch && isdigit(*pch)) {
+ pch++;
+ }
+ }
+ }
+
+ *poffset = fNegative ? -offset : offset;
+
+ return pch;
+}
+
+
+
+/*
+ * ParsePosixDate - parse the date element in TZ. The format of date is one
+ * of following:
+ *
+ * Jn, n, and Mm.n.d
+ *
+ * ENTRY pch - beginning of the substring in TZ.
+ *
+ * pDstDate - pointer to _startdate or _enddate storing the result.
+ *
+ * RETURN pointer to one position after the end of the date element parsed,
+ * or NULL if failed.
+ */
+
+static char * _CRTAPI3
+ParsePosixDate(
+ REG1 char *pch,
+ REG2 PDSTDATE pDstDate
+ )
+{
+ pDstDate->Jn = -1;
+ pDstDate->n = -1;
+ pDstDate->Mn = -1;
+
+ /*
+ * Two out of the three -1's will remain.
+ */
+
+ if(*pch == 'J') { /* Jn */
+ pDstDate->Jn = atoi(++pch);
+ } else if(*pch != 'M') { /* n */
+ pDstDate->n = atoi(pch);
+ } else { /* Mm.n.d */
+
+ pDstDate->Mm = atoi(++pch);
+
+ if(*++pch != '.') {
+ pch++;
+ }
+ pDstDate->Mn = atoi(++pch);
+
+ if(*++pch != '.') {
+ pch++;
+ }
+ pDstDate->Md = atoi(++pch);
+ }
+
+ while(*pch && isdigit(*pch)) {
+ pch++;
+ }
+
+#define IN_RANGE(x, a, b) (x >= a && x <= b)
+
+ return ((pDstDate->Jn != -1 && IN_RANGE(pDstDate->Jn, 1, 365)) ||
+ (pDstDate->n != -1 && IN_RANGE(pDstDate->n, 0, 365)) ||
+ (pDstDate->Mm != -1 && IN_RANGE(pDstDate->Mm, 1, 12) &&
+ IN_RANGE(pDstDate->Mn, 1, 5) && IN_RANGE(pDstDate->Md, 0, 6)))
+ ? pch : NULL;
+}
+
+/*
+ * ParsePosixTime - parse the time element in TZ. The format of time is:
+ *
+ * hh[:mm[:ss]]
+ *
+ * ENTRY pch - beginning of the substring in TZ.
+ *
+ * ptime - pointer to a variable(_starttime or _endtime) storing the
+ * time(in seconds) parsed.
+ *
+ * RETURN pointer to one position after the end of the time element parsed.
+ */
+
+static char * _CRTAPI3
+ParsePosixTime(
+ REG1 char *pch,
+ REG2 long *ptime
+ )
+{
+ long time;
+
+ time = atol(pch)*SEC_PER_HOUR; /* hh */
+
+ while(*pch && isdigit(*pch)) {
+ pch++;
+ }
+
+ if(*pch == ':') {
+
+ time += atol(++pch)*60L; /* mm */
+ while(*pch && isdigit(*pch)) {
+ pch++;
+ }
+
+ if(*pch == ':') {
+
+ time += atol(++pch); /* ss */
+ while(*pch && isdigit(*pch)) {
+ pch++;
+ }
+ }
+ }
+
+ *ptime = time;
+
+ return pch;
+}
+
+/*
+ * tzset - sets the timezone information from the TZ environment variable.
+ * Global tzname[], _timezone, _daylight, and _dstoffset will be
+ * set. Static _startdate, _enddate, _starttime, and _endtime will
+ * also be set. TZ string looks like:
+ *
+ * stdoffset[dst[offset][,start[/time],end[/time]]]
+ *
+ * In form of variables: tzname[0]_timezone[tzname[1][_dstoffset]
+ * [,_startdate[/_starttime],_enddate[/_endtime]]]
+ *
+ * ENTRY none.
+ *
+ * RETURN none.
+ */
+
+void _CRTAPI1 tzset(
+ void
+ )
+{
+ /* pch points to the beginning of an element to be parsed. */
+ REG1 char *pch;
+
+ /* pchCurr points to one position after the end of last element parsed. */
+ REG2 char *pchCurr;
+
+ char *TZ;
+
+ _endtime = 7200L;
+ _starttime = 7200L;
+
+ if (!(TZ = getenv("TZ")) || !*TZ) {
+ TZ = "PST8PDT7,M4.1.0/2:00,M10.5.0/2:00"; /* use default */
+ }
+
+ if((pchCurr = ParsePosixStdOrDst(pch=TZ)) == NULL) {
+ return;
+ }
+
+ memcpy(tzname[0], pch, (int)(pchCurr-pch));
+ tzname[0][(int)(pchCurr-pch)] = '\0';
+
+ if((pchCurr = ParsePosixOffset(pch=pchCurr, &_timezone)) == NULL) {
+ return;
+ }
+
+ _daylight = (*pchCurr != '\0');
+
+ if(!_daylight) {
+ return;
+ }
+
+ if((pchCurr = ParsePosixStdOrDst(pch=pchCurr)) == NULL) {
+ return;
+ }
+
+ memcpy(tzname[1], pch, (int)(pchCurr-pch));
+ tzname[1][(int)(pchCurr-pch)] = '\0';
+
+ if(isdigit(*pchCurr) || *pchCurr == '-' || *pchCurr == '+') {
+ if((pchCurr = ParsePosixOffset(pch=pchCurr, &_dstoffset)) == NULL) {
+ return;
+ }
+ } else {
+ /* default: 1 hour ahead of standard time */
+ _dstoffset = _timezone - SEC_PER_HOUR;
+ }
+
+ if(*pchCurr == ',') { /* ,start[/time],end[/time] */
+
+ if((pchCurr = ParsePosixDate(pchCurr+1, &_startdate)) == NULL) {
+ goto out;
+ }
+
+ if(*pchCurr == '/') {
+ if(!(pchCurr = ParsePosixTime(pchCurr+1, &_starttime))) {
+ goto out;
+ }
+ }
+
+ if(*pchCurr != ',') {
+ goto out;
+ }
+
+ if ((pchCurr = ParsePosixDate(pchCurr+1, &_enddate)) == NULL) {
+ goto out;
+ }
+
+ if (*pchCurr == '/') {
+ if(!(pchCurr = ParsePosixTime(pchCurr+1, &_endtime))) {
+ goto out;
+ }
+ }
+ }
+out:
+ /*
+ * Adjust the _endtime to account for the fact that
+ * dst ends at _endtime local time, rather than
+ * standard time.
+ */
+
+ _endtime -= (_timezone - _dstoffset);
+}
+
+
+#define DAY1 (4) /* Jan 1 1970 was a Thursday */
+
+/*
+ * GetDstStartOrEndYearDay - Converts day info from DSTDATE into 0-based
+ * year-day.
+ *
+ * ENTRY tm_year - the year concerned(tb->tm_year).
+ *
+ * pDstDate - pointer to either _startdate or _enddate.
+ *
+ * RETURN the year-day calculated.
+ */
+
+static int _CRTAPI3
+GetDstStartOrEndYearDay(
+ REG1 int tm_year,
+ REG2 PDSTDATE pDstDate
+ )
+{
+ REG1 int yday; /* year-day */
+ REG2 int theyear;
+
+ theyear = tm_year + 1900;
+
+ if(pDstDate->Jn != -1) {
+
+ /*
+ * Jn is in [1, 365] and leap day is not counted.
+ * Convert Jn to 0-based yday; Note: 60 is March 1.
+ */
+
+
+ yday = (IS_LEAP_YEAR(theyear) && (pDstDate->Jn >= 60))
+ ? pDstDate->Jn : pDstDate->Jn - 1;
+
+ } else if(pDstDate->n != -1) {
+
+ /*
+ * n is in [0, 365] and leap day is counted.
+ */
+
+ yday = pDstDate->n;
+
+ } else { /* Mm.n.d */
+
+ int *ptrday;
+ int years;
+ int wday;
+
+ /*
+ * We first need to calculate year-day(yday) and week-day
+ * (wday) of 1st day of month pDstDate->Mm. We then figure
+ * out year-day(yday) of Md day of week Mn of month Mm.
+ */
+
+ ptrday = IS_LEAP_YEAR(theyear) ? _lpdays : _days;
+
+ yday = ptrday[pDstDate->Mm-1] + 1; /* ptrday[i] are all by -1 off */
+
+ years = tm_year - 70;
+
+ /*
+ * Here constant Day1 is the week-day of Jan 1, 1970.
+ * (years+1)/4 is for correcting the leap years.
+ */
+
+ wday = (yday + 365*years + (years+1)/4 + DAY1) % 7;
+
+ /*
+ * Calculate yday of Md day of week 1 of month Mm.
+ */
+
+ yday += pDstDate->Md - wday;
+ if(pDstDate->Md < wday) {
+ yday += 7;
+ }
+
+ /*
+ * Calculate yday of Md day of week Mn of month Mm.
+ */
+
+ yday += (pDstDate->Mn-1)*7;
+
+ /*
+ * Adjust if yday goes beyond the end of the month.
+ */
+
+ if(pDstDate->Md == 5 && yday >= ptrday[pDstDate->Mm] + 1) {
+ yday -= 7;
+ }
+
+ }
+
+ return yday;
+}
+
+/*
+ * _isindst - Tells whether Xenix-type time value falls under DST.
+ *
+ * ENTRY tb - 'time' structure holding broken-down time value.
+ *
+ * RETURN 1 if time represented is in DST, else 0.
+ */
+
+int _CRTAPI1 _isindst (
+ REG1 struct tm *tb
+ )
+{
+ int st_yday, end_yday;
+ int st_sec, end_sec;
+
+ int check_time;
+
+ /*
+ * We need start/end year-days of DST in syday/eyday which are converted
+ * from one of the format Jn, n, and Mm.n.d. We already have start/end
+ * time (in seconds) of DST in _starttime/_endtime.
+ */
+
+ st_yday = GetDstStartOrEndYearDay(tb->tm_year, &_startdate);
+ end_yday = GetDstStartOrEndYearDay(tb->tm_year, &_enddate);
+
+ st_sec = st_yday * SEC_PER_DAY + _starttime;
+ end_sec = end_yday * SEC_PER_DAY + _endtime;
+
+ check_time = tb->tm_yday * SEC_PER_DAY + tb->tm_hour * SEC_PER_HOUR
+ + tb->tm_min * 60 + tb->tm_sec;
+
+ if (check_time >= st_sec && check_time < end_sec)
+ return 1;
+
+ return 0;
+}
+
+/*
+ * _isskiptime - Tells whether the given time is skipped at the
+ * dst change. For instance, we set our clocks forward one
+ * hour at 2am to 3am... This function returns true for
+ * the times between 1:59:59 and 3:00:00.
+ *
+ * ENTRY tb - 'time' structure holding broken-down time value.
+ *
+ * RETURN 1 if time represented is in the skipped period, 0
+ * otherwise.
+ */
+
+int _CRTAPI1 _isskiptime (
+ REG1 struct tm *tb
+ )
+{
+ int st_yday;
+ int st_sec;
+ int check_time;
+
+ st_yday = GetDstStartOrEndYearDay(tb->tm_year, &_startdate);
+ st_sec = st_yday * SEC_PER_DAY + _starttime;
+
+ check_time = tb->tm_yday * SEC_PER_DAY + tb->tm_hour * SEC_PER_HOUR
+ + tb->tm_min * 60 + tb->tm_sec;
+
+ if (check_time >= st_sec && check_time < st_sec - _dstoffset) {
+ return 1;
+ }
+ return 0;
+}
+
+#endif /* _POSIX_ */