15f58d1fdSGreg Roach<?php 23976b470SGreg Roach 35f58d1fdSGreg Roach/** 45f58d1fdSGreg Roach * webtrees: online genealogy 5*054771e9SGreg Roach * Copyright (C) 2020 webtrees development team 65f58d1fdSGreg Roach * This program is free software: you can redistribute it and/or modify 75f58d1fdSGreg Roach * it under the terms of the GNU General Public License as published by 85f58d1fdSGreg Roach * the Free Software Foundation, either version 3 of the License, or 95f58d1fdSGreg Roach * (at your option) any later version. 105f58d1fdSGreg Roach * This program is distributed in the hope that it will be useful, 115f58d1fdSGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of 125f58d1fdSGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 135f58d1fdSGreg Roach * GNU General Public License for more details. 145f58d1fdSGreg Roach * You should have received a copy of the GNU General Public License 155f58d1fdSGreg Roach * along with this program. If not, see <http://www.gnu.org/licenses/>. 165f58d1fdSGreg Roach */ 17fcfa147eSGreg Roach 185f58d1fdSGreg Roachdeclare(strict_types=1); 195f58d1fdSGreg Roach 205f58d1fdSGreg Roachnamespace Fisharebest\Webtrees; 215f58d1fdSGreg Roach 22*054771e9SGreg Roachuse function view; 235f58d1fdSGreg Roach 245f58d1fdSGreg Roach/** 25*054771e9SGreg Roach * The different between to GEDCOM dates. 265f58d1fdSGreg Roach */ 275f58d1fdSGreg Roachclass Age 285f58d1fdSGreg Roach{ 29*054771e9SGreg Roach /** @var int */ 30*054771e9SGreg Roach private $years; 315f58d1fdSGreg Roach 325f58d1fdSGreg Roach /** @var int */ 33*054771e9SGreg Roach private $months; 345f58d1fdSGreg Roach 355f58d1fdSGreg Roach /** @var int */ 36*054771e9SGreg Roach private $days; 375f58d1fdSGreg Roach 385f58d1fdSGreg Roach /** @var int */ 39*054771e9SGreg Roach private $total_days; 405f58d1fdSGreg Roach 41*054771e9SGreg Roach /** @var bool */ 42*054771e9SGreg Roach private $is_exact; 43*054771e9SGreg Roach 44*054771e9SGreg Roach /** @var bool */ 45*054771e9SGreg Roach private $is_valid; 465f58d1fdSGreg Roach 475f58d1fdSGreg Roach /** 485f58d1fdSGreg Roach * Age constructor. 495f58d1fdSGreg Roach * 50*054771e9SGreg Roach * @param Date $x - The first date 51*054771e9SGreg Roach * @param Date $y - The second date 525f58d1fdSGreg Roach */ 53*054771e9SGreg Roach public function __construct(Date $x, Date $y) 545f58d1fdSGreg Roach { 55*054771e9SGreg Roach // If the dates are ranges, use the start/end calendar dates. 56*054771e9SGreg Roach $start = $x->minimumDate(); 57*054771e9SGreg Roach $end = $y->maximumDate(); 585f58d1fdSGreg Roach 59*054771e9SGreg Roach [$this->years, $this->months, $this->days] = $start->ageDifference($end); 605f58d1fdSGreg Roach 61*054771e9SGreg Roach $this->total_days = $end->minimumJulianDay() - $start->minimumJulianDay(); 62*054771e9SGreg Roach 63*054771e9SGreg Roach // Use the same precision as found in the dates. 64*054771e9SGreg Roach if ($start->day() === 0 || $end->day() === 0) { 65*054771e9SGreg Roach $this->days = 0; 665f58d1fdSGreg Roach } 675f58d1fdSGreg Roach 68*054771e9SGreg Roach if ($start->month() === 0 || $end->month() === 0) { 69*054771e9SGreg Roach $this->months = 0; 705f58d1fdSGreg Roach } 715f58d1fdSGreg Roach 72*054771e9SGreg Roach // Are the dates exact? 73*054771e9SGreg Roach $this->is_exact = $start->day() !== 0 && $end->day() !== 0; 74*054771e9SGreg Roach 75*054771e9SGreg Roach // Are the dates valid? 76*054771e9SGreg Roach $this->is_valid = $x->isOK() && $y->isOK(); 775f58d1fdSGreg Roach } 785f58d1fdSGreg Roach 795f58d1fdSGreg Roach /** 80*054771e9SGreg Roach * Show an age in a human-friendly form, such as "34 years", "8 months", "20 days". 81*054771e9SGreg Roach * Show an empty string for invalid/missing dates. 82*054771e9SGreg Roach * Show a warning icon for negative ages. 83*054771e9SGreg Roach * Show zero ages without any units. 84*054771e9SGreg Roach * 85*054771e9SGreg Roach * @return string 865f58d1fdSGreg Roach */ 87*054771e9SGreg Roach public function ageString(): string 885f58d1fdSGreg Roach { 89*054771e9SGreg Roach if (!$this->is_valid) { 90*054771e9SGreg Roach return ''; 915f58d1fdSGreg Roach } 925f58d1fdSGreg Roach 93*054771e9SGreg Roach if ($this->years < 0) { 94*054771e9SGreg Roach return view('icons/warning'); 955f58d1fdSGreg Roach } 965f58d1fdSGreg Roach 97*054771e9SGreg Roach if ($this->years > 0) { 98*054771e9SGreg Roach return I18N::plural('%s year', '%s years', $this->years, I18N::number($this->years)); 995f58d1fdSGreg Roach } 1005f58d1fdSGreg Roach 1015f58d1fdSGreg Roach if ($this->months > 0) { 102*054771e9SGreg Roach return I18N::plural('%s month', '%s months', $this->months, I18N::number($this->months)); 1035f58d1fdSGreg Roach } 1045f58d1fdSGreg Roach 105*054771e9SGreg Roach if ($this->days > 0 || $this->is_exact) { 106*054771e9SGreg Roach return I18N::plural('%s day', '%s days', $this->days, I18N::number($this->days)); 1075f58d1fdSGreg Roach } 1085f58d1fdSGreg Roach 109*054771e9SGreg Roach return I18N::number(0); 1105f58d1fdSGreg Roach } 111783c6f8dSGreg Roach 112783c6f8dSGreg Roach /** 113*054771e9SGreg Roach * How many days between two events? 114*054771e9SGreg Roach * If either date is invalid return -1. 115783c6f8dSGreg Roach * 116783c6f8dSGreg Roach * @return int 117783c6f8dSGreg Roach */ 118*054771e9SGreg Roach public function ageDays(): int 119783c6f8dSGreg Roach { 120*054771e9SGreg Roach if ($this->is_valid) { 121*054771e9SGreg Roach return $this->total_days; 122783c6f8dSGreg Roach } 123783c6f8dSGreg Roach 124*054771e9SGreg Roach return -1; 125*054771e9SGreg Roach } 126*054771e9SGreg Roach 127*054771e9SGreg Roach /** 128*054771e9SGreg Roach * How many years between two events? 129*054771e9SGreg Roach * If either date is invalid return -1. 130*054771e9SGreg Roach * 131*054771e9SGreg Roach * @return int 132*054771e9SGreg Roach */ 133*054771e9SGreg Roach public function ageYears(): int 134*054771e9SGreg Roach { 135*054771e9SGreg Roach if ($this->is_valid) { 136*054771e9SGreg Roach return $this->years; 137*054771e9SGreg Roach } 138*054771e9SGreg Roach 139*054771e9SGreg Roach return -1; 140*054771e9SGreg Roach } 141*054771e9SGreg Roach 142*054771e9SGreg Roach /** 143*054771e9SGreg Roach * @param bool $living 144*054771e9SGreg Roach * 145*054771e9SGreg Roach * @return string 146*054771e9SGreg Roach */ 147*054771e9SGreg Roach public function ageAtEvent(bool $living): string 148*054771e9SGreg Roach { 149*054771e9SGreg Roach $age = $this->ageString(); 150*054771e9SGreg Roach 151*054771e9SGreg Roach if ($age === '') { 152*054771e9SGreg Roach return ''; 153*054771e9SGreg Roach } 154*054771e9SGreg Roach 155*054771e9SGreg Roach if ($living) { 156*054771e9SGreg Roach /* I18N: The current age of a living individual */ 157*054771e9SGreg Roach return I18N::translate('(age %s)', $age); 158*054771e9SGreg Roach } 159*054771e9SGreg Roach 160*054771e9SGreg Roach /* I18N: The age of an individual at a given date */ 161*054771e9SGreg Roach return I18N::translate('(aged %s)', $age); 162*054771e9SGreg Roach } 163*054771e9SGreg Roach 164*054771e9SGreg Roach /** 165*054771e9SGreg Roach * Similar to age-at-event, but for events such as burial, cremation, etc. 166*054771e9SGreg Roach * 167*054771e9SGreg Roach * @return string 168*054771e9SGreg Roach */ 169*054771e9SGreg Roach public function timeAfterDeath(): string 170*054771e9SGreg Roach { 171*054771e9SGreg Roach if (!$this->is_valid) { 172*054771e9SGreg Roach return ''; 173*054771e9SGreg Roach } 174*054771e9SGreg Roach 175*054771e9SGreg Roach if ($this->years === 0 && $this->months === 0 && $this->days === 0) { 176*054771e9SGreg Roach if ($this->is_exact) { 177*054771e9SGreg Roach return '(' . I18N::translate('on the date of death') . ')'; 178*054771e9SGreg Roach } 179*054771e9SGreg Roach 180*054771e9SGreg Roach return ''; 181*054771e9SGreg Roach } 182*054771e9SGreg Roach 183*054771e9SGreg Roach return '(' . $this->ageString() . ' ' . I18N::translate('after death') . ')'; 184783c6f8dSGreg Roach } 1855f58d1fdSGreg Roach} 186