|
4 | 4 |
|
5 | 5 | namespace Roukmoute\Polyfill\Calendar; |
6 | 6 |
|
7 | | -final class Jewish |
| 7 | +/** |
| 8 | + * Jewish Serial Day Number (SDN) conversions |
| 9 | + * |
| 10 | + * @see https://github.com/php/php-src/blob/PHP-8.1.9/ext/calendar/jewish.c |
| 11 | + */ |
| 12 | +final class Jewish implements SDNConversions |
8 | 13 | { |
9 | 14 | public const HALAKIM_PER_HOUR = 1080; |
10 | 15 | public const HALAKIM_PER_DAY = 25920; |
@@ -85,17 +90,110 @@ public static function jewishtojd(int $month, int $day, int $year): int |
85 | 90 |
|
86 | 91 | $lengthOfAdarIAndII = (self::getMonthsInYear(($year - 1) % 19) == 12) ? 29 : 59; |
87 | 92 |
|
88 | | - if ($month === 4) { |
89 | | - $sdn = $tishri1After + $day - $lengthOfAdarIAndII - 237; |
90 | | - } elseif ($month === 5) { |
91 | | - $sdn = $tishri1After + $day - $lengthOfAdarIAndII - 208; |
| 93 | + $sdn = self::calSDN($month, (int) $tishri1After, $day, $lengthOfAdarIAndII); |
| 94 | + break; |
| 95 | + |
| 96 | + default: |
| 97 | + /* It is Adar II or later - don't need the year length. */ |
| 98 | + self::findStartOfYear($year + 1, $metonicCycle, $metonicYear, $moladDay, $moladHalakim, $tishri1After); |
| 99 | + |
| 100 | + switch ($month) { |
| 101 | + case 7: |
| 102 | + $sdn = $tishri1After + $day - 207; |
| 103 | + break; |
| 104 | + case 8: |
| 105 | + $sdn = $tishri1After + $day - 178; |
| 106 | + break; |
| 107 | + case 9: |
| 108 | + $sdn = $tishri1After + $day - 148; |
| 109 | + break; |
| 110 | + case 10: |
| 111 | + $sdn = $tishri1After + $day - 119; |
| 112 | + break; |
| 113 | + case 11: |
| 114 | + $sdn = $tishri1After + $day - 89; |
| 115 | + break; |
| 116 | + case 12: |
| 117 | + $sdn = $tishri1After + $day - 60; |
| 118 | + break; |
| 119 | + case 13: |
| 120 | + $sdn = $tishri1After + $day - 30; |
| 121 | + break; |
| 122 | + default: |
| 123 | + return 0; |
| 124 | + } |
| 125 | + } |
| 126 | + |
| 127 | + return $sdn + self::JEWISH_SDN_OFFSET; |
| 128 | + } |
| 129 | + |
| 130 | + /** |
| 131 | + * Convert a Jewish republican calendar date to a SDN. |
| 132 | + * {@inheritDoc} |
| 133 | + */ |
| 134 | + public static function toSDN(int $year, int $month, int $day): int |
| 135 | + { |
| 136 | + $metonicCycle = 0; |
| 137 | + $metonicYear = 0; |
| 138 | + $tishri1 = 0; |
| 139 | + $tishri1After = 0; |
| 140 | + $moladDay = 0; |
| 141 | + $moladHalakim = 0; |
| 142 | + |
| 143 | + if ($year <= 0 || $day <= 0 || $day > 30) { |
| 144 | + return 0; |
| 145 | + } |
| 146 | + switch ($month) { |
| 147 | + case 1: |
| 148 | + case 2: |
| 149 | + /* It is Tishri or Heshvan - don't need the $year length. */ |
| 150 | + self::findStartOfYear($year, $metonicCycle, $metonicYear, $moladDay, $moladHalakim, $tishri1); |
| 151 | + if ($month == 1) { |
| 152 | + $sdn = $tishri1 + $day - 1; |
| 153 | + } else { |
| 154 | + $sdn = $tishri1 + $day + 29; |
| 155 | + } |
| 156 | + break; |
| 157 | + |
| 158 | + case 3: |
| 159 | + /* It is Kislev - must find the $year length. */ |
| 160 | + |
| 161 | + /* Find the start of the $year. */ |
| 162 | + self::findStartOfYear($year, $metonicCycle, $metonicYear, $moladDay, $moladHalakim, ${$tishri1}); |
| 163 | + |
| 164 | + /* Find the end of the $year. */ |
| 165 | + $moladHalakim += self::HALAKIM_PER_LUNAR_CYCLE * self::getMonthsInYear($metonicYear); |
| 166 | + $moladDay += (int) ($moladHalakim / self::HALAKIM_PER_DAY); |
| 167 | + $moladHalakim %= self::HALAKIM_PER_DAY; |
| 168 | + $tishri1After = self::tishri1(($metonicYear + 1) % 19, $moladDay, $moladHalakim); |
| 169 | + |
| 170 | + $yearLength = $tishri1After - $tishri1; |
| 171 | + |
| 172 | + if ($yearLength === 355 || $yearLength === 385) { |
| 173 | + $sdn = $tishri1 + $day + 59; |
92 | 174 | } else { |
93 | | - $sdn = $tishri1After + $day - $lengthOfAdarIAndII - 178; |
| 175 | + $sdn = $tishri1 + $day + 58; |
94 | 176 | } |
95 | 177 | break; |
96 | 178 |
|
| 179 | + case 4: |
| 180 | + case 5: |
| 181 | + case 6: |
| 182 | + /* It is Tevet, Shevat or Adar I - don't need the $year length. */ |
| 183 | + |
| 184 | + self::findStartOfYear($year + 1, $metonicCycle, $metonicYear, $moladDay, $moladHalakim, $tishri1After); |
| 185 | + |
| 186 | + if (self::getMonthsInYear(($year - 1) % 19) === 12) { |
| 187 | + $lengthOfAdarIAndII = 29; |
| 188 | + } else { |
| 189 | + $lengthOfAdarIAndII = 59; |
| 190 | + } |
| 191 | + |
| 192 | + $sdn = self::calSDN($month, (int) $tishri1After, $day, $lengthOfAdarIAndII); |
| 193 | + break; |
| 194 | + |
97 | 195 | default: |
98 | | - /* It is Adar II or later - don't need the year length. */ |
| 196 | + /* It is Adar II or later - don't need the $year length. */ |
99 | 197 | self::findStartOfYear($year + 1, $metonicCycle, $metonicYear, $moladDay, $moladHalakim, $tishri1After); |
100 | 198 |
|
101 | 199 | switch ($month) { |
@@ -128,6 +226,23 @@ public static function jewishtojd(int $month, int $day, int $year): int |
128 | 226 | return $sdn + self::JEWISH_SDN_OFFSET; |
129 | 227 | } |
130 | 228 |
|
| 229 | + private static function calSDN( |
| 230 | + int $month, |
| 231 | + int $tishri1After, |
| 232 | + int $day, |
| 233 | + int $lengthOfAdarIAndII |
| 234 | + ): int { |
| 235 | + if ($month === 4) { |
| 236 | + $sdn = $tishri1After + $day - $lengthOfAdarIAndII - 237; |
| 237 | + } elseif ($month === 5) { |
| 238 | + $sdn = $tishri1After + $day - $lengthOfAdarIAndII - 208; |
| 239 | + } else { |
| 240 | + $sdn = $tishri1After + $day - $lengthOfAdarIAndII - 178; |
| 241 | + } |
| 242 | + |
| 243 | + return $sdn; |
| 244 | + } |
| 245 | + |
131 | 246 | private static function getMonthsInYear($metonicYear): int |
132 | 247 | { |
133 | 248 | return self::$monthsPerYear[(int) $metonicYear] ?? 12; |
@@ -157,16 +272,21 @@ private static function tishri1(int $metonicYear, int $moladDay, int $moladHalak |
157 | 272 | $tishri1 = $moladDay; |
158 | 273 | $dow = $tishri1 % 7; |
159 | 274 | $leapYear = $metonicYear === 2 || $metonicYear === 5 || $metonicYear === 7 |
160 | | - || $metonicYear === 10 || $metonicYear === 13 || $metonicYear === 16 |
| 275 | + || $metonicYear === 10 |
| 276 | + || $metonicYear === 13 |
| 277 | + || $metonicYear === 16 |
161 | 278 | || $metonicYear === 18; |
162 | 279 | $lastWasLeapYear = $metonicYear === 3 || $metonicYear === 6 |
163 | | - || $metonicYear === 8 || $metonicYear === 11 || $metonicYear === 14 |
164 | | - || $metonicYear === 17 || $metonicYear === 0; |
| 280 | + || $metonicYear === 8 |
| 281 | + || $metonicYear === 11 |
| 282 | + || $metonicYear === 14 |
| 283 | + || $metonicYear === 17 |
| 284 | + || $metonicYear === 0; |
165 | 285 |
|
166 | 286 | /* Apply rules 2, 3 and 4. */ |
167 | | - if (($moladHalakim >= self::NOON) || |
168 | | - ((!$leapYear) && $dow === self::TUESDAY && $moladHalakim >= self::AM3_11_20) || |
169 | | - ($lastWasLeapYear && $dow === self::MONDAY && $moladHalakim >= self::AM9_32_43) |
| 287 | + if (($moladHalakim >= self::NOON) |
| 288 | + || ((!$leapYear) && $dow === self::TUESDAY && $moladHalakim >= self::AM3_11_20) |
| 289 | + || ($lastWasLeapYear && $dow === self::MONDAY && $moladHalakim >= self::AM9_32_43) |
170 | 290 | ) { |
171 | 291 | ++$tishri1; |
172 | 292 | ++$dow; |
|
0 commit comments