Subversion Repositories Kolibri OS

Rev

Rev 4872 | Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * mktm_r.c
  3.  * Original Author:     Adapted from tzcode maintained by Arthur David Olson.
  4.  * Modifications:       Changed to mktm_r and added __tzcalc_limits - 04/10/02, Jeff Johnston
  5.  *                      Fixed bug in mday computations - 08/12/04, Alex Mogilnikov <alx@intellectronika.ru>
  6.  *                      Fixed bug in __tzcalc_limits - 08/12/04, Alex Mogilnikov <alx@intellectronika.ru>
  7.  *
  8.  * Converts the calendar time pointed to by tim_p into a broken-down time
  9.  * expressed as local time. Returns a pointer to a structure containing the
  10.  * broken-down time.
  11.  */
  12.  
  13. #include <stdlib.h>
  14. #include <time.h>
  15. #include "local.h"
  16.  
  17. static _CONST int mon_lengths[2][MONSPERYEAR] = {
  18.   {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
  19.   {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
  20. } ;
  21.  
  22. static _CONST int year_lengths[2] = {
  23.   365,
  24.   366
  25. } ;
  26.  
  27. struct tm *
  28. _DEFUN (_mktm_r, (tim_p, res, is_gmtime),
  29.         _CONST time_t * tim_p _AND
  30.         struct tm *res _AND
  31.         int is_gmtime)
  32. {
  33.   long days, rem;
  34.   time_t lcltime;
  35.   int y;
  36.   int yleap;
  37.   _CONST int *ip;
  38.    __tzinfo_type *tz = __gettzinfo ();
  39.  
  40.   /* base decision about std/dst time on current time */
  41.   lcltime = *tim_p;
  42.    
  43.   days = ((long)lcltime) / SECSPERDAY;
  44.   rem = ((long)lcltime) % SECSPERDAY;
  45.   while (rem < 0)
  46.     {
  47.       rem += SECSPERDAY;
  48.       --days;
  49.     }
  50.   while (rem >= SECSPERDAY)
  51.     {
  52.       rem -= SECSPERDAY;
  53.       ++days;
  54.     }
  55.  
  56.   /* compute hour, min, and sec */  
  57.   res->tm_hour = (int) (rem / SECSPERHOUR);
  58.   rem %= SECSPERHOUR;
  59.   res->tm_min = (int) (rem / SECSPERMIN);
  60.   res->tm_sec = (int) (rem % SECSPERMIN);
  61.  
  62.   /* compute day of week */
  63.   if ((res->tm_wday = ((EPOCH_WDAY + days) % DAYSPERWEEK)) < 0)
  64.     res->tm_wday += DAYSPERWEEK;
  65.  
  66.   /* compute year & day of year */
  67.   y = EPOCH_YEAR;
  68.   if (days >= 0)
  69.     {
  70.       for (;;)
  71.         {
  72.           yleap = isleap(y);
  73.           if (days < year_lengths[yleap])
  74.             break;
  75.           y++;
  76.           days -= year_lengths[yleap];
  77.         }
  78.     }
  79.   else
  80.     {
  81.       do
  82.         {
  83.           --y;
  84.           yleap = isleap(y);
  85.           days += year_lengths[yleap];
  86.         } while (days < 0);
  87.     }
  88.  
  89.   res->tm_year = y - YEAR_BASE;
  90.   res->tm_yday = days;
  91.   ip = mon_lengths[yleap];
  92.   for (res->tm_mon = 0; days >= ip[res->tm_mon]; ++res->tm_mon)
  93.     days -= ip[res->tm_mon];
  94.   res->tm_mday = days + 1;
  95.  
  96.   if (!is_gmtime)
  97.     {
  98.       long offset;
  99.       int hours, mins, secs;
  100.  
  101.       TZ_LOCK;
  102.       if (_daylight)
  103.         {
  104.           if (y == tz->__tzyear || __tzcalc_limits (y))
  105.             res->tm_isdst = (tz->__tznorth
  106.                              ? (*tim_p >= tz->__tzrule[0].change
  107.                                 && *tim_p < tz->__tzrule[1].change)
  108.                              : (*tim_p >= tz->__tzrule[0].change
  109.                                 || *tim_p < tz->__tzrule[1].change));
  110.           else
  111.             res->tm_isdst = -1;
  112.         }
  113.       else
  114.         res->tm_isdst = 0;
  115.  
  116.       offset = (res->tm_isdst == 1
  117.                   ? tz->__tzrule[1].offset
  118.                   : tz->__tzrule[0].offset);
  119.  
  120.       hours = (int) (offset / SECSPERHOUR);
  121.       offset = offset % SECSPERHOUR;
  122.      
  123.       mins = (int) (offset / SECSPERMIN);
  124.       secs = (int) (offset % SECSPERMIN);
  125.  
  126.       res->tm_sec -= secs;
  127.       res->tm_min -= mins;
  128.       res->tm_hour -= hours;
  129.  
  130.       if (res->tm_sec >= SECSPERMIN)
  131.         {
  132.           res->tm_min += 1;
  133.           res->tm_sec -= SECSPERMIN;
  134.         }
  135.       else if (res->tm_sec < 0)
  136.         {
  137.           res->tm_min -= 1;
  138.           res->tm_sec += SECSPERMIN;
  139.         }
  140.       if (res->tm_min >= MINSPERHOUR)
  141.         {
  142.           res->tm_hour += 1;
  143.           res->tm_min -= MINSPERHOUR;
  144.         }
  145.       else if (res->tm_min < 0)
  146.         {
  147.           res->tm_hour -= 1;
  148.           res->tm_min += MINSPERHOUR;
  149.         }
  150.       if (res->tm_hour >= HOURSPERDAY)
  151.         {
  152.           ++res->tm_yday;
  153.           ++res->tm_wday;
  154.           if (res->tm_wday > 6)
  155.             res->tm_wday = 0;
  156.           ++res->tm_mday;
  157.           res->tm_hour -= HOURSPERDAY;
  158.           if (res->tm_mday > ip[res->tm_mon])
  159.             {
  160.               res->tm_mday -= ip[res->tm_mon];
  161.               res->tm_mon += 1;
  162.               if (res->tm_mon == 12)
  163.                 {
  164.                   res->tm_mon = 0;
  165.                   res->tm_year += 1;
  166.                   res->tm_yday = 0;
  167.                 }
  168.             }
  169.         }
  170.        else if (res->tm_hour < 0)
  171.         {
  172.           res->tm_yday -= 1;
  173.           res->tm_wday -= 1;
  174.           if (res->tm_wday < 0)
  175.             res->tm_wday = 6;
  176.           res->tm_mday -= 1;
  177.           res->tm_hour += 24;
  178.           if (res->tm_mday == 0)
  179.             {
  180.               res->tm_mon -= 1;
  181.               if (res->tm_mon < 0)
  182.                 {
  183.                   res->tm_mon = 11;
  184.                   res->tm_year -= 1;
  185.                   res->tm_yday = 364 + isleap(res->tm_year + 1900);
  186.                 }
  187.               res->tm_mday = ip[res->tm_mon];
  188.             }
  189.         }
  190.       TZ_UNLOCK;
  191.     }
  192.   else
  193.     res->tm_isdst = 0;
  194.  
  195.   return (res);
  196. }
  197.  
  198. int
  199. _DEFUN (__tzcalc_limits, (year),
  200.         int year)
  201. {
  202.   int days, year_days, years;
  203.   int i, j;
  204.   __tzinfo_type *tz = __gettzinfo ();
  205.  
  206.   if (year < EPOCH_YEAR)
  207.     return 0;
  208.  
  209.   tz->__tzyear = year;
  210.  
  211.   years = (year - EPOCH_YEAR);
  212.  
  213.   year_days = years * 365 +
  214.     (years - 1 + EPOCH_YEARS_SINCE_LEAP) / 4 - (years - 1 + EPOCH_YEARS_SINCE_CENTURY) / 100 +
  215.     (years - 1 + EPOCH_YEARS_SINCE_LEAP_CENTURY) / 400;
  216.  
  217.   for (i = 0; i < 2; ++i)
  218.     {
  219.         if (tz->__tzrule[i].ch == 'J') {
  220.         /* The Julian day n (1 <= n <= 365). */
  221.         days = year_days + tz->__tzrule[i].d +
  222.                 (isleap(year) && tz->__tzrule[i].d >= 60);
  223.         /* Convert to yday */
  224.         --days;
  225.         } else if (tz->__tzrule[i].ch == 'D')
  226.         days = year_days + tz->__tzrule[i].d;
  227.       else
  228.         {
  229.           int yleap = isleap(year);
  230.           int m_day, m_wday, wday_diff;
  231.           _CONST int *ip = mon_lengths[yleap];
  232.  
  233.           days = year_days;
  234.  
  235.           for (j = 1; j < tz->__tzrule[i].m; ++j)
  236.             days += ip[j-1];
  237.  
  238.           m_wday = (EPOCH_WDAY + days) % DAYSPERWEEK;
  239.          
  240.           wday_diff = tz->__tzrule[i].d - m_wday;
  241.           if (wday_diff < 0)
  242.             wday_diff += DAYSPERWEEK;
  243.           m_day = (tz->__tzrule[i].n - 1) * DAYSPERWEEK + wday_diff;
  244.  
  245.           while (m_day >= ip[j-1])
  246.             m_day -= DAYSPERWEEK;
  247.  
  248.           days += m_day;
  249.         }
  250.  
  251.       /* store the change-over time in GMT form by adding offset */
  252.       tz->__tzrule[i].change = days * SECSPERDAY +
  253.                                 tz->__tzrule[i].s + tz->__tzrule[i].offset;
  254.     }
  255.  
  256.   tz->__tznorth = (tz->__tzrule[0].change < tz->__tzrule[1].change);
  257.  
  258.   return 1;
  259. }
  260.