1 /* Copyright (c) 2002 Arthur David Olson */
2 /*
3  * tzcalc_limits.c
4  * Original Author: Adapted from tzcode maintained by Arthur David Olson.
5  * Modifications:
6  * - Changed to mktm_r and added __tzcalc_limits - 04/10/02, Jeff Johnston
7  * - Fixed bug in mday computations - 08/12/04, Alex Mogilnikov <alx@intellectronika.ru>
8  * - Fixed bug in __tzcalc_limits - 08/12/04, Alex Mogilnikov <alx@intellectronika.ru>
9  * - Moved __tzcalc_limits() to separate file - 05/09/14, Freddie Chopin <freddie_chopin@op.pl>
10  */
11 
12 #include "local.h"
13 
14 int
__tzcalc_limits(int year)15 __tzcalc_limits (int year)
16 {
17   int days, year_days, years;
18   int i, j;
19   __tzinfo_type *const tz = __gettzinfo ();
20 
21   if (year < EPOCH_YEAR)
22     return 0;
23 
24   tz->__tzyear = year;
25 
26   years = (year - EPOCH_YEAR);
27 
28   year_days = years * 365 +
29     (years - 1 + EPOCH_YEARS_SINCE_LEAP) / 4 -
30     (years - 1 + EPOCH_YEARS_SINCE_CENTURY) / 100 +
31     (years - 1 + EPOCH_YEARS_SINCE_LEAP_CENTURY) / 400;
32 
33   for (i = 0; i < 2; ++i)
34     {
35       if (tz->__tzrule[i].ch == 'J')
36 	{
37 	  /* The Julian day n (1 <= n <= 365). */
38 	  days = year_days + tz->__tzrule[i].d +
39 	    (isleap(year) && tz->__tzrule[i].d >= 60);
40 	  /* Convert to yday */
41 	  --days;
42 	}
43       else if (tz->__tzrule[i].ch == 'D')
44 	days = year_days + tz->__tzrule[i].d;
45       else
46 	{
47 	  const int yleap = isleap(year);
48 	  int m_day, m_wday, wday_diff;
49 	  const uint8_t *const ip = __month_lengths[yleap];
50 
51 	  days = year_days;
52 
53 	  for (j = 1; j < tz->__tzrule[i].m; ++j)
54 	    days += ip[j-1];
55 
56 	  m_wday = (EPOCH_WDAY + days) % DAYSPERWEEK;
57 
58 	  wday_diff = tz->__tzrule[i].d - m_wday;
59 	  if (wday_diff < 0)
60 	    wday_diff += DAYSPERWEEK;
61 	  m_day = (tz->__tzrule[i].n - 1) * DAYSPERWEEK + wday_diff;
62 
63 	  while (m_day >= ip[j-1])
64 	    m_day -= DAYSPERWEEK;
65 
66 	  days += m_day;
67 	}
68 
69       /* store the change-over time in GMT form by adding offset */
70       tz->__tzrule[i].change = (time_t) days * SECSPERDAY +
71       tz->__tzrule[i].s + tz->__tzrule[i].offset;
72     }
73 
74   tz->__tznorth = (tz->__tzrule[0].change < tz->__tzrule[1].change);
75 
76   return 1;
77 }
78