1<?php 2/** 3 * webtrees: online genealogy 4 * Copyright (C) 2018 webtrees development team 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 3 of the License, or 8 * (at your option) any later version. 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 */ 16declare(strict_types=1); 17 18namespace Fisharebest\Webtrees\Date; 19 20use Fisharebest\ExtCalendar\JewishCalendar; 21use Fisharebest\Webtrees\I18N; 22 23/** 24 * Definitions for the Jewish calendar 25 */ 26class JewishDate extends CalendarDate 27{ 28 // Convert GEDCOM month names to month numbers 29 const MONTH_ABBREVIATIONS = [ 30 '' => 0, 31 'TSH' => 1, 32 'CSH' => 2, 33 'KSL' => 3, 34 'TVT' => 4, 35 'SHV' => 5, 36 'ADR' => 6, 37 'ADS' => 7, 38 'NSN' => 8, 39 'IYR' => 9, 40 'SVN' => 10, 41 'TMZ' => 11, 42 'AAV' => 12, 43 'ELL' => 13, 44 ]; 45 46 /** 47 * Create a date from either: 48 * a Julian day number 49 * day/month/year strings from a GEDCOM date 50 * another CalendarDate object 51 * 52 * @param array|int|CalendarDate $date 53 */ 54 public function __construct($date) 55 { 56 $this->calendar = new JewishCalendar(); 57 parent::__construct($date); 58 } 59 60 /** 61 * Generate the %j format for a date. 62 * 63 * @return string 64 */ 65 protected function formatDay(): string 66 { 67 if (WT_LOCALE === 'he' || WT_LOCALE === 'yi') { 68 return (new JewishCalendar())->numberToHebrewNumerals($this->d, true); 69 } 70 71 return parent::formatDay(); 72 } 73 74 /** 75 * Generate the %y format for a date. 76 * 77 * NOTE Short year is NOT a 2-digit year. It is for calendars such as hebrew 78 * which have a 3-digit form of 4-digit years. 79 * 80 * @return string 81 */ 82 protected function formatShortYear(): string 83 { 84 if (WT_LOCALE === 'he' || WT_LOCALE === 'yi') { 85 return (new JewishCalendar())->numberToHebrewNumerals($this->y, false); 86 } 87 88 return parent::formatLongYear(); 89 } 90 91 /** 92 * Generate the %Y format for a date. 93 * 94 * @return string 95 */ 96 protected function formatLongYear(): string 97 { 98 if (WT_LOCALE === 'he' || WT_LOCALE === 'yi') { 99 return (new JewishCalendar())->numberToHebrewNumerals($this->y, true); 100 } 101 102 return parent::formatLongYear(); 103 } 104 105 /** 106 * Full month name in nominative case. 107 * 108 * @param int $month_number 109 * @param bool $leap_year Some calendars use leap months 110 * 111 * @return string 112 */ 113 protected function monthNameNominativeCase(int $month_number, bool $leap_year): string 114 { 115 static $translated_month_names; 116 117 if ($translated_month_names === null) { 118 $translated_month_names = [ 119 0 => '', 120 /* I18N: a month in the Jewish calendar */ 121 1 => I18N::translateContext('NOMINATIVE', 'Tishrei'), 122 /* I18N: a month in the Jewish calendar */ 123 2 => I18N::translateContext('NOMINATIVE', 'Heshvan'), 124 /* I18N: a month in the Jewish calendar */ 125 3 => I18N::translateContext('NOMINATIVE', 'Kislev'), 126 /* I18N: a month in the Jewish calendar */ 127 4 => I18N::translateContext('NOMINATIVE', 'Tevet'), 128 /* I18N: a month in the Jewish calendar */ 129 5 => I18N::translateContext('NOMINATIVE', 'Shevat'), 130 /* I18N: a month in the Jewish calendar */ 131 6 => I18N::translateContext('NOMINATIVE', 'Adar I'), 132 /* I18N: a month in the Jewish calendar */ 133 7 => I18N::translateContext('NOMINATIVE', 'Adar'), 134 /* I18N: a month in the Jewish calendar */ 135 -7 => I18N::translateContext('NOMINATIVE', 'Adar II'), 136 /* I18N: a month in the Jewish calendar */ 137 8 => I18N::translateContext('NOMINATIVE', 'Nissan'), 138 /* I18N: a month in the Jewish calendar */ 139 9 => I18N::translateContext('NOMINATIVE', 'Iyar'), 140 /* I18N: a month in the Jewish calendar */ 141 10 => I18N::translateContext('NOMINATIVE', 'Sivan'), 142 /* I18N: a month in the Jewish calendar */ 143 11 => I18N::translateContext('NOMINATIVE', 'Tamuz'), 144 /* I18N: a month in the Jewish calendar */ 145 12 => I18N::translateContext('NOMINATIVE', 'Av'), 146 /* I18N: a month in the Jewish calendar */ 147 13 => I18N::translateContext('NOMINATIVE', 'Elul'), 148 ]; 149 } 150 151 if ($month_number === 7 && $leap_year) { 152 return $translated_month_names[-7]; 153 } 154 155 return $translated_month_names[$month_number]; 156 } 157 158 /** 159 * Full month name in genitive case. 160 * 161 * @param int $month_number 162 * @param bool $leap_year Some calendars use leap months 163 * 164 * @return string 165 */ 166 protected function monthNameGenitiveCase(int $month_number, bool $leap_year): string 167 { 168 static $translated_month_names; 169 170 if ($translated_month_names === null) { 171 $translated_month_names = [ 172 0 => '', 173 /* I18N: a month in the Jewish calendar */ 174 1 => I18N::translateContext('GENITIVE', 'Tishrei'), 175 /* I18N: a month in the Jewish calendar */ 176 2 => I18N::translateContext('GENITIVE', 'Heshvan'), 177 /* I18N: a month in the Jewish calendar */ 178 3 => I18N::translateContext('GENITIVE', 'Kislev'), 179 /* I18N: a month in the Jewish calendar */ 180 4 => I18N::translateContext('GENITIVE', 'Tevet'), 181 /* I18N: a month in the Jewish calendar */ 182 5 => I18N::translateContext('GENITIVE', 'Shevat'), 183 /* I18N: a month in the Jewish calendar */ 184 6 => I18N::translateContext('GENITIVE', 'Adar I'), 185 /* I18N: a month in the Jewish calendar */ 186 7 => I18N::translateContext('GENITIVE', 'Adar'), 187 /* I18N: a month in the Jewish calendar */ 188 -7 => I18N::translateContext('GENITIVE', 'Adar II'), 189 /* I18N: a month in the Jewish calendar */ 190 8 => I18N::translateContext('GENITIVE', 'Nissan'), 191 /* I18N: a month in the Jewish calendar */ 192 9 => I18N::translateContext('GENITIVE', 'Iyar'), 193 /* I18N: a month in the Jewish calendar */ 194 10 => I18N::translateContext('GENITIVE', 'Sivan'), 195 /* I18N: a month in the Jewish calendar */ 196 11 => I18N::translateContext('GENITIVE', 'Tamuz'), 197 /* I18N: a month in the Jewish calendar */ 198 12 => I18N::translateContext('GENITIVE', 'Av'), 199 /* I18N: a month in the Jewish calendar */ 200 13 => I18N::translateContext('GENITIVE', 'Elul'), 201 ]; 202 } 203 204 if ($month_number === 7 && $leap_year) { 205 return $translated_month_names[-7]; 206 } 207 208 return $translated_month_names[$month_number]; 209 } 210 211 /** 212 * Full month name in locative case. 213 * 214 * @param int $month_number 215 * @param bool $leap_year Some calendars use leap months 216 * 217 * @return string 218 */ 219 protected function monthNameLocativeCase(int $month_number, bool $leap_year): string 220 { 221 static $translated_month_names; 222 223 if ($translated_month_names === null) { 224 $translated_month_names = [ 225 0 => '', 226 /* I18N: a month in the Jewish calendar */ 227 1 => I18N::translateContext('LOCATIVE', 'Tishrei'), 228 /* I18N: a month in the Jewish calendar */ 229 2 => I18N::translateContext('LOCATIVE', 'Heshvan'), 230 /* I18N: a month in the Jewish calendar */ 231 3 => I18N::translateContext('LOCATIVE', 'Kislev'), 232 /* I18N: a month in the Jewish calendar */ 233 4 => I18N::translateContext('LOCATIVE', 'Tevet'), 234 /* I18N: a month in the Jewish calendar */ 235 5 => I18N::translateContext('LOCATIVE', 'Shevat'), 236 /* I18N: a month in the Jewish calendar */ 237 6 => I18N::translateContext('LOCATIVE', 'Adar I'), 238 /* I18N: a month in the Jewish calendar */ 239 7 => I18N::translateContext('LOCATIVE', 'Adar'), 240 /* I18N: a month in the Jewish calendar */ 241 -7 => I18N::translateContext('LOCATIVE', 'Adar II'), 242 /* I18N: a month in the Jewish calendar */ 243 8 => I18N::translateContext('LOCATIVE', 'Nissan'), 244 /* I18N: a month in the Jewish calendar */ 245 9 => I18N::translateContext('LOCATIVE', 'Iyar'), 246 /* I18N: a month in the Jewish calendar */ 247 10 => I18N::translateContext('LOCATIVE', 'Sivan'), 248 /* I18N: a month in the Jewish calendar */ 249 11 => I18N::translateContext('LOCATIVE', 'Tamuz'), 250 /* I18N: a month in the Jewish calendar */ 251 12 => I18N::translateContext('LOCATIVE', 'Av'), 252 /* I18N: a month in the Jewish calendar */ 253 13 => I18N::translateContext('LOCATIVE', 'Elul'), 254 ]; 255 } 256 257 if ($month_number === 7 && $leap_year) { 258 return $translated_month_names[-7]; 259 } 260 261 return $translated_month_names[$month_number]; 262 } 263 264 /** 265 * Full month name in instrumental case. 266 * 267 * @param int $month_number 268 * @param bool $leap_year Some calendars use leap months 269 * 270 * @return string 271 */ 272 protected function monthNameInstrumentalCase(int $month_number, bool $leap_year): string 273 { 274 static $translated_month_names; 275 276 if ($translated_month_names === null) { 277 $translated_month_names = [ 278 0 => '', 279 /* I18N: a month in the Jewish calendar */ 280 1 => I18N::translateContext('INSTRUMENTAL', 'Tishrei'), 281 /* I18N: a month in the Jewish calendar */ 282 2 => I18N::translateContext('INSTRUMENTAL', 'Heshvan'), 283 /* I18N: a month in the Jewish calendar */ 284 3 => I18N::translateContext('INSTRUMENTAL', 'Kislev'), 285 /* I18N: a month in the Jewish calendar */ 286 4 => I18N::translateContext('INSTRUMENTAL', 'Tevet'), 287 /* I18N: a month in the Jewish calendar */ 288 5 => I18N::translateContext('INSTRUMENTAL', 'Shevat'), 289 /* I18N: a month in the Jewish calendar */ 290 6 => I18N::translateContext('INSTRUMENTAL', 'Adar I'), 291 /* I18N: a month in the Jewish calendar */ 292 7 => I18N::translateContext('INSTRUMENTAL', 'Adar'), 293 /* I18N: a month in the Jewish calendar */ 294 -7 => I18N::translateContext('INSTRUMENTAL', 'Adar II'), 295 /* I18N: a month in the Jewish calendar */ 296 8 => I18N::translateContext('INSTRUMENTAL', 'Nissan'), 297 /* I18N: a month in the Jewish calendar */ 298 9 => I18N::translateContext('INSTRUMENTAL', 'Iyar'), 299 /* I18N: a month in the Jewish calendar */ 300 10 => I18N::translateContext('INSTRUMENTAL', 'Sivan'), 301 /* I18N: a month in the Jewish calendar */ 302 11 => I18N::translateContext('INSTRUMENTAL', 'Tamuz'), 303 /* I18N: a month in the Jewish calendar */ 304 12 => I18N::translateContext('INSTRUMENTAL', 'Av'), 305 /* I18N: a month in the Jewish calendar */ 306 13 => I18N::translateContext('INSTRUMENTAL', 'Elul'), 307 ]; 308 } 309 310 if ($month_number === 7 && $leap_year) { 311 return $translated_month_names[-7]; 312 } 313 314 return $translated_month_names[$month_number]; 315 } 316 317 /** 318 * Abbreviated month name 319 * 320 * @param int $month_number 321 * @param bool $leap_year Some calendars use leap months 322 * 323 * @return string 324 */ 325 protected function monthNameAbbreviated(int $month_number, bool $leap_year): string 326 { 327 return $this->monthNameNominativeCase($month_number, $leap_year); 328 } 329 330 /** 331 * Which months follows this one? Calendars with leap-months should provide their own implementation. 332 * 333 * @return int[] 334 */ 335 protected function nextMonth(): array 336 { 337 if ($this->m == 6 && !$this->isLeapYear()) { 338 return [ 339 $this->y, 340 8, 341 ]; 342 } 343 344 return [ 345 $this->y + ($this->m == 13 ? 1 : 0), 346 ($this->m % 13) + 1, 347 ]; 348 } 349} 350