Shim::calDaysInMonth()   A
last analyzed

Complexity

Conditions 5
Paths 5

Size

Total Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
nc 5
nop 3
dl 0
loc 19
rs 9.3222
c 0
b 0
f 0
1
<?php
2
namespace Fisharebest\ExtCalendar;
3
4
use InvalidArgumentException;
5
6
/**
7
 * class Shim - PHP implementations of functions from the PHP calendar extension.
8
 *
9
 * @link      http://php.net/manual/en/book.calendar.php
10
 *
11
 * @author    Greg Roach <[email protected]>
12
 * @copyright (c) 2014-2020 Greg Roach
13
 * @license   This program is free software: you can redistribute it and/or modify
14
 *            it under the terms of the GNU General Public License as published by
15
 *            the Free Software Foundation, either version 3 of the License, or
16
 *            (at your option) any later version.
17
 *
18
 *            This program is distributed in the hope that it will be useful,
19
 *            but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 *            MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
 *            GNU General Public License for more details.
22
 *
23
 *            You should have received a copy of the GNU General Public License
24
 *            along with this program.  If not, see <http://www.gnu.org/licenses/>.
25
 */
26
class Shim
0 ignored issues
show
Coding Style introduced by
Shim does not seem to conform to the naming convention (Utils?$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
27
{
28
    /** @var FrenchCalendar */
29
    private static $french_calendar;
30
31
    /** @var GregorianCalendar */
32
    private static $gregorian_calendar;
33
34
    /** @var JewishCalendar */
35
    private static $jewish_calendar;
36
37
    /** @var JulianCalendar */
38
    private static $julian_calendar;
39
40
    /**
41
     * English names for the days of the week.
42
     *
43
     * @var string[]
44
     */
45
    private static $DAY_NAMES = array(
46
        'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday',
47
    );
48
49
    /**
50
     * Abbreviated English names for the days of the week.
51
     *
52
     * @var string[]
53
     */
54
    private static $DAY_NAMES_SHORT = array(
55
        'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat',
56
    );
57
58
    /** @var string[] Names of the months of the Gregorian/Julian calendars */
59
    private static $MONTH_NAMES = array(
60
        '', 'January', 'February', 'March', 'April', 'May', 'June',
61
        'July', 'August', 'September', 'October', 'November', 'December',
62
    );
63
64
    /** @var string[] Abbreviated names of the months of the Gregorian/Julian calendars */
65
    private static $MONTH_NAMES_SHORT = array(
66
        '', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',
67
    );
68
69
    /** @var string[] Name of the months of the French calendar */
70
    private static $MONTH_NAMES_FRENCH = array(
71
        '', 'Vendemiaire', 'Brumaire', 'Frimaire', 'Nivose', 'Pluviose', 'Ventose',
72
        'Germinal', 'Floreal', 'Prairial', 'Messidor', 'Thermidor', 'Fructidor', 'Extra'
73
    );
74
75
    /** @var string[] Names of the months of the Jewish calendar in a non-leap year */
76
    private static $MONTH_NAMES_JEWISH = array(
77
        '', 'Tishri', 'Heshvan', 'Kislev', 'Tevet', 'Shevat', 'Adar',
78
        'Adar', 'Nisan', 'Iyyar', 'Sivan', 'Tammuz', 'Av', 'Elul',
79
    );
80
81
    /** @var string[] Names of the months of the Jewish calendar in a leap year */
82
    private static $MONTH_NAMES_JEWISH_LEAP_YEAR = array(
83
        '', 'Tishri', 'Heshvan', 'Kislev', 'Tevet', 'Shevat', 'Adar I',
84
        'Adar II', 'Nisan', 'Iyyar', 'Sivan', 'Tammuz', 'Av', 'Elul',
85
    );
86
87
    /** @var string[] Names of the months of the Jewish calendar (before PHP bug 54254 was fixed) */
88
    private static $MONTH_NAMES_JEWISH_54254 = array(
89
        '', 'Tishri', 'Heshvan', 'Kislev', 'Tevet', 'Shevat', 'AdarI',
90
        'AdarII', 'Nisan', 'Iyyar', 'Sivan', 'Tammuz', 'Av', 'Elul',
91
    );
92
93
    /**
94
     * Create the necessary shims to emulate the ext/calendar package.
95
     *
96
     * @return void
97
     */
98
    public static function create()
99
    {
100
        self::$french_calendar    = new FrenchCalendar();
101
        self::$gregorian_calendar = new GregorianCalendar();
102
        self::$jewish_calendar    = new JewishCalendar(array(
103
            JewishCalendar::EMULATE_BUG_54254 => self::shouldEmulateBug54254(),
104
        ));
105
        self::$julian_calendar    = new JulianCalendar();
106
    }
107
108
    /**
109
     * Do we need to emulate PHP bug #54254?
110
     *
111
     * This bug relates to the names used for months 6 and 7 in the Jewish calendar.
112
     *
113
     * It was fixed in PHP 5.5.0
114
     *
115
     * @link https://bugs.php.net/bug.php?id=54254
116
     *
117
     * @return bool
118
     */
119
    public static function shouldEmulateBug54254()
120
    {
121
        return version_compare(PHP_VERSION, '5.5.0', '<');
122
    }
123
124
    /**
125
     * Do we need to emulate PHP bug #67960?
126
     *
127
     * This bug relates to the constants CAL_DOW_SHORT and CAL_DOW_LONG.
128
     *
129
     * It was fixed in PHP 5.6.5 and 5.5.21
130
     *
131
     * @link https://bugs.php.net/bug.php?id=67960
132
     * @link https://github.com/php/php-src/pull/806
133
     *
134
     * @return bool
135
     */
136
    public static function shouldEmulateBug67960()
137
    {
138
        return version_compare(PHP_VERSION, '5.5.21', '<') || version_compare(PHP_VERSION, '5.6.0', '>=') && version_compare(PHP_VERSION, '5.6.5', '<') ;
139
    }
140
141
    /**
142
     * Do we need to emulate PHP bug #67976?
143
     *
144
     * This bug relates to the number of days in the month 13 of year 14 in
145
     * the French calendar.
146
     *
147
     * It was fixed in PHP 5.6.25 and 7.0.10
148
     *
149
     * @link https://bugs.php.net/bug.php?id=67976
150
     *
151
     * @return bool
152
     */
153
    public static function shouldEmulateBug67976()
154
    {
155
        return version_compare(PHP_VERSION, '5.6.25', '<') || version_compare(PHP_VERSION, '7.0.0', '>=') && version_compare(PHP_VERSION, '7.0.10', '<') ;
156
    }
157
158
    /**
159
     * Return the number of days in a month for a given year and calendar.
160
     *
161
     * Shim implementation of cal_days_in_month()
162
     *
163
     * @link https://php.net/cal_days_in_month
164
     * @link https://bugs.php.net/bug.php?id=67976
165
     *
166
     * @param int $calendar_id
167
     * @param int $month
168
     * @param int $year
169
     *
170
     * @return int|bool The number of days in the specified month, or false on error
171
     */
172
    public static function calDaysInMonth($calendar_id, $month, $year)
173
    {
174
        switch ($calendar_id) {
175
            case CAL_FRENCH:
176
                return self::calDaysInMonthFrench($year, $month);
177
178
            case CAL_GREGORIAN:
179
                return self::calDaysInMonthCalendar(self::$gregorian_calendar, $year, $month);
180
181
            case CAL_JEWISH:
182
                return self::calDaysInMonthCalendar(self::$jewish_calendar, $year, $month);
183
184
            case CAL_JULIAN:
185
                return self::calDaysInMonthCalendar(self::$julian_calendar, $year, $month);
186
187
            default:
188
                return trigger_error('invalid calendar ID ' . $calendar_id, E_USER_WARNING);
189
        }
190
    }
191
192
    /**
193
     * Calculate the number of days in a month in a specified (Gregorian or Julian) calendar.
194
     *
195
     * @param CalendarInterface $calendar
196
     * @param int               $year
197
     * @param int               $month
198
     *
199
     * @return int|bool
200
     */
201
    private static function calDaysInMonthCalendar(CalendarInterface $calendar, $year, $month)
202
    {
203
        try {
204
            return $calendar->daysInMonth($year, $month);
205
        } catch (InvalidArgumentException $ex) {
206
            $error_msg = PHP_VERSION_ID < 70200 ? 'invalid date.' : 'invalid date';
207
208
            return trigger_error($error_msg, E_USER_WARNING);
209
        }
210
    }
211
212
    /**
213
     * Calculate the number of days in a month in the French calendar.
214
     *
215
     * Mimic PHP’s validation of the parameters
216
     *
217
     * @param int $year
218
     * @param int $month
219
     *
220
     * @return int|bool
221
     */
222
    private static function calDaysInMonthFrench($year, $month)
223
    {
224
        if ($month == 13 && $year == 14 && self::shouldEmulateBug67976()) {
225
            return -2380948;
226 View Code Duplication
        } elseif ($year > 14) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
227
            $error_msg = PHP_VERSION_ID < 70200 ? 'invalid date.' : 'invalid date';
228
229
            return trigger_error($error_msg, E_USER_WARNING);
230
        } else {
231
            return self::calDaysInMonthCalendar(self::$french_calendar, $year, $month);
232
        }
233
    }
234
235
    /**
236
     * Converts from Julian Day Count to a supported calendar.
237
     *
238
     * Shim implementation of cal_from_jd()
239
     *
240
     * @link https://php.net/cal_from_jd
241
     *
242
     * @param int $julian_day  Julian Day number
243
     * @param int $calendar_id Calendar constant
244
     *
245
     * @return array|bool
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array|boolean.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
246
     */
247
    public static function calFromJd($julian_day, $calendar_id)
248
    {
249
        switch ($calendar_id) {
250
            case CAL_FRENCH:
251
                return self::calFromJdCalendar($julian_day, self::jdToFrench($julian_day), self::$MONTH_NAMES_FRENCH, self::$MONTH_NAMES_FRENCH);
252
253
            case CAL_GREGORIAN:
254
                return self::calFromJdCalendar($julian_day, self::jdToGregorian($julian_day), self::$MONTH_NAMES, self::$MONTH_NAMES_SHORT);
255
256
            case CAL_JEWISH:
257
                $months = self::jdMonthNameJewishMonths($julian_day);
258
259
                $cal = self::calFromJdCalendar($julian_day, self::jdToCalendar(self::$jewish_calendar, $julian_day, 347998, 324542846), $months, $months);
260
261
                if (($julian_day < 347998 || $julian_day > 324542846) && !self::shouldEmulateBug67976()) {
262
                    $cal['dow'] = null;
263
                    $cal['dayname'] = '';
264
                    $cal['abbrevdayname'] = '';
265
                }
266
267
                return $cal;
268
269
            case CAL_JULIAN:
270
                return self::calFromJdCalendar($julian_day, self::jdToJulian($julian_day), self::$MONTH_NAMES, self::$MONTH_NAMES_SHORT);
271
272
            default:
273
                return trigger_error('invalid calendar ID ' . $calendar_id, E_USER_WARNING);
274
        }
275
    }
276
277
    /**
278
     * Convert a Julian day number to a calendar and provide details.
279
     *
280
     * @param int      $julian_day
281
     * @param string   $mdy
282
     * @param string[] $months
283
     * @param string[] $months_short
284
     *
285
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,string|integer>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
286
     */
287
    private static function calFromJdCalendar($julian_day, $mdy, $months, $months_short)
288
    {
289
        list($month, $day, $year) = explode('/', $mdy);
290
291
        return array(
292
            'date'          => $month . '/' . $day . '/' . $year,
293
            'month'         => (int) $month,
294
            'day'           => (int) $day,
295
            'year'          => (int) $year,
296
            'dow'           => self::jdDayOfWeek($julian_day, 0),
297
            'abbrevdayname' => self::jdDayOfWeek($julian_day, 2),
298
            'dayname'       => self::jdDayOfWeek($julian_day, 1),
299
            'abbrevmonth'   => $months_short[$month],
300
            'monthname'     => $months[$month],
301
        );
302
    }
303
304
    /**
305
     * Returns information about a particular calendar.
306
     *
307
     * Shim implementation of cal_info()
308
     *
309
     * @link https://php.net/cal_info
310
     *
311
     * @param int $calendar_id
312
     *
313
     * @return array|bool
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,string[]|in...olean>|boolean>|boolean.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
314
     */
315
    public static function calInfo($calendar_id)
316
    {
317
        switch ($calendar_id) {
318
            case CAL_FRENCH:
319
                return self::calInfoCalendar(self::$MONTH_NAMES_FRENCH, self::$MONTH_NAMES_FRENCH, 30, 'French', 'CAL_FRENCH');
320
321
            case CAL_GREGORIAN:
322
                return self::calInfoCalendar(self::$MONTH_NAMES, self::$MONTH_NAMES_SHORT, 31, 'Gregorian', 'CAL_GREGORIAN');
323
324
            case CAL_JEWISH:
325
                $months = self::shouldEmulateBug54254() ? self::$MONTH_NAMES_JEWISH_54254 : self::$MONTH_NAMES_JEWISH_LEAP_YEAR;
326
327
                return self::calInfoCalendar($months, $months, 30, 'Jewish', 'CAL_JEWISH');
328
329
            case CAL_JULIAN:
330
                return self::calInfoCalendar(self::$MONTH_NAMES, self::$MONTH_NAMES_SHORT, 31, 'Julian', 'CAL_JULIAN');
331
332
            case -1:
333
                return array(
334
                CAL_GREGORIAN => self::calInfo(CAL_GREGORIAN),
335
                CAL_JULIAN    => self::calInfo(CAL_JULIAN),
336
                CAL_JEWISH    => self::calInfo(CAL_JEWISH),
337
                CAL_FRENCH    => self::calInfo(CAL_FRENCH),
338
            );
339
340
            default:
341
                return trigger_error('invalid calendar ID ' . $calendar_id, E_USER_WARNING);
342
        }
343
    }
344
345
    /**
346
     * Returns information about the French calendar.
347
     *
348
     * @param string[] $month_names
349
     * @param string[] $month_names_short
350
     * @param int      $max_days_in_month
351
     * @param string   $calendar_name
352
     * @param string   $calendar_symbol
353
     *
354
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,string[]|integer|string>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
355
     */
356
    private static function calInfoCalendar($month_names, $month_names_short, $max_days_in_month, $calendar_name, $calendar_symbol)
357
    {
358
        return array(
359
            'months'         => array_slice($month_names, 1, null, true),
360
            'abbrevmonths'   => array_slice($month_names_short, 1, null, true),
361
            'maxdaysinmonth' => $max_days_in_month,
362
            'calname'        => $calendar_name,
363
            'calsymbol'      => $calendar_symbol,
364
        );
365
    }
366
367
    /**
368
     *  Converts from a supported calendar to Julian Day Count
369
     *
370
     * Shim implementation of cal_to_jd()
371
     *
372
     * @link https://php.net/cal_to_jd
373
     *
374
     * @param int $calendar_id
375
     * @param int $month
376
     * @param int $day
377
     * @param int $year
378
     *
379
     * @return int|bool
380
     */
381
    public static function calToJd($calendar_id, $month, $day, $year)
382
    {
383
        switch ($calendar_id) {
384
            case CAL_FRENCH:
385
                return self::frenchToJd($month, $day, $year);
386
387
            case CAL_GREGORIAN:
388
                return self::gregorianToJd($month, $day, $year);
389
390
            case CAL_JEWISH:
391
                return self::jewishToJd($month, $day, $year);
392
393
            case CAL_JULIAN:
394
                return self::julianToJd($month, $day, $year);
395
396
            default:
397
                return trigger_error('invalid calendar ID ' . $calendar_id . '.', E_USER_WARNING);
398
        }
399
    }
400
401
    /**
402
     * Get Unix timestamp for midnight on Easter of a given year.
403
     *
404
     * Shim implementation of easter_date()
405
     *
406
     * @link https://php.net/easter_date
407
     *
408
     * @param int $year
409
     *
410
     * @return int|bool
0 ignored issues
show
Documentation introduced by
Should the return type not be boolean|integer|double?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
411
     */
412
    public static function easterDate($year)
413
    {
414
        if ($year < 1970 || $year > 2037) {
415
            return trigger_error('This function is only valid for years between 1970 and 2037 inclusive', E_USER_WARNING);
416
        }
417
418
        $days = self::$gregorian_calendar->easterDays($year);
419
420
        // Calculate time-zone offset
421
        $date_time      = new \DateTime('now', new \DateTimeZone(date_default_timezone_get()));
422
        $offset_seconds = (int) $date_time->format('Z');
423
424
        if ($days < 11) {
425
            return self::jdtounix(self::$gregorian_calendar->ymdToJd($year, 3, $days + 21)) - $offset_seconds;
426
        } else {
427
            return self::jdtounix(self::$gregorian_calendar->ymdToJd($year, 4, $days - 10)) - $offset_seconds;
428
        }
429
    }
430
431
    /**
432
     * Get number of days after March 21 on which Easter falls for a given year.
433
     *
434
     * Shim implementation of easter_days()
435
     *
436
     * @link https://php.net/easter_days
437
     *
438
     * @param int $year
439
     * @param int $method Use the Julian or Gregorian calendar
440
     *
441
     * @return int
442
     */
443
    public static function easterDays($year, $method)
444
    {
445
        if ($method == CAL_EASTER_ALWAYS_JULIAN ||
446
            $method == CAL_EASTER_ROMAN && $year <= 1582 ||
447
            $year <= 1752 && $method != CAL_EASTER_ROMAN && $method != CAL_EASTER_ALWAYS_GREGORIAN
448
        ) {
449
            return self::$julian_calendar->easterDays($year);
450
        } else {
451
            return self::$gregorian_calendar->easterDays($year);
452
        }
453
    }
454
455
    /**
456
     * Converts a date from the French Republican Calendar to a Julian Day Count.
457
     *
458
     * Shim implementation of FrenchToJD()
459
     *
460
     * @link https://php.net/FrenchToJD
461
     *
462
     * @param int $month
463
     * @param int $day
464
     * @param int $year
465
     *
466
     * @return int
467
     */
468
    public static function frenchToJd($month, $day, $year)
469
    {
470
        if ($year <= 0) {
471
            return 0;
472
        } else {
473
            return self::$french_calendar->ymdToJd($year, $month, $day);
474
        }
475
    }
476
477
    /**
478
     * Converts a Gregorian date to Julian Day Count.
479
     *
480
     * Shim implementation of GregorianToJD()
481
     *
482
     * @link https://php.net/GregorianToJD
483
     *
484
     * @param int $month
485
     * @param int $day
486
     * @param int $year
487
     *
488
     * @return int
489
     */
490
    public static function gregorianToJd($month, $day, $year)
491
    {
492
        if ($year == 0) {
493
            return 0;
494
        } else {
495
            return self::$gregorian_calendar->ymdToJd($year, $month, $day);
496
        }
497
    }
498
499
    /**
500
     * Returns the day of the week.
501
     *
502
     * Shim implementation of JDDayOfWeek()
503
     *
504
     * @link https://php.net/JDDayOfWeek
505
     * @link https://bugs.php.net/bug.php?id=67960
506
     *
507
     * @param int $julian_day
508
     * @param int $mode
509
     *
510
     * @return int|string
511
     */
512
    public static function jdDayOfWeek($julian_day, $mode)
513
    {
514
        $day_of_week = ($julian_day + 1) % 7;
515
        if ($day_of_week < 0) {
516
            $day_of_week += 7;
517
        }
518
519
        switch ($mode) {
520
            case 1: // 1, not CAL_DOW_LONG - see bug 67960
521
                return self::$DAY_NAMES[$day_of_week];
522
523
            case 2: // 2, not CAL_DOW_SHORT - see bug 67960
524
                return self::$DAY_NAMES_SHORT[$day_of_week];
525
526
            default: // CAL_DOW_DAYNO or anything else
527
                return $day_of_week;
528
        }
529
    }
530
531
    /**
532
     * Returns a month name.
533
     *
534
     * Shim implementation of JDMonthName()
535
     *
536
     * @link https://php.net/JDMonthName
537
     *
538
     * @param int $julian_day
539
     * @param int $mode
540
     *
541
     * @return string
542
     */
543
    public static function jdMonthName($julian_day, $mode)
544
    {
545
        switch ($mode) {
546
            case CAL_MONTH_GREGORIAN_LONG:
547
                return self::jdMonthNameCalendar(self::$gregorian_calendar, $julian_day, self::$MONTH_NAMES);
548
549
            case CAL_MONTH_JULIAN_LONG:
550
                return self::jdMonthNameCalendar(self::$julian_calendar, $julian_day, self::$MONTH_NAMES);
551
552
            case CAL_MONTH_JULIAN_SHORT:
553
                return self::jdMonthNameCalendar(self::$julian_calendar, $julian_day, self::$MONTH_NAMES_SHORT);
554
555
            case CAL_MONTH_JEWISH:
556
                return self::jdMonthNameCalendar(self::$jewish_calendar, $julian_day, self::jdMonthNameJewishMonths($julian_day));
557
558
            case CAL_MONTH_FRENCH:
559
                return self::jdMonthNameCalendar(self::$french_calendar, $julian_day, self::$MONTH_NAMES_FRENCH);
560
561
            case CAL_MONTH_GREGORIAN_SHORT:
562
            default:
563
                return self::jdMonthNameCalendar(self::$gregorian_calendar, $julian_day, self::$MONTH_NAMES_SHORT);
564
        }
565
    }
566
567
    /**
568
     * Calculate the month-name for a given julian day, in a given calendar,
569
     * with given set of month names.
570
     *
571
     * @param CalendarInterface $calendar
572
     * @param int               $julian_day
573
     * @param string[]          $months
574
     *
575
     * @return string
576
     */
577
    private static function jdMonthNameCalendar(CalendarInterface $calendar, $julian_day, $months)
578
    {
579
        list(, $month) = $calendar->jdToYmd($julian_day);
580
581
        return $months[$month];
582
    }
583
584
    /**
585
     * Determine which month names to use for the Jewish calendar.
586
     *
587
     * @param int $julian_day
588
     *
589
     * @return string[]
590
     */
591
    private static function jdMonthNameJewishMonths($julian_day)
592
    {
593
        list(, , $year) = explode('/', self::jdToCalendar(self::$jewish_calendar, $julian_day, 347998, 324542846));
594
595
        if (self::$jewish_calendar->isLeapYear($year)) {
596
            return self::shouldEmulateBug54254() ? self::$MONTH_NAMES_JEWISH_54254 : self::$MONTH_NAMES_JEWISH_LEAP_YEAR;
597
        } else {
598
            return self::shouldEmulateBug54254() ? self::$MONTH_NAMES_JEWISH_54254 : self::$MONTH_NAMES_JEWISH;
599
        }
600
    }
601
602
    /**
603
     * Convert a Julian day in a specific calendar to a day/month/year.
604
     *
605
     * Julian days outside the specified range are returned as “0/0/0”.
606
     *
607
     * @param CalendarInterface $calendar
608
     * @param int               $julian_day
609
     * @param int               $min_jd
610
     * @param int               $max_jd
611
     *
612
     * @return string
613
     */
614
    private static function jdToCalendar(CalendarInterface $calendar, $julian_day, $min_jd, $max_jd)
615
    {
616
        if ($julian_day >= $min_jd && $julian_day <= $max_jd) {
617
            list($year, $month, $day) = $calendar->jdToYmd($julian_day);
618
619
            return $month . '/' . $day . '/' . $year;
620
        } else {
621
            return '0/0/0';
622
        }
623
    }
624
625
    /**
626
     * Converts a Julian Day Count to the French Republican Calendar.
627
     *
628
     * Shim implementation of JDToFrench()
629
     *
630
     * @link https://php.net/JDToFrench
631
     *
632
     * @param int $julian_day A Julian Day number
633
     *
634
     * @return string A string of the form "month/day/year"
635
     */
636
    public static function jdToFrench($julian_day)
637
    {
638
        // JDToFrench() converts years 1 to 14 inclusive, even though the calendar
639
        // officially ended on 10 Nivôse 14 (JD 2380687, 31st December 1805 Gregorian).
640
        return self::jdToCalendar(self::$french_calendar, $julian_day, 2375840, 2380952);
641
    }
642
643
    /**
644
     * Converts Julian Day Count to Gregorian date.
645
     *
646
     * Shim implementation of JDToGregorian()
647
     *
648
     * @link https://php.net/JDToGregorian
649
     *
650
     * @param int $julian_day A Julian Day number
651
     *
652
     * @return string A string of the form "month/day/year"
653
     */
654 View Code Duplication
    public static function jdToGregorian($julian_day)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
655
    {
656
        // PHP has different limits on 32 and 64 bit systems.
657
        $MAX_JD = PHP_INT_SIZE == 4 ? 536838866 : 2305843009213661906;
658
659
        return self::jdToCalendar(self::$gregorian_calendar, $julian_day, 1, $MAX_JD);
660
    }
661
662
    /**
663
     * Converts a Julian day count to a Jewish calendar date.
664
     *
665
     * Shim implementation of JdtoJjewish()
666
     *
667
     * @link https://php.net/JdtoJewish
668
     *
669
     * @param int  $julian_day A Julian Day number
670
     * @param bool $hebrew     If true, the date is returned in Hebrew text
671
     * @param int  $fl         If $hebrew is true, then add alafim and gereshayim to the text
672
     *
673
     * @return string|bool A string of the form "month/day/year", or false on error
674
     */
675
    public static function jdToJewish($julian_day, $hebrew, $fl)
676
    {
677
        if ($hebrew) {
678 View Code Duplication
            if ($julian_day < 347998 || $julian_day > 4000075) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
679
                $error_msg = PHP_VERSION_ID < 70200 ? 'Year out of range (0-9999).' : 'Year out of range (0-9999)';
680
681
                return trigger_error($error_msg, E_USER_WARNING);
682
            }
683
684
            return self::$jewish_calendar->jdToHebrew(
685
                $julian_day,
686
                (bool)($fl & CAL_JEWISH_ADD_ALAFIM_GERESH),
687
                (bool)($fl & CAL_JEWISH_ADD_ALAFIM),
688
                (bool)($fl & CAL_JEWISH_ADD_GERESHAYIM)
689
            );
690
        } else {
691
            // The upper limit is hard-coded into PHP to prevent numeric overflow on 32 bit systems.
692
            return self::jdToCalendar(self::$jewish_calendar, $julian_day, 347998, 324542846);
693
        }
694
    }
