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