xref: /webtrees/app/Date/JulianDate.php (revision 8d897fd11a9a8845d8456cb9eaad33b9c9d5a225)
1<?php
2
3/**
4 * webtrees: online genealogy
5 * Copyright (C) 2019 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 <http://www.gnu.org/licenses/>.
16 */
17declare(strict_types=1);
18
19namespace Fisharebest\Webtrees\Date;
20
21use Fisharebest\ExtCalendar\JulianCalendar;
22use Fisharebest\Webtrees\I18N;
23
24/**
25 * Definitions for proleptic Julian dates.
26 */
27class JulianDate extends AbstractGregorianJulianDate
28{
29    // GEDCOM calendar escape
30    public const ESCAPE = '@#DJULIAN@';
31
32    /** @var bool True for dates recorded in new-style/old-style format, e.g. 2 FEB 1743/44 */
33    private $new_old_style = false;
34
35    /**
36     * Create a date from either:
37     * a Julian day number
38     * day/month/year strings from a GEDCOM date
39     * another CalendarDate object
40     *
41     * @param array|int|AbstractCalendarDate $date
42     */
43    public function __construct($date)
44    {
45        $this->calendar = new JulianCalendar();
46        parent::__construct($date);
47    }
48
49    /**
50     * Most years are 1 more than the previous, but not always (e.g. 1BC->1AD)
51     *
52     * @param int $year
53     *
54     * @return int
55     */
56    protected function nextYear(int $year): int
57    {
58        if ($year === -1) {
59            return 1;
60        }
61
62        return $year + 1;
63    }
64
65    /**
66     * Process new-style/old-style years and years BC
67     *
68     * @param string $year
69     *
70     * @return int
71     */
72    protected function extractYear(string $year): int
73    {
74        if (preg_match('/^(\d\d\d\d)\/\d{1,4}$/', $year, $match)) {
75            // Assume the first year is correct
76            $this->new_old_style = true;
77
78            return (int) $match[1] + 1;
79        }
80
81        if (preg_match('/^(\d+) B\.C\.$/', $year, $match)) {
82            return - (int) $match[1];
83        }
84
85        return (int) $year;
86    }
87
88    /**
89     * Generate the %Y format for a date.
90     *
91     * @return string
92     */
93    protected function formatLongYear(): string
94    {
95        if ($this->year < 0) {
96            return /*  I18N: BCE=Before the Common Era, for Julian years < 0. See http://en.wikipedia.org/wiki/Common_Era */
97                I18N::translate('%s&nbsp;BCE', I18N::digits(-$this->year));
98        }
99
100        if ($this->new_old_style) {
101            return I18N::translate('%s&nbsp;CE', I18N::digits(sprintf('%d/%02d', $this->year - 1, $this->year % 100)));
102        }
103
104        /* I18N: CE=Common Era, for Julian years > 0. See http://en.wikipedia.org/wiki/Common_Era */
105        return I18N::translate('%s&nbsp;CE', I18N::digits($this->year));
106    }
107
108    /**
109     * Generate the %E format for a date.
110     *
111     * @return string
112     */
113    protected function formatGedcomYear(): string
114    {
115        if ($this->year < 0) {
116            return sprintf('%04d B.C.', -$this->year);
117        }
118
119        if ($this->new_old_style) {
120            return sprintf('%04d/%02d', $this->year - 1, $this->year % 100);
121        }
122
123        return sprintf('%04d', $this->year);
124    }
125}
126