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