** Given a year, a rule, and the offset from UT at the time that rule takes ** effect, calculate the year-relative time that rule takes effect. */
| 876 | ** effect, calculate the year-relative time that rule takes effect. |
| 877 | */ |
| 878 | static int_fast32_t transtime(const int year, const struct rule *const rulep, const int_fast32_t offset) { |
| 879 | int leapyear; |
| 880 | int_fast32_t value; |
| 881 | int d, m1, yy0, yy1, yy2, dow; |
| 882 | |
| 883 | INITIALIZE(value); |
| 884 | leapyear = isleap(year); |
| 885 | switch (rulep->r_type) { |
| 886 | |
| 887 | case JULIAN_DAY: |
| 888 | /* |
| 889 | ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap |
| 890 | ** years. |
| 891 | ** In non-leap years, or if the day number is 59 or less, just |
| 892 | ** add SECSPERDAY times the day number-1 to the time of |
| 893 | ** January 1, midnight, to get the day. |
| 894 | */ |
| 895 | value = (rulep->r_day - 1) * SECSPERDAY; |
| 896 | if (leapyear && rulep->r_day >= 60) |
| 897 | value += SECSPERDAY; |
| 898 | break; |
| 899 | |
| 900 | case DAY_OF_YEAR: |
| 901 | /* |
| 902 | ** n - day of year. |
| 903 | ** Just add SECSPERDAY times the day number to the time of |
| 904 | ** January 1, midnight, to get the day. |
| 905 | */ |
| 906 | value = rulep->r_day * SECSPERDAY; |
| 907 | break; |
| 908 | |
| 909 | case MONTH_NTH_DAY_OF_WEEK: |
| 910 | /* |
| 911 | ** Mm.n.d - nth "dth day" of month m. |
| 912 | */ |
| 913 | |
| 914 | /* |
| 915 | ** Use Zeller's Congruence to get day-of-week of first day of |
| 916 | ** month. |
| 917 | */ |
| 918 | m1 = (rulep->r_mon + 9) % 12 + 1; |
| 919 | yy0 = (rulep->r_mon <= 2) ? (year - 1) : year; |
| 920 | yy1 = yy0 / 100; |
| 921 | yy2 = yy0 % 100; |
| 922 | dow = ((26 * m1 - 2) / 10 + |
| 923 | 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7; |
| 924 | if (dow < 0) |
| 925 | dow += DAYSPERWEEK; |
| 926 | |
| 927 | /* |
| 928 | ** "dow" is the day-of-week of the first day of the month. Get |
| 929 | ** the day-of-month (zero-origin) of the first "dow" day of the |
| 930 | ** month. |
| 931 | */ |
| 932 | d = rulep->r_day - dow; |
| 933 | if (d < 0) |
| 934 | d += DAYSPERWEEK; |
| 935 | for (int i = 1; i < rulep->r_week; ++i) { |