Subversion Repositories Kolibri OS

Rev

Rev 4921 | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. /*
  2.  * gmtime_r.c
  3.  * Original Author: Adapted from tzcode maintained by Arthur David Olson.
  4.  * Modifications:
  5.  * - Changed to mktm_r and added __tzcalc_limits - 04/10/02, Jeff Johnston
  6.  * - Fixed bug in mday computations - 08/12/04, Alex Mogilnikov <alx@intellectronika.ru>
  7.  * - Fixed bug in __tzcalc_limits - 08/12/04, Alex Mogilnikov <alx@intellectronika.ru>
  8.  * - Move code from _mktm_r() to gmtime_r() - 05/09/14, Freddie Chopin <freddie_chopin@op.pl>
  9.  * - Fixed bug in calculations for dates after year 2069 or before year 1901. Ideas for
  10.  *   solution taken from musl's __secs_to_tm() - 07/12/2014, Freddie Chopin
  11.  *   <freddie_chopin@op.pl>
  12.  * - Use faster algorithm from civil_from_days() by Howard Hinnant - 12/06/2014,
  13.  * Freddie Chopin <freddie_chopin@op.pl>
  14.  *
  15.  * Converts the calendar time pointed to by tim_p into a broken-down time
  16.  * expressed as local time. Returns a pointer to a structure containing the
  17.  * broken-down time.
  18.  */
  19.  
  20. #include "local.h"
  21.  
  22. /* Move epoch from 01.01.1970 to 01.03.0000 (yes, Year 0) - this is the first
  23.  * day of a 400-year long "era", right after additional day of leap year.
  24.  * This adjustment is required only for date calculation, so instead of
  25.  * modifying time_t value (which would require 64-bit operations to work
  26.  * correctly) it's enough to adjust the calculated number of days since epoch.
  27.  */
  28. #define EPOCH_ADJUSTMENT_DAYS   719468L
  29. /* year to which the adjustment was made */
  30. #define ADJUSTED_EPOCH_YEAR     0
  31. /* 1st March of year 0 is Wednesday */
  32. #define ADJUSTED_EPOCH_WDAY     3
  33. /* there are 97 leap years in 400-year periods. ((400 - 97) * 365 + 97 * 366) */
  34. #define DAYS_PER_ERA            146097L
  35. /* there are 24 leap years in 100-year periods. ((100 - 24) * 365 + 24 * 366) */
  36. #define DAYS_PER_CENTURY        36524L
  37. /* there is one leap year every 4 years */
  38. #define DAYS_PER_4_YEARS        (3 * 365 + 366)
  39. /* number of days in a non-leap year */
  40. #define DAYS_PER_YEAR           365
  41. /* number of days in January */
  42. #define DAYS_IN_JANUARY         31
  43. /* number of days in non-leap February */
  44. #define DAYS_IN_FEBRUARY        28
  45. /* number of years per era */
  46. #define YEARS_PER_ERA           400
  47.  
  48. struct tm *
  49. _DEFUN (gmtime_r, (tim_p, res),
  50.         _CONST time_t *__restrict tim_p _AND
  51.         struct tm *__restrict res)
  52. {
  53.   long days, rem;
  54.   _CONST time_t lcltime = *tim_p;
  55.   int era, weekday, year;
  56.   unsigned erayear, yearday, month, day;
  57.   unsigned long eraday;
  58.  
  59.   days = ((long)lcltime) / SECSPERDAY + EPOCH_ADJUSTMENT_DAYS;
  60.   rem = ((long)lcltime) % SECSPERDAY;
  61.   if (rem < 0)
  62.     {
  63.       rem += SECSPERDAY;
  64.       --days;
  65.     }
  66.  
  67.   /* compute hour, min, and sec */
  68.   res->tm_hour = (int) (rem / SECSPERHOUR);
  69.   rem %= SECSPERHOUR;
  70.   res->tm_min = (int) (rem / SECSPERMIN);
  71.   res->tm_sec = (int) (rem % SECSPERMIN);
  72.  
  73.   /* compute day of week */
  74.   if ((weekday = ((ADJUSTED_EPOCH_WDAY + days) % DAYSPERWEEK)) < 0)
  75.     weekday += DAYSPERWEEK;
  76.   res->tm_wday = weekday;
  77.  
  78.   /* compute year, month, day & day of year */
  79.   /* for description of this algorithm see
  80.    * http://howardhinnant.github.io/date_algorithms.html#civil_from_days */
  81.   era = (days >= 0 ? days : days - (DAYS_PER_ERA - 1)) / DAYS_PER_ERA;
  82.   eraday = days - era * DAYS_PER_ERA;   /* [0, 146096] */
  83.   erayear = (eraday - eraday / (DAYS_PER_4_YEARS - 1) + eraday / DAYS_PER_CENTURY -
  84.       eraday / (DAYS_PER_ERA - 1)) / 365;       /* [0, 399] */
  85.   yearday = eraday - (DAYS_PER_YEAR * erayear + erayear / 4 - erayear / 100);   /* [0, 365] */
  86.   month = (5 * yearday + 2) / 153;      /* [0, 11] */
  87.   day = yearday - (153 * month + 2) / 5 + 1;    /* [1, 31] */
  88.   month += month < 10 ? 2 : -10;
  89.   year = ADJUSTED_EPOCH_YEAR + erayear + era * YEARS_PER_ERA + (month <= 1);
  90.  
  91.   res->tm_yday = yearday >= DAYS_PER_YEAR - DAYS_IN_JANUARY - DAYS_IN_FEBRUARY ?
  92.       yearday - (DAYS_PER_YEAR - DAYS_IN_JANUARY - DAYS_IN_FEBRUARY) :
  93.       yearday + DAYS_IN_JANUARY + DAYS_IN_FEBRUARY + isleap(erayear);
  94.   res->tm_year = year - YEAR_BASE;
  95.   res->tm_mon = month;
  96.   res->tm_mday = day;
  97.  
  98.   res->tm_isdst = 0;
  99.  
  100.   return (res);
  101. }
  102.