home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / crt / src / tzset.c < prev    next >
C/C++ Source or Header  |  1998-06-17  |  30KB  |  934 lines

  1. /***
  2. *tzset.c - set timezone information and see if we're in daylight time
  3. *
  4. *       Copyright (c) 1985-1998, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. *       defines _tzset() - set timezone and daylight saving time vars
  8. *
  9. *******************************************************************************/
  10.  
  11. #ifdef _WIN32
  12.  
  13.  
  14. #include <cruntime.h>
  15. #include <ctype.h>
  16. #include <ctime.h>
  17. #include <time.h>
  18. #include <stdlib.h>
  19. #include <internal.h>
  20. #include <mtdll.h>
  21. #include <windows.h>
  22. #include <setlocal.h>
  23. #include <string.h>
  24. #include <dbgint.h>
  25.  
  26.  
  27. /*
  28.  * Number of milliseconds in one day
  29.  */
  30. #define DAY_MILLISEC    (24L * 60L * 60L * 1000L)
  31.  
  32. /*
  33.  * The macro below is valid for years between 1901 and 2099, which easily
  34.  * includes all years representable by the current implementation of time_t.
  35.  */
  36. #define IS_LEAP_YEAR(year)  ( (year & 3) == 0 )
  37.  
  38. /*
  39.  * Pointer to a saved copy of the TZ value obtained in the previous call
  40.  * to tzset() set (if any).
  41.  */
  42. static char * lastTZ = NULL;
  43.  
  44. /*
  45.  * Flag indicating that time zone information came from GetTimeZoneInformation
  46.  * API call.
  47.  */
  48. static int tzapiused;
  49.  
  50. static TIME_ZONE_INFORMATION tzinfo;
  51.  
  52. /*
  53.  * Structure used to represent DST transition date/times.
  54.  */
  55. typedef struct {
  56.         int  yr;        /* year of interest */
  57.         int  yd;        /* day of year */
  58.         long ms;        /* milli-seconds in the day */
  59.         } transitiondate;
  60.  
  61. /*
  62.  * DST start and end structs.
  63.  */
  64. static transitiondate dststart = { -1, 0, 0L };
  65. static transitiondate dstend   = { -1, 0, 0L };
  66.  
  67. static int __cdecl _isindst_lk(struct tm *);
  68.  
  69.  
  70.  
  71. /***
  72. *void tzset() - sets timezone information and calc if in daylight time
  73. *
  74. *Purpose:
  75. *       Sets the timezone information from the TZ environment variable
  76. *       and then sets _timezone, _daylight, and _tzname. If we're in daylight
  77. *       time is automatically calculated.
  78. *
  79. *Entry:
  80. *       None, reads TZ environment variable.
  81. *
  82. *Exit:
  83. *       sets _daylight, _timezone, and _tzname global vars, no return value
  84. *
  85. *Exceptions:
  86. *
  87. *******************************************************************************/
  88.  
  89.  
  90. #ifdef _MT
  91. static void __cdecl _tzset_lk(void);
  92. #else  /* _MT */
  93. #define _tzset_lk _tzset
  94. #endif  /* _MT */
  95.  
  96. void __cdecl __tzset(void)
  97. {
  98.         static int first_time = 0;
  99.  
  100.         if ( !first_time ) {
  101.  
  102.             _mlock( _TIME_LOCK );
  103.  
  104.             if ( !first_time ) {
  105.                 _tzset_lk();
  106.                 first_time++;
  107.             }
  108.  
  109.             _munlock(_TIME_LOCK );
  110.  
  111.         }
  112. }
  113.  
  114.  
  115. #ifdef _MT
  116. void __cdecl _tzset (
  117.         void
  118.         )
  119. {
  120.         _mlock( _TIME_LOCK );
  121.  
  122.         _tzset_lk();
  123.  
  124.         _munlock( _TIME_LOCK );
  125. }
  126.  
  127.  
  128. static void __cdecl _tzset_lk (
  129.  
  130. #else  /* _MT */
  131.  
  132. void __cdecl _tzset (
  133.  
  134. #endif  /* _MT */
  135.  
  136.         void
  137.         )
  138. {
  139.         char *TZ;
  140.         int defused;
  141.         int negdiff = 0;
  142.  
  143.         _mlock(_ENV_LOCK);
  144.  
  145.         /*
  146.          * Clear the flag indicated whether GetTimeZoneInformation was used.
  147.          */
  148.         tzapiused = 0;
  149.  
  150.         /*
  151.          * Set year fields of dststart and dstend structures to -1 to ensure
  152.          * they are recomputed as after this
  153.          */
  154.         dststart.yr = dstend.yr = -1;
  155.  
  156.         /*
  157.          * Fetch the value of the TZ environment variable.
  158.          */
  159.         if ( (TZ = _getenv_lk("TZ")) == NULL ) {
  160.  
  161.             /*
  162.              * There is no TZ environment variable, try to use the time zone
  163.              * information from the system.
  164.              */
  165.  
  166.             _munlock(_ENV_LOCK);
  167.  
  168.             if ( GetTimeZoneInformation( &tzinfo ) != 0xFFFFFFFF ) {
  169.                 /*
  170.                  * Note that the API was used.
  171.                  */
  172.                 tzapiused = 1;
  173.  
  174.                 /*
  175.                  * Derive _timezone value from Bias and StandardBias fields.
  176.                  */
  177.                 _timezone = tzinfo.Bias * 60L;
  178.  
  179.                 if ( tzinfo.StandardDate.wMonth != 0 )
  180.                     _timezone += (tzinfo.StandardBias * 60L);
  181.  
  182.                 /*
  183.                  * Check to see if there is a daylight time bias. Since the
  184.                  * StandardBias has been added into _timezone, it must be
  185.                  * compensated for in the value computed for _dstbias.
  186.                  */
  187.                 if ( (tzinfo.DaylightDate.wMonth != 0) &&
  188.                      (tzinfo.DaylightBias != 0) )
  189.                 {
  190.                     _daylight = 1;
  191.                     _dstbias = (tzinfo.DaylightBias - tzinfo.StandardBias) *
  192.                                60L;
  193.                 }
  194.                 else {
  195.                         _daylight = 0;
  196.  
  197.                     /*
  198.                      * Set daylight bias to 0 because GetTimeZoneInformation
  199.                      * may return TIME_ZONE_ID_DAYLIGHT even though there is
  200.                      * no DST (in NT 3.51, just turn off the automatic DST
  201.                      * adjust in the control panel)!
  202.                      */
  203.                     _dstbias = 0;
  204.                 }
  205.  
  206.                 /*
  207.                  * Try to grab the name strings for both the time zone and the
  208.                  * daylight zone. Note the wide character strings in tzinfo
  209.                  * must be converted to multibyte characters strings. The
  210.                  * locale codepage, __lc_codepage, is used for this. Note that
  211.                  * if setlocale() with LC_ALL or LC_CTYPE has not been called,
  212.                  * then __lc_codepage will be 0 (_CLOCALECP), which is CP_ACP
  213.                  * (which means use the host's default ANSI codepage).
  214.                  */
  215.                 if ( (WideCharToMultiByte( __lc_codepage,
  216.                                            WC_COMPOSITECHECK |
  217.                                             WC_SEPCHARS,
  218.                                            tzinfo.StandardName,
  219.                                            -1,
  220.                                            _tzname[0],
  221.                                            63,
  222.                                            NULL,
  223.                                            &defused ) != 0) &&
  224.                      (!defused) )
  225.                     _tzname[0][63] = '\0';
  226.                 else
  227.                     _tzname[0][0] = '\0';
  228.  
  229.                 if ( (WideCharToMultiByte( __lc_codepage,
  230.                                            WC_COMPOSITECHECK |
  231.                                             WC_SEPCHARS,
  232.                                            tzinfo.DaylightName,
  233.                                            -1,
  234.                                            _tzname[1],
  235.                                            63,
  236.                                            NULL,
  237.                                            &defused ) != 0) &&
  238.                      (!defused) )
  239.                     _tzname[1][63] = '\0';
  240.                 else
  241.                     _tzname[1][0] = '\0';
  242.  
  243.             }
  244.  
  245.             /*
  246.              * Time zone information is unavailable, just return.
  247.              */
  248.             return;
  249.         }
  250.  
  251.  
  252.         if ( (*TZ == '\0') || ((lastTZ != NULL) && (strcmp(TZ, lastTZ) == 0)) )
  253.         {
  254.             /*
  255.              * Either TZ is NULL, pointing to '\0', or is the unchanged
  256.              * from a earlier call (to this function). In any case, there
  257.              * is no work to do, so just return
  258.              */
  259.             _munlock(_ENV_LOCK);
  260.             return;
  261.         }
  262.  
  263.         /*
  264.          * Update lastTZ
  265.          */
  266.         _free_crt(lastTZ);
  267.  
  268.         if ((lastTZ = _malloc_crt(strlen(TZ)+1)) == NULL)
  269.         {
  270.             _munlock(_ENV_LOCK);
  271.             return;
  272.         }
  273.         strcpy(lastTZ, TZ);
  274.  
  275.         _munlock(_ENV_LOCK);
  276.  
  277.         /*
  278.          * Process TZ value and update _tzname, _timezone and _daylight.
  279.          */
  280.  
  281.         strncpy(_tzname[0], TZ, 3);
  282.         _tzname[0][3] = '\0';
  283.  
  284.         /*
  285.          * time difference is of the form:
  286.          *
  287.          *      [+|-]hh[:mm[:ss]]
  288.          *
  289.          * check minus sign first.
  290.          */
  291.         if ( *(TZ += 3) == '-' ) {
  292.             negdiff++;
  293.             TZ++;
  294.         }
  295.  
  296.         /*
  297.          * process, then skip over, the hours
  298.          */
  299.         _timezone = atol(TZ) * 3600L;
  300.  
  301.         while ( (*TZ == '+') || ((*TZ >= '0') && (*TZ <= '9')) ) TZ++;
  302.  
  303.         /*
  304.          * check if minutes were specified
  305.          */
  306.         if ( *TZ == ':' ) {
  307.             /*
  308.              * process, then skip over, the minutes
  309.              */
  310.             _timezone += atol(++TZ) * 60L;
  311.             while ( (*TZ >= '0') && (*TZ <= '9') ) TZ++;
  312.  
  313.             /*
  314.              * check if seconds were specified
  315.              */
  316.             if ( *TZ == ':' ) {
  317.                 /*
  318.                  * process, then skip over, the seconds
  319.                  */
  320.                 _timezone += atol(++TZ);
  321.                 while ( (*TZ >= '0') && (*TZ <= '9') ) TZ++;
  322.             }
  323.         }
  324.  
  325.         if ( negdiff )
  326.             _timezone = -_timezone;
  327.  
  328.         /*
  329.          * finally, check for a DST zone suffix
  330.          */
  331.         if ( _daylight = *TZ ) {
  332.             strncpy(_tzname[1], TZ, 3);
  333.             _tzname[1][3] = '\0';
  334.         }
  335.         else
  336.             *_tzname[1] = '\0';
  337.  
  338. }
  339.  
  340. /***
  341. *static void cvtdate( trantype, datetype, year, month, week, dayofweek,
  342. *                     date, hour, min, second, millisec ) - convert
  343. *       transition date format
  344. *
  345. *Purpose:
  346. *       Convert the format of a transition date specification to a value of
  347. *       a transitiondate structure.
  348. *
  349. *Entry:
  350. *       int trantype    - 1, if it is the start of DST
  351. *                         0, if is the end of DST (in which case the date is
  352. *                            is a DST date)
  353. *       int datetype    - 1, if a day-in-month format is specified.
  354. *                         0, if an absolute date is specified.
  355. *       int year        - year for which the date is being converted (70 ==
  356. *                         1970)
  357. *       int month       - month (0 == January)
  358. *       int week        - week of month, if datetype == 1 (note that 5== last
  359. *                         week of month),
  360. *                         0, otherwise.
  361. *       int dayofweek   - day of week (0 == Sunday), if datetype == 1.
  362. *                         0, otherwise.
  363. *       int date        - date of month (1 - 31)
  364. *       int hour        - hours (0 - 23)
  365. *       int min         - minutes (0 - 59)
  366. *       int sec         - seconds (0 - 59)
  367. *       int msec        - milliseconds (0 - 999)
  368. *
  369. *Exit:
  370. *       dststart or dstend is filled in with the converted date.
  371. *
  372. *******************************************************************************/
  373.  
  374. static void __cdecl cvtdate (
  375.         int trantype,
  376.         int datetype,
  377.         int year,
  378.         int month,
  379.         int week,
  380.         int dayofweek,
  381.         int date,
  382.         int hour,
  383.         int min,
  384.         int sec,
  385.         int msec
  386.         )
  387. {
  388.         int yearday;
  389.         int monthdow;
  390.  
  391.         if ( datetype == 1 ) {
  392.  
  393.             /*
  394.              * Transition day specified in day-in-month format.
  395.              */
  396.  
  397.             /*
  398.              * Figure the year-day of the start of the month.
  399.              */
  400.             yearday = 1 + (IS_LEAP_YEAR(year) ? _lpdays[month - 1] :
  401.                       _days[month - 1]);
  402.  
  403.             /*
  404.              * Figure the day of the week of the start of the month.
  405.              */
  406.             monthdow = (yearday + ((year - 70) * 365) + ((year - 1) >> 2) -
  407.                         _LEAP_YEAR_ADJUST + _BASE_DOW) % 7;
  408.  
  409.             /*
  410.              * Figure the year-day of the transition date
  411.              */
  412.             if ( monthdow < dayofweek )
  413.                 yearday += (dayofweek - monthdow) + (week - 1) * 7;
  414.             else
  415.                 yearday += (dayofweek - monthdow) + week * 7;
  416.  
  417.             /*
  418.              * May have to adjust the calculation above if week == 5 (meaning
  419.              * the last instance of the day in the month). Check if year falls
  420.              * beyond after month and adjust accordingly.
  421.              */
  422.             if ( (week == 5) &&
  423.                  (yearday > (IS_LEAP_YEAR(year) ? _lpdays[month] :
  424.                              _days[month])) )
  425.             {
  426.                 yearday -= 7;
  427.             }
  428.         }
  429.         else {
  430.             /*
  431.              * Transition day specified as an absolute day
  432.              */
  433.             yearday = IS_LEAP_YEAR(year) ? _lpdays[month - 1] :
  434.                       _days[month - 1];
  435.  
  436.             yearday += date;
  437.         }
  438.  
  439.         if ( trantype == 1 ) {
  440.             /*
  441.              * Converted date was for the start of DST
  442.              */
  443.             dststart.yd = yearday;
  444.             dststart.ms = (long)msec +
  445.                           (1000L * (sec + 60L * (min + 60L * hour)));
  446.             /*
  447.              * Set year field of dststart so that unnecessary calls to
  448.              * cvtdate() may be avoided.
  449.              */
  450.             dststart.yr = year;
  451.         }
  452.         else {
  453.             /*
  454.              * Converted date was for the end of DST
  455.              */
  456.             dstend.yd = yearday;
  457.             dstend.ms = (long)msec +
  458.                               (1000L * (sec + 60L * (min + 60L * hour)));
  459.             /*
  460.              * The converted date is still a DST date. Must convert to a
  461.              * standard (local) date while being careful the millisecond field
  462.              * does not overflow or underflow.
  463.              */
  464.             if ( (dstend.ms += (_dstbias * 1000L)) < 0 ) {
  465.                 dstend.ms += DAY_MILLISEC;
  466.                 dstend.yd--;
  467.             }
  468.             else if ( dstend.ms >= DAY_MILLISEC ) {
  469.                 dstend.ms -= DAY_MILLISEC;
  470.                 dstend.yd++;
  471.             }
  472.  
  473.             /*
  474.              * Set year field of dstend so that unnecessary calls to cvtdate()
  475.              * may be avoided.
  476.              */
  477.             dstend.yr = year;
  478.         }
  479.  
  480.         return;
  481. }
  482.  
  483. /***
  484. *int _isindst(tb) - determine if broken-down time falls in DST
  485. *
  486. *Purpose:
  487. *       Determine if the given broken-down time falls within daylight saving
  488. *       time (DST). The DST rules are either obtained from Win32 (tzapiused !=
  489. *       TRUE) or assumed to be USA rules, post 1986.
  490. *
  491. *       If the DST rules are obtained from Win32's GetTimeZoneInformation API,
  492. *       the transition dates to/from DST can be specified in either of two
  493. *       formats. First, a day-in-month format, similar to the way USA rules
  494. *       are specified, can be used. The transition date is given as the n-th
  495. *       occurence of a specified day of the week in a specified month. Second,
  496. *       an absolute date can be specified. The two cases are distinguished by
  497. *       the value of wYear field in the SYSTEMTIME structure (0 denotes a
  498. *       day-in-month format).
  499. *
  500. *       USA rules for DST are that a time is in DST iff it is on or after
  501. *       02:00 on the first Sunday in April, and before 01:00 on the last
  502. *       Sunday in October.
  503. *
  504. *Entry:
  505. *       struct tm *tb - structure holding broken-down time value
  506. *
  507. *Exit:
  508. *       1, if time represented is in DST
  509. *       0, otherwise
  510. *
  511. *******************************************************************************/
  512.  
  513. int __cdecl _isindst (
  514.         struct tm *tb
  515.         )
  516. #ifdef _MT
  517. {
  518.         int retval;
  519.  
  520.         _mlock( _TIME_LOCK );
  521.         retval = _isindst_lk( tb );
  522.         _munlock( _TIME_LOCK );
  523.  
  524.         return retval;
  525. }
  526.  
  527. static int __cdecl _isindst_lk (
  528.         struct tm *tb
  529.         )
  530. #endif  /* _MT */
  531. {
  532.         long ms;
  533.  
  534.         if ( _daylight == 0 )
  535.             return 0;
  536.  
  537.         /*
  538.          * Compute (recompute) the transition dates for daylight saving time
  539.          * if necessary.The yr (year) fields of dststart and dstend is
  540.          * compared to the year of interest to determine necessity.
  541.          */
  542.         if ( (tb->tm_year != dststart.yr) || (tb->tm_year != dstend.yr) ) {
  543.             if ( tzapiused ) {
  544.                 /*
  545.                  * Convert the start of daylight saving time to dststart.
  546.                  */
  547.                 if ( tzinfo.DaylightDate.wYear == 0 )
  548.                     cvtdate( 1,
  549.                              1,             /* day-in-month format */
  550.                              tb->tm_year,
  551.                              tzinfo.DaylightDate.wMonth,
  552.                              tzinfo.DaylightDate.wDay,
  553.                              tzinfo.DaylightDate.wDayOfWeek,
  554.                              0,
  555.                              tzinfo.DaylightDate.wHour,
  556.                              tzinfo.DaylightDate.wMinute,
  557.                              tzinfo.DaylightDate.wSecond,
  558.                              tzinfo.DaylightDate.wMilliseconds );
  559.                 else
  560.                     cvtdate( 1,
  561.                              0,             /* absolute date */
  562.                              tb->tm_year,
  563.                              tzinfo.DaylightDate.wMonth,
  564.                              0,
  565.                              0,
  566.                              tzinfo.DaylightDate.wDay,
  567.                              tzinfo.DaylightDate.wHour,
  568.                              tzinfo.DaylightDate.wMinute,
  569.                              tzinfo.DaylightDate.wSecond,
  570.                              tzinfo.DaylightDate.wMilliseconds );
  571.                 /*
  572.                  * Convert start of standard time to dstend.
  573.                  */
  574.                 if ( tzinfo.StandardDate.wYear == 0 )
  575.                     cvtdate( 0,
  576.                              1,             /* day-in-month format */
  577.                              tb->tm_year,
  578.                              tzinfo.StandardDate.wMonth,
  579.                              tzinfo.StandardDate.wDay,
  580.                              tzinfo.StandardDate.wDayOfWeek,
  581.                              0,
  582.                              tzinfo.StandardDate.wHour,
  583.                              tzinfo.StandardDate.wMinute,
  584.                              tzinfo.StandardDate.wSecond,
  585.                              tzinfo.StandardDate.wMilliseconds );
  586.                 else
  587.                     cvtdate( 0,
  588.                              0,             /* absolute date */
  589.                              tb->tm_year,
  590.                              tzinfo.StandardDate.wMonth,
  591.                              0,
  592.                              0,
  593.                              tzinfo.StandardDate.wDay,
  594.                              tzinfo.StandardDate.wHour,
  595.                              tzinfo.StandardDate.wMinute,
  596.                              tzinfo.StandardDate.wSecond,
  597.                              tzinfo.StandardDate.wMilliseconds );
  598.  
  599.             }
  600.             else {
  601.                 /*
  602.                  * GetTimeZoneInformation API was NOT used, or failed. USA
  603.                  * daylight saving time rules are assumed.
  604.                  */
  605.                 cvtdate( 1,
  606.                          1,
  607.                          tb->tm_year,
  608.                          4,                 /* April */
  609.                          1,                 /* first... */
  610.                          0,                 /* ...Sunday */
  611.                          0,
  612.                          2,                 /* 02:00 (2 AM) */
  613.                          0,
  614.                          0,
  615.                          0 );
  616.  
  617.                 cvtdate( 0,
  618.                          1,
  619.                          tb->tm_year,
  620.                          10,                /* October */
  621.                          5,                 /* last... */
  622.                          0,                 /* ...Sunday */
  623.                          0,
  624.                          2,                 /* 02:00 (2 AM) */
  625.                          0,
  626.                          0,
  627.                          0 );
  628.             }
  629.         }
  630.  
  631.         /*
  632.          * Handle simple cases first.
  633.          */
  634.         if ( dststart.yd < dstend.yd ) {
  635.             /*
  636.              * Northern hemisphere ordering
  637.              */
  638.             if ( (tb->tm_yday < dststart.yd) || (tb->tm_yday > dstend.yd) )
  639.                 return 0;
  640.             if ( (tb->tm_yday > dststart.yd) && (tb->tm_yday < dstend.yd) )
  641.                 return 1;
  642.         }
  643.         else {
  644.             /*
  645.              * Southern hemisphere ordering
  646.              */
  647.             if ( (tb->tm_yday < dstend.yd) || (tb->tm_yday > dststart.yd) )
  648.                 return 1;
  649.             if ( (tb->tm_yday > dstend.yd) && (tb->tm_yday < dststart.yd) )
  650.                 return 0;
  651.         }
  652.  
  653.         ms = 1000L * (tb->tm_sec + 60L * tb->tm_min + 3600L * tb->tm_hour);
  654.  
  655.         if ( tb->tm_yday == dststart.yd ) {
  656.             if ( ms >= dststart.ms )
  657.                 return 1;
  658.             else
  659.                 return 0;
  660.         }
  661.         else {
  662.             /*
  663.              * tb->tm_yday == dstend.yd
  664.              */
  665.             if ( ms < dstend.ms )
  666.                 return 1;
  667.             else
  668.                 return 0;
  669.         }
  670.  
  671. }
  672.  
  673.  
  674.  
  675. #else  /* _WIN32 */
  676.  
  677. #if defined (_M_MPPC) || defined (_M_M68K)
  678.  
  679.  
  680. #include <cruntime.h>
  681. #include <ctype.h>
  682. #include <ctime.h>
  683. #include <time.h>
  684. #include <stdlib.h>
  685. #include <internal.h>
  686. #include <string.h>
  687. #include <macos\script.h>
  688. #include <macos\osutils.h>
  689.  
  690. /***
  691. *void tzset() - sets timezone information and calc if in daylight time
  692. *
  693. *Purpose:
  694. *       Sets the timezone information from the TZ environment variable
  695. *       and then sets _timezone, _daylight, and _tzname. If we're in daylight
  696. *       time is automatically calculated.
  697. *
  698. *Entry:
  699. *       None, reads TZ environment variable.
  700. *
  701. *Exit:
  702. *       sets _daylight, _timezone, and _tzname global vars, no return value
  703. *
  704. *Exceptions:
  705. *
  706. *******************************************************************************/
  707.  
  708. void __cdecl _tzset (
  709.         void
  710.         )
  711. {
  712.         REG1 char *TZ;
  713.         char *lastTZ=NULL;
  714.         MachineLocation ml;
  715.         long gmtDelta;
  716.         REG2 int negdiff = 0;
  717.  
  718.         /*
  719.          * Fetch the value of the TZ environment variable. If there is no TZ
  720.          * environment variable, or if it is trivial, then the timezone
  721.          * information will be taken from the OS.
  722.          */
  723.  
  724.         if ( (TZ = getenv("TZ")) && (*TZ) ) {
  725.             /*
  726.              * TZ environment variable exists and is non-trivial. See if
  727.              * it is unchanged from a previous _tzset call.
  728.              */
  729.             if ( (lastTZ == NULL) || (strcmp(TZ, lastTZ) != 0) ) {
  730.                 /*
  731.                  * TZ has changed, or there has been no prior _tzset call.
  732.                  * Update lastTZ value.
  733.                  */
  734.                 free(lastTZ);
  735.                 lastTZ = _strdup(TZ);
  736.             }
  737.             else {
  738.                 /*
  739.                  * Timezone environment variable hasn't changed since the
  740.                  * last _tzset call, just return.
  741.                  */
  742.                 return;
  743.  
  744.             }
  745.         }
  746.         else {
  747.             /*
  748.              * The TZ environment variable either does not exist, or is
  749.              * trivial. Therefore, timezone information will be obtained
  750.              * from the OS.
  751.              */
  752.             if ( lastTZ != NULL ) {
  753.                 free(lastTZ);
  754.                 lastTZ = NULL;
  755.             }
  756.             ReadLocation(&ml);
  757.             //get gmtDelta from machinelocation in RAM
  758.             gmtDelta = ml.u.gmtDelta & 0x00ffffff;
  759.  
  760.             if ((gmtDelta >> 23) & 1) //need to sign extend
  761.                 gmtDelta = gmtDelta | 0xff000000;
  762.  
  763.             //set timezone and daylight
  764.             _timezone = - gmtDelta;
  765.             _daylight = (ml.u.dlsDelta ? 1 : 0);
  766.             *_tzname[0] = '\0';
  767.             *_tzname[1] = '\0';
  768.             return;
  769.         }
  770.  
  771.         strncpy(_tzname[0], TZ, 3);
  772.  
  773.         /*
  774.          * time difference is of the form:
  775.          *
  776.          *      [+|-]hh[:mm[:ss]]
  777.          *
  778.          * check minus sign first.
  779.          */
  780.         if ( *(TZ += 3) == '-' ) {
  781.                 negdiff++;
  782.                 TZ++;
  783.         }
  784.  
  785.         /*
  786.          * process, then skip over, the hours
  787.          */
  788.         _timezone = atol(TZ) * 3600L;
  789.  
  790.         while ( (*TZ == '+') || ((*TZ >= '0') && (*TZ <= '9')) ) TZ++;
  791.  
  792.         /*
  793.          * check if minutes were specified
  794.          */
  795.         if ( *TZ == ':' ) {
  796.             /*
  797.              * process, then skip over, the minutes
  798.              */
  799.             _timezone += atol(++TZ) * 60L;
  800.             while ( (*TZ >= '0') && (*TZ <= '9') ) TZ++;
  801.  
  802.             /*
  803.              * check if seconds were specified
  804.              */
  805.             if ( *TZ == ':' ) {
  806.                 /*
  807.                  * process, then skip over, the seconds
  808.                  */
  809.                 _timezone += atol(++TZ);
  810.                 while ( (*TZ >= '0') && (*TZ <= '9') ) TZ++;
  811.             }
  812.         }
  813.         if ( negdiff )
  814.                 _timezone = -_timezone;
  815.  
  816.         /*
  817.          * finally, check for a DST zone suffix
  818.          */
  819.         if (*TZ)
  820.                 strncpy(_tzname[1], TZ, 3);
  821.         else
  822.                 *_tzname[1] = '\0';
  823.         _daylight = *_tzname[1] != '\0';
  824. }
  825.  
  826. /*
  827.  *  _isindst - Tells whether Xenix-type time value falls under DST
  828.  *
  829.  *  This is the rule for years before 1987:
  830.  *  a time is in DST iff it is on or after 02:00:00 on the last Sunday
  831.  *  in April and before 01:00:00 on the last Sunday in October.
  832.  *  This is the rule for years starting with 1987:
  833.  *  a time is in DST iff it is on or after 02:00:00 on the first Sunday
  834.  *  in April and before 01:00:00 on the last Sunday in October.
  835.  *
  836.  *  ENTRY   tb  - 'time' structure holding broken-down time value
  837.  *
  838.  *  RETURN  1 if time represented is in DST, else 0
  839.  */
  840.  
  841. int __cdecl _isindst (
  842.         REG1 struct tm *tb
  843.         )
  844. {
  845.         int mdays;
  846.         REG2 int yr;
  847.         int lastsun;
  848.  
  849.         /* If the month is before April or after October, then we know
  850.          * immediately it can't be DST. */
  851.  
  852.         if (tb->tm_mon < 3 || tb->tm_mon > 9)
  853.                 return(0);
  854.  
  855.         /* If the month is after April and before October then we know
  856.          * immediately it must be DST. */
  857.  
  858.         if (tb->tm_mon > 3 && tb->tm_mon < 9)
  859.                 return(1);
  860.         /*
  861.          * Now for the hard part.  Month is April or October; see if date
  862.          * falls between appropriate Sundays.
  863.          */
  864.  
  865.         /*
  866.          * The objective for years before 1987 (after 1986) is to determine
  867.          * if the day is on or after 2:00 am on the last (first) Sunday in
  868.          * April, or before 1:00 am on the last Sunday in October.
  869.          *
  870.          * We know the year-day (0..365) of the current time structure. We must
  871.          * determine the year-day of the last (first) Sunday in this month,
  872.          * April or October, and then do the comparison.
  873.          *
  874.          * To determine the year-day of the last Sunday, we do the following:
  875.          *      1. Get the year-day of the last day of the current month (Apr
  876.          *         or Oct)
  877.          *      2. Determine the week-day number of #1,
  878.          *         which is defined as 0 = Sun, 1 = Mon, ... 6 = Sat
  879.          *      3. Subtract #2 from #1
  880.          *
  881.          * To determine the year-day of the first Sunday, we do the following:
  882.          *      1. Get the year-day of the 7th day of the current month (April)
  883.          *      2. Determine the week-day number of #1,
  884.          *         which is defined as 0 = Sun, 1 = Mon, ... 6 = Sat
  885.          *      3. Subtract #2 from #1
  886.          */
  887.  
  888.         yr = tb->tm_year + 1900;    /* To see if this is a leap-year */
  889.  
  890.         /* First we get #1. The year-days for each month are stored in _days[]
  891.          * they're all off by -1 */
  892.  
  893.         if (yr > 1986 && tb->tm_mon == 3)
  894.                 mdays = 7 + _days[tb->tm_mon];
  895.         else
  896.                 mdays = _days[tb->tm_mon+1];
  897.  
  898.         /* if this is a leap-year, add an extra day */
  899.         if (!(yr & 3))
  900.                 mdays++;
  901.  
  902.         /* mdays now has #1 */
  903.  
  904.         yr = tb->tm_year - 70;
  905.  
  906.         /* Now get #2.  We know the week-day number of the beginning of the
  907.          * epoch, Jan. 1, 1970, which is defined as the constant _BASE_DOW.  We
  908.          * then add the number of days that have passed from _BASE_DOW to the day
  909.          * of #2
  910.          *      mdays + 365 * yr
  911.          * correct for the leap years which intervened
  912.          *      + (yr + 1)/ 4
  913.          * and take the result mod 7, except that 0 must be mapped to 7.
  914.          * This is #2, which we then subtract from #1, mdays
  915.          */
  916.  
  917.         lastsun = mdays - ((mdays + 365*yr + ((yr+1)/4) + _BASE_DOW) % 7);
  918.  
  919.         /* Now we know 1 and 3; we're golden: */
  920.  
  921.         return (tb->tm_mon==3
  922.                 ? (tb->tm_yday > lastsun ||
  923.                 (tb->tm_yday == lastsun && tb->tm_hour >= 2))
  924.                 : (tb->tm_yday < lastsun ||
  925.                 (tb->tm_yday == lastsun && tb->tm_hour < 1)));
  926. }
  927.  
  928.  
  929.  
  930.  
  931. #endif  /* defined (_M_MPPC) || defined (_M_M68K) */
  932.  
  933. #endif  /* _WIN32 */
  934.