Issues (2563)

app/Date/JewishDate.php (1 issue)

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