Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /****************************************************************************
  2. *
  3. *                            Open Watcom Project
  4. *
  5. *    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
  6. *
  7. *  ========================================================================
  8. *
  9. *    This file contains Original Code and/or Modifications of Original
  10. *    Code as defined in and that are subject to the Sybase Open Watcom
  11. *    Public License version 1.0 (the 'License'). You may not use this file
  12. *    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
  13. *    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
  14. *    provided with the Original Code and Modifications, and is also
  15. *    available at www.sybase.com/developer/opensource.
  16. *
  17. *    The Original Code and all software distributed under the License are
  18. *    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  19. *    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
  20. *    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
  21. *    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
  22. *    NON-INFRINGEMENT. Please see the License for the specific language
  23. *    governing rights and limitations under the License.
  24. *
  25. *  ========================================================================
  26. *
  27. * Description:  time utility functions
  28. *
  29. ****************************************************************************/
  30.  
  31. #include "variety.h"
  32. #include <time.h>
  33. #include "rtdata.h"
  34. #include "timedata.h"
  35.  
  36. static int time_less( const struct tm *t1, const struct tm *t2 );
  37.  
  38. static int calc_yday( const struct tm *timetm, int year )
  39. {
  40.     struct tm   tmptm;
  41.     int         month_days;
  42.     int         first_wday;
  43.     int         nth_week;
  44.     short const *diyr;
  45.  
  46.     if( timetm->tm_isdst == 0 ) { // M.m.n.d form
  47.         diyr = ( __leapyear( ( unsigned ) year + 1900 ) ) ? __dilyr : __diyr;
  48.         month_days = diyr[timetm->tm_mon + 1] - diyr[timetm->tm_mon];
  49.         tmptm.tm_sec   = 0;
  50.         tmptm.tm_min   = 0;
  51.         tmptm.tm_hour  = 0;
  52.         tmptm.tm_mday  = 1;
  53.         tmptm.tm_mon   = timetm->tm_mon;
  54.         tmptm.tm_year  = year;
  55.         tmptm.tm_isdst = 0;
  56.         ( void ) mktime( &tmptm );
  57.         first_wday = ( timetm->tm_wday - tmptm.tm_wday + 7 ) % 7;
  58.         if( timetm->tm_mday == 5 ) {
  59.             if( ( 1 + first_wday + ( timetm->tm_mday - 1 ) * 7 ) > month_days )
  60.                 nth_week = timetm->tm_mday - 2;   // fifth req. weekday does not exist
  61.             else
  62.                 nth_week = timetm->tm_mday - 1;
  63.         } else
  64.             nth_week = timetm->tm_mday - 1;
  65.         return( tmptm.tm_yday + first_wday + nth_week * 7 );
  66.     }
  67.     if( timetm->tm_isdst == 1 )  /* if Jn form */
  68.         return( timetm->tm_yday - 1 );
  69.     return( timetm->tm_yday );
  70. }
  71.  
  72. /* determine if in souther hemisphere -> start is after end */
  73. static int check_order( const struct tm *start, const struct tm *end, int year )
  74. {
  75.     int start_day;
  76.     int end_day;
  77.  
  78.     /* these quick checks should always be enough */
  79.     if( ( start->tm_isdst == 0 ) && ( end->tm_isdst == 0 ) ) { // M.m.n.d form
  80.         if( start->tm_mon > end->tm_mon )
  81.             return( 1 );
  82.         if( start->tm_mon < end->tm_mon )
  83.             return( 0 );
  84.     }
  85.     /* start/end of daylight savings time is in the same month (rare case) */
  86.     /* these are *expensive* calculations under NT since 2 TZ checks must be done */
  87.     start_day = calc_yday( start, year );
  88.     end_day = calc_yday( end, year );
  89.     if( start_day > end_day )
  90.         return( 1 );
  91.     return( 0 );
  92. }
  93.  
  94. /* determine if daylight savings time */
  95. int __isindst( struct tm *t )
  96. {
  97.     int                 month;
  98.     int                 dst;
  99.     int                 n1;
  100.     int                 n2;
  101.     int                 month_days;
  102.     int                 time_check;
  103.     int                 south;
  104.     struct tm const     *start;
  105.     struct tm const     *end;
  106.     short const         *diyr;
  107.  
  108.     // already determined -- if we are sure
  109.     if( t->tm_isdst >= 0 )
  110.         return( t->tm_isdst );
  111.     dst = 0;
  112.     // if zone doesn't have a daylight savings period
  113.     if( _RWD_daylight == 0 )
  114.         return( t->tm_isdst = dst );
  115.     //  // check for no daylight savings time rule
  116.     //  if( tzname[1][0] == '\0' ) {    // doesn't work since Win32 says
  117.     //      return( t->tm_isdst = dst );// daylight zone name = standard zone name
  118.     //  }
  119.  
  120.     south = check_order( &_RWD_start_dst, &_RWD_end_dst, t->tm_year );
  121.     if( south ) {
  122.         // if southern hemisphere
  123.         // invert start and end dates and then invert return value
  124.         start = &_RWD_end_dst;
  125.         end = &_RWD_start_dst;
  126.     } else {
  127.         start = &_RWD_start_dst;
  128.         end = &_RWD_end_dst;
  129.     }
  130.     month = t->tm_mon;
  131.     diyr = ( __leapyear( ( unsigned ) t->tm_year + 1900 ) ) ? __dilyr : __diyr;
  132.     month_days = diyr[month + 1] - diyr[month];
  133.     time_check = 0;
  134.     /*
  135.      * M.m.n.d form
  136.      * m = start->tm_mon  (month 0-11)
  137.      * n = start->tm_mday (n'th week day 1-5)
  138.      * d = start->tm_wday (week day 0-6)
  139.      */
  140.     if( start->tm_isdst == 0 ) { /* if Mm.n.d form */
  141.         if( month > start->tm_mon )
  142.             dst = 1;                        /* assume dst for now */
  143.         else if( month == start->tm_mon ) {
  144.             /* calculate for current day */
  145.             n1 = t->tm_mday - ( t->tm_wday + 7 - start->tm_wday ) % 7;
  146.             /* calculate for previous day */
  147.             n2 = t->tm_mday - 1 - ( t->tm_wday - 1 + 7 - start->tm_wday ) % 7;
  148.             //  n_ stands for the day of the month that is past &&
  149.             //  is closest to today && is the required weekday
  150.             if( start->tm_mday == 5 ) {
  151.                 if( n1 > month_days - 7 ) {
  152.                     dst = 1;                /* assume dst for now */
  153.                     if( n2 <= month_days - 7 )
  154.                         time_check = 1;
  155.                 }
  156.             } else {
  157.                 if( n1 >= 7 * ( start->tm_mday - 1 ) + 1 ) {
  158.                     dst = 1;                /* assume dst for now */
  159.                     if( n2 < 7 * ( start->tm_mday - 1 ) + 1 )
  160.                         time_check = 1;
  161.                 }
  162.             }
  163.         }
  164.     } else {
  165.         n1 = start->tm_yday;
  166.         if( start->tm_isdst == 1 ) { /* if Jn form */
  167.             if( __leapyear( ( unsigned ) t->tm_year + 1900 ) ) {
  168.                 if( n1 > __diyr[2] )
  169.                     n1++;      /* past Feb 28 */
  170.             }
  171.             n1--;
  172.         }
  173.         if( t->tm_yday >= n1 ) {
  174.             dst = 1;                        /* assume dst for now */
  175.             if( t->tm_yday == n1 )
  176.                 time_check = 1;
  177.         }
  178.     }
  179.     /* if it is the day for a switch-over then check the time too */
  180.     if( time_check )
  181.         dst = !time_less( t, start );
  182.  
  183.     /* if we are certain that it is before daylight saving then return */
  184.     if( dst == 0 ) {
  185.         if( south )
  186.             dst = south - dst;  /* invert value of dst */
  187.         return( t->tm_isdst = dst );
  188.     }
  189.  
  190.     /* now see if it is after daylight saving */
  191.     time_check = 0;
  192.     if( end->tm_isdst == 0 ) { /* if Mm.n.d form */
  193.         if( month > end->tm_mon )
  194.             dst = 0;                        /* not dst */
  195.         else if( month == end->tm_mon ) {
  196.             dst = 0;
  197.             /* calculate for current day */
  198.             n1 = t->tm_mday - ( t->tm_wday + 7 - end->tm_wday ) % 7;
  199.             /* calculate for previous day */
  200.             n2 = t->tm_mday - 1 -
  201.                 ( t->tm_wday - 1 + 7 - end->tm_wday ) % 7;
  202.             if( end->tm_mday == 5 ) {
  203.                 if( n1 <= month_days - 7 )
  204.                     dst = 1;
  205.                 else if( n2 <= month_days - 7 )
  206.                     time_check = 1;
  207.             } else {
  208.                 if( n1 < 7 * ( end->tm_mday - 1 ) + 1 )
  209.                     dst = 1;
  210.                 else if( n2 < 7 * ( end->tm_mday - 1 ) + 1 )
  211.                     time_check = 1;
  212.             }
  213.         }
  214.     } else {
  215.         n1 = end->tm_yday;
  216.         if( end->tm_isdst == 1 ) { /* if Jn form */
  217.             if( __leapyear( ( unsigned ) t->tm_year + 1900 ) ) {
  218.                 if( n1 > __diyr[2] )
  219.                     n1++;      /* past Feb 28 */
  220.             }
  221.             n1--;
  222.         }
  223.         if( t->tm_yday >= n1 ) {
  224.             dst = 0;
  225.             if( t->tm_yday == n1 )
  226.                 time_check = 1;
  227.         }
  228.     }
  229.     /* if it is the day for a switch-over then check the time too */
  230.     if( time_check )
  231.         dst = time_less( t, end );
  232.     if( south )
  233.         dst = south - dst;      /* invert value of dst */
  234.     return( t->tm_isdst = dst );
  235. }
  236.  
  237. static int time_less( const struct tm *t1, const struct tm *t2 )
  238. {
  239.     int before;
  240.  
  241.     before = 0;
  242.     if( t1->tm_hour < t2->tm_hour )
  243.         before = 1;
  244.     else if( t1->tm_hour == t2->tm_hour ) {
  245.         if( t1->tm_min < t2->tm_min
  246.         ||  t1->tm_min == t2->tm_min && t1->tm_sec < t2->tm_sec )
  247.                 before = 1;
  248.     }
  249.     return( before );
  250. }
  251.