695
696
    /**
697
     * Converts a Julian Day Count to a Julian Calendar Date.
698
     *
699
     * Shim implementation of JDToJulian()
700
     *
701
     * @link https://php.net/JDToJulian
702
     *
703
     * @param int $julian_day A Julian Day number
704
     *
705
     * @return string A string of the form "month/day/year"
706
     */
707 View Code Duplication
    public static function jdToJulian($julian_day)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
708
    {
709
        // PHP has different limits on 32 and 64 bit systems.
710
        $MAX_JD = PHP_INT_SIZE == 4 ? 536838829 : 784368370349;
711
712
        return self::jdToCalendar(self::$julian_calendar, $julian_day, 1, $MAX_JD);
713
    }
714
715
    /**
716
     * Convert Julian Day to Unix timestamp.
717
     *
718
     * Shim implementation of jdtounix()
719
     *
720
     * @link https://php.net/jdtounix
721
     *
722
     * @param int $julian_day
723
     *
724
     * @return int|false
725
     */
726
    public static function jdToUnix($julian_day)
727
    {
728
        if ($julian_day >= 2440588 && $julian_day <= 2465343) {
729
            return (int) ($julian_day - 2440588) * 86400;
730
        } else {
731
            return false;
732
        }
733
    }
734
735
    /**
736
     * Converts a date in the Jewish Calendar to Julian Day Count.
737
     *
738
     * Shim implementation of JewishToJD()
739
     *
740
     * @link https://php.net/JewishToJD
741
     *
742
     * @param int $month
743
     * @param int $day
744
     * @param int $year
745
     *
746
     * @return int
747
     */
