xref: /webtrees/app/Date/JewishDate.php (revision e7f56f2af615447ab1a7646851f88b465ace9e04)
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 self::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