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