748
    public static function jewishToJd($month, $day, $year)
749
    {
750
        if ($year <= 0) {
751
            return 0;
752
        } else {
753
            return self::$jewish_calendar->ymdToJd($year, $month, $day);
754
        }
755
    }
756
757
    /**
758
     * Converts a Julian Calendar date to Julian Day Count.
759
     *
760
     * Shim implementation of JdToJulian()
761
     *
762
     * @link https://php.net/JdToJulian
763
     *
764
     * @param int $month
765
     * @param int $day
766
     * @param int $year
767
     *
768
     * @return int
769
     */
770
    public static function julianToJd($month, $day, $year)
771
    {
772
        if ($year == 0) {
773
            return 0;
774
        } else {
775
            return self::$julian_calendar->ymdToJd($year, $month, $day);
776
        }
777
    }
778
779
    /**
780
     * Convert Unix timestamp to Julian Day.
781
     *
782
     * Shim implementation of unixtojd()
783
     *
784
     * @link https://php.net/unixtojd
785
     *
786
     * @param int $timestamp
787
     *
788
     * @return false|int
789
     */
790
    public static function unixToJd($timestamp)
791
    {
792
        if ($timestamp < 0) {
793
            return false;
794
        } else {
795
            // Convert timestamp based on local timezone
796
            return self::GregorianToJd(gmdate('n', $timestamp), gmdate('j', $timestamp), gmdate('Y', $timestamp));
797
        }
798
    }
799
}
800