1
0
Fork 0
mirror of https://github.com/YunoHost-Apps/webtrees_ynh.git synced 2024-09-03 18:26:37 +02:00
webtrees_ynh/sources/app/Date/CalendarDate.php

944 lines
25 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* webtrees: online genealogy
* Copyright (C) 2016 webtrees development team
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Fisharebest\Webtrees\Date;
use FishareBest\ExtCalendar\CalendarInterface;
use FishareBest\ExtCalendar\JewishCalendar;
use Fisharebest\Webtrees\I18N;
/**
* Classes for Gedcom Date/Calendar functionality.
*
* CalendarDate is a base class for classes such as GregorianDate, etc.
* + All supported calendars have non-zero days/months/years.
* + We store dates as both Y/M/D and Julian Days.
* + For imprecise dates such as "JAN 2000" we store the start/end julian day.
*
* NOTE: Since different calendars start their days at different times, (civil
* midnight, solar midnight, sunset, sunrise, etc.), we convert on the basis of
* midday.
*/
class CalendarDate {
/** @var int[] Convert GEDCOM month names to month numbers */
public static $MONTH_ABBREV = array('' => 0, 'JAN' => 1, 'FEB' => 2, 'MAR' => 3, 'APR' => 4, 'MAY' => 5, 'JUN' => 6, 'JUL' => 7, 'AUG' => 8, 'SEP' => 9, 'OCT' => 10, 'NOV' => 11, 'DEC' => 12);
/** @var string[] Convert numbers to/from roman numerals */
protected static $roman_numerals = array(1000 => 'M', 900 => 'CM', 500 => 'D', 400 => 'CD', 100 => 'C', 90 => 'XC', 50 => 'L', 40 => 'XL', 10 => 'X', 9 => 'IX', 5 => 'V', 4 => 'IV', 1 => 'I');
/** @var CalendarInterface The calendar system used to represent this date */
protected $calendar;
/** @var int Year number */
public $y;
/** @var int Month number */
public $m;
/** @var int Day number */
public $d;
/** @var int Earliest Julian day number (start of month/year for imprecise dates) */
public $minJD;
/** @var int Latest Julian day number (end of month/year for imprecise dates) */
public $maxJD;
/**
* Create a date from either:
* a Julian day number
* day/month/year strings from a GEDCOM date
* another CalendarDate object
*
* @param array|int|CalendarDate $date
*/
public function __construct($date) {
// Construct from an integer (a julian day number)
if (is_integer($date)) {
$this->minJD = $date;
$this->maxJD = $date;
list($this->y, $this->m, $this->d) = $this->calendar->jdToYmd($date);
return;
}
// Construct from an array (of three gedcom-style strings: "1900", "FEB", "4")
if (is_array($date)) {
$this->d = (int) $date[2];
if (array_key_exists($date[1], static::$MONTH_ABBREV)) {
$this->m = static::$MONTH_ABBREV[$date[1]];
} else {
$this->m = 0;
$this->d = 0;
}
$this->y = $this->extractYear($date[0]);
// Our simple lookup table above does not take into account Adar and leap-years.
if ($this->m === 6 && $this->calendar instanceof JewishCalendar && !$this->calendar->isLeapYear($this->y)) {
$this->m = 7;
}
$this->setJdFromYmd();
return;
}
// Construct from an equivalent xxxxDate object
if (get_class($this) == get_class($date)) {
$this->y = $date->y;
$this->m = $date->m;
$this->d = $date->d;
$this->minJD = $date->minJD;
$this->maxJD = $date->maxJD;
return;
}
// ...else construct an inequivalent xxxxDate object
if ($date->y == 0) {
// Incomplete date - convert on basis of anniversary in current year
$today = $date->calendar->jdToYmd(unixtojd());
$jd = $date->calendar->ymdToJd($today[0], $date->m, $date->d == 0 ? $today[2] : $date->d);
} else {
// Complete date
$jd = (int) (($date->maxJD + $date->minJD) / 2);
}
list($this->y, $this->m, $this->d) = $this->calendar->jdToYmd($jd);
// New date has same precision as original date
if ($date->y == 0) {
$this->y = 0;
}
if ($date->m == 0) {
$this->m = 0;
}
if ($date->d == 0) {
$this->d = 0;
}
$this->setJdFromYmd();
}
/**
* Is the current year a leap year?
*
* @return bool
*/
public function isLeapYear() {
return $this->calendar->isLeapYear($this->y);
}
/**
* Set the objects Julian day number from a potentially incomplete year/month/day
*/
public function setJdFromYmd() {
if ($this->y == 0) {
$this->minJD = 0;
$this->maxJD = 0;
} elseif ($this->m == 0) {
$this->minJD = $this->calendar->ymdToJd($this->y, 1, 1);
$this->maxJD = $this->calendar->ymdToJd($this->nextYear($this->y), 1, 1) - 1;
} elseif ($this->d == 0) {
list($ny, $nm) = $this->nextMonth();
$this->minJD = $this->calendar->ymdToJd($this->y, $this->m, 1);
$this->maxJD = $this->calendar->ymdToJd($ny, $nm, 1) - 1;
} else {
$this->minJD = $this->calendar->ymdToJd($this->y, $this->m, $this->d);
$this->maxJD = $this->minJD;
}
}
/**
* Full month name in nominative case.
*
* We put these in the base class, to save duplicating it in the Julian and Gregorian calendars.
*
* @param int $month_number
* @param bool $leap_year Some calendars use leap months
*
* @return string
*/
public static function monthNameNominativeCase($month_number, $leap_year) {
static $translated_month_names;
if ($translated_month_names === null) {
$translated_month_names = array(
0 => '',
1 => I18N::translateContext('NOMINATIVE', 'January'),
2 => I18N::translateContext('NOMINATIVE', 'February'),
3 => I18N::translateContext('NOMINATIVE', 'March'),
4 => I18N::translateContext('NOMINATIVE', 'April'),
5 => I18N::translateContext('NOMINATIVE', 'May'),
6 => I18N::translateContext('NOMINATIVE', 'June'),
7 => I18N::translateContext('NOMINATIVE', 'July'),
8 => I18N::translateContext('NOMINATIVE', 'August'),
9 => I18N::translateContext('NOMINATIVE', 'September'),
10 => I18N::translateContext('NOMINATIVE', 'October'),
11 => I18N::translateContext('NOMINATIVE', 'November'),
12 => I18N::translateContext('NOMINATIVE', 'December'),
);
}
return $translated_month_names[$month_number];
}
/**
* Full month name in genitive case.
*
* We put these in the base class, to save duplicating it in the Julian and Gregorian calendars.
*
* @param int $month_number
* @param bool $leap_year Some calendars use leap months
*
* @return string
*/
protected function monthNameGenitiveCase($month_number, $leap_year) {
static $translated_month_names;
if ($translated_month_names === null) {
$translated_month_names = array(
0 => '',
1 => I18N::translateContext('GENITIVE', 'January'),
2 => I18N::translateContext('GENITIVE', 'February'),
3 => I18N::translateContext('GENITIVE', 'March'),
4 => I18N::translateContext('GENITIVE', 'April'),
5 => I18N::translateContext('GENITIVE', 'May'),
6 => I18N::translateContext('GENITIVE', 'June'),
7 => I18N::translateContext('GENITIVE', 'July'),
8 => I18N::translateContext('GENITIVE', 'August'),
9 => I18N::translateContext('GENITIVE', 'September'),
10 => I18N::translateContext('GENITIVE', 'October'),
11 => I18N::translateContext('GENITIVE', 'November'),
12 => I18N::translateContext('GENITIVE', 'December'),
);
}
return $translated_month_names[$month_number];
}
/**
* Full month name in locative case.
*
* We put these in the base class, to save duplicating it in the Julian and Gregorian calendars.
*
* @param int $month_number
* @param bool $leap_year Some calendars use leap months
*
* @return string
*/
protected function monthNameLocativeCase($month_number, $leap_year) {
static $translated_month_names;
if ($translated_month_names === null) {
$translated_month_names = array(
0 => '',
1 => I18N::translateContext('LOCATIVE', 'January'),
2 => I18N::translateContext('LOCATIVE', 'February'),
3 => I18N::translateContext('LOCATIVE', 'March'),
4 => I18N::translateContext('LOCATIVE', 'April'),
5 => I18N::translateContext('LOCATIVE', 'May'),
6 => I18N::translateContext('LOCATIVE', 'June'),
7 => I18N::translateContext('LOCATIVE', 'July'),
8 => I18N::translateContext('LOCATIVE', 'August'),
9 => I18N::translateContext('LOCATIVE', 'September'),
10 => I18N::translateContext('LOCATIVE', 'October'),
11 => I18N::translateContext('LOCATIVE', 'November'),
12 => I18N::translateContext('LOCATIVE', 'December'),
);
}
return $translated_month_names[$month_number];
}
/**
* Full month name in instrumental case.
*
* We put these in the base class, to save duplicating it in the Julian and Gregorian calendars.
*
* @param int $month_number
* @param bool $leap_year Some calendars use leap months
*
* @return string
*/
protected function monthNameInstrumentalCase($month_number, $leap_year) {
static $translated_month_names;
if ($translated_month_names === null) {
$translated_month_names = array(
0 => '',
1 => I18N::translateContext('INSTRUMENTAL', 'January'),
2 => I18N::translateContext('INSTRUMENTAL', 'February'),
3 => I18N::translateContext('INSTRUMENTAL', 'March'),
4 => I18N::translateContext('INSTRUMENTAL', 'April'),
5 => I18N::translateContext('INSTRUMENTAL', 'May'),
6 => I18N::translateContext('INSTRUMENTAL', 'June'),
7 => I18N::translateContext('INSTRUMENTAL', 'July'),
8 => I18N::translateContext('INSTRUMENTAL', 'August'),
9 => I18N::translateContext('INSTRUMENTAL', 'September'),
10 => I18N::translateContext('INSTRUMENTAL', 'October'),
11 => I18N::translateContext('INSTRUMENTAL', 'November'),
12 => I18N::translateContext('INSTRUMENTAL', 'December'),
);
}
return $translated_month_names[$month_number];
}
/**
* Abbreviated month name
*
* @param int $month_number
* @param bool $leap_year Some calendars use leap months
*
* @return string
*/
protected function monthNameAbbreviated($month_number, $leap_year) {
static $translated_month_names;
if ($translated_month_names === null) {
$translated_month_names = array(
0 => '',
1 => I18N::translateContext('Abbreviation for January', 'Jan'),
2 => I18N::translateContext('Abbreviation for February', 'Feb'),
3 => I18N::translateContext('Abbreviation for March', 'Mar'),
4 => I18N::translateContext('Abbreviation for April', 'Apr'),
5 => I18N::translateContext('Abbreviation for May', 'May'),
6 => I18N::translateContext('Abbreviation for June', 'Jun'),
7 => I18N::translateContext('Abbreviation for July', 'Jul'),
8 => I18N::translateContext('Abbreviation for August', 'Aug'),
9 => I18N::translateContext('Abbreviation for September', 'Sep'),
10 => I18N::translateContext('Abbreviation for October', 'Oct'),
11 => I18N::translateContext('Abbreviation for November', 'Nov'),
12 => I18N::translateContext('Abbreviation for December', 'Dec'),
);
}
return $translated_month_names[$month_number];
}
/**
* Full day of th eweek
*
* @param int $day_number
*
* @return string
*/
public function dayNames($day_number) {
static $translated_day_names;
if ($translated_day_names === null) {
$translated_day_names = array(
0 => I18N::translate('Monday'),
1 => I18N::translate('Tuesday'),
2 => I18N::translate('Wednesday'),
3 => I18N::translate('Thursday'),
4 => I18N::translate('Friday'),
5 => I18N::translate('Saturday'),
6 => I18N::translate('Sunday'),
);
}
return $translated_day_names[$day_number];
}
/**
* Abbreviated day of the week
*
* @param int $day_number
*
* @return string
*/
protected function dayNamesAbbreviated($day_number) {
static $translated_day_names;
if ($translated_day_names === null) {
$translated_day_names = array(
0 => /* I18N: abbreviation for Monday */ I18N::translate('Mon'),
1 => /* I18N: abbreviation for Tuesday */ I18N::translate('Tue'),
2 => /* I18N: abbreviation for Wednesday */ I18N::translate('Wed'),
3 => /* I18N: abbreviation for Thursday */ I18N::translate('Thu'),
4 => /* I18N: abbreviation for Friday */ I18N::translate('Fri'),
5 => /* I18N: abbreviation for Saturday */ I18N::translate('Sat'),
6 => /* I18N: abbreviation for Sunday */ I18N::translate('Sun'),
);
}
return $translated_day_names[$day_number];
}
/**
* Most years are 1 more than the previous, but not always (e.g. 1BC->1AD)
*
* @param int $year
*
* @return int
*/
protected function nextYear($year) {
return $year + 1;
}
/**
* Calendars that use suffixes, etc. (e.g. “B.C.”) or OS/NS notation should redefine this.
*
* @param string $year
*
* @return int
*/
protected function extractYear($year) {
return (int) $year;
}
/**
* Compare two dates, for sorting
*
* @param CalendarDate $d1
* @param CalendarDate $d2
*
* @return int
*/
public static function compare(CalendarDate $d1, CalendarDate $d2) {
if ($d1->maxJD < $d2->minJD) {
return -1;
} elseif ($d2->minJD > $d1->maxJD) {
return 1;
} else {
return 0;
}
}
/**
* How long between an event and a given julian day
* Return result as either a number of years or
* a gedcom-style age string.
*
* @todo JewishDate needs to redefine this to cope with leap months
*
* @param bool $full true=gedcom style, false=just years
* @param int $jd date for calculation
* @param bool $warn_on_negative show a warning triangle for negative ages
*
* @return string
*/
public function getAge($full, $jd, $warn_on_negative = true) {
if ($this->y == 0 || $jd == 0) {
return $full ? '' : '0';
}
if ($this->minJD < $jd && $this->maxJD > $jd) {
return $full ? '' : '0';
}
if ($this->minJD == $jd) {
return $full ? '' : '0';
}
if ($warn_on_negative && $jd < $this->minJD) {
return '<i class="icon-warning"></i>';
}
list($y, $m, $d) = $this->calendar->jdToYmd($jd);
$dy = $y - $this->y;
$dm = $m - max($this->m, 1);
$dd = $d - max($this->d, 1);
if ($dd < 0) {
$dm--;
}
if ($dm < 0) {
$dm += $this->calendar->monthsInYear();
$dy--;
}
// Not a full age? Then just the years
if (!$full) {
return $dy;
}
// Age in years?
if ($dy > 1) {
return $dy . 'y';
}
$dm += $dy * $this->calendar->monthsInYear();
// Age in months?
if ($dm > 1) {
return $dm . 'm';
}
// Age in days?
return ($jd - $this->minJD) . 'd';
}
/**
* Convert a date from one calendar to another.
*
* @param string $calendar
*
* @return CalendarDate
*/
public function convertToCalendar($calendar) {
switch ($calendar) {
case 'gregorian':
return new GregorianDate($this);
case 'julian':
return new JulianDate($this);
case 'jewish':
return new JewishDate($this);
case 'french':
return new FrenchDate($this);
case 'hijri':
return new HijriDate($this);
case 'jalali':
return new JalaliDate($this);
default:
return $this;
}
}
/**
* Is this date within the valid range of the calendar
*
* @return bool
*/
public function inValidRange() {
return $this->minJD >= $this->calendar->jdStart() && $this->maxJD <= $this->calendar->jdEnd();
}
/**
* How many months in a year
*
* @return int
*/
public function monthsInYear() {
return $this->calendar->monthsInYear();
}
/**
* How many days in the current month
*
* @return int
*/
public function daysInMonth() {
try {
return $this->calendar->daysInMonth($this->y, $this->m);
} catch (\InvalidArgumentException $ex) {
// calendar.php calls this with "DD MMM" dates, for which we cannot calculate
// the length of a month. Should we validate this before calling this function?
return 0;
}
}
/**
* How many days in the current week
*
* @return int
*/
public function daysInWeek() {
return $this->calendar->daysInWeek();
}
/**
* Format a date, using similar codes to the PHP date() function.
*
* @param string $format See http://php.net/date
* @param string $qualifier GEDCOM qualifier, so we can choose the right case for the month name.
*
* @return string
*/
public function format($format, $qualifier = '') {
// Dont show exact details for inexact dates
if (!$this->d) {
// The comma is for US "M D, Y" dates
$format = preg_replace('/%[djlDNSwz][,]?/', '', $format);
}
if (!$this->m) {
$format = str_replace(array('%F', '%m', '%M', '%n', '%t'), '', $format);
}
if (!$this->y) {
$format = str_replace(array('%t', '%L', '%G', '%y', '%Y'), '', $format);
}
// If weve trimmed the format, also trim the punctuation
if (!$this->d || !$this->m || !$this->y) {
$format = trim($format, ',. ;/-');
}
if ($this->d && preg_match('/%[djlDNSwz]/', $format)) {
// If we have a day-number *and* we are being asked to display it, then genitive
$case = 'GENITIVE';
} else {
switch ($qualifier) {
case 'TO':
case 'ABT':
case 'FROM':
$case = 'GENITIVE';
break;
case 'AFT':
$case = 'LOCATIVE';
break;
case 'BEF':
case 'BET':
case 'AND':
$case = 'INSTRUMENTAL';
break;
case '':
case 'INT':
case 'EST':
case 'CAL':
default: // There shouldn't be any other options...
$case = 'NOMINATIVE';
break;
}
}
// Build up the formatted date, character at a time
preg_match_all('/%[^%]/', $format, $matches);
foreach ($matches[0] as $match) {
switch ($match) {
case '%d':
$format = str_replace($match, $this->formatDayZeros(), $format);
break;
case '%j':
$format = str_replace($match, $this->formatDay(), $format);
break;
case '%l':
$format = str_replace($match, $this->formatLongWeekday(), $format);
break;
case '%D':
$format = str_replace($match, $this->formatShortWeekday(), $format);
break;
case '%N':
$format = str_replace($match, $this->formatIsoWeekday(), $format);
break;
case '%w':
$format = str_replace($match, $this->formatNumericWeekday(), $format);
break;
case '%z':
$format = str_replace($match, $this->formatDayOfYear(), $format);
break;
case '%F':
$format = str_replace($match, $this->formatLongMonth($case), $format);
break;
case '%m':
$format = str_replace($match, $this->formatMonthZeros(), $format);
break;
case '%M':
$format = str_replace($match, $this->formatShortMonth(), $format);
break;
case '%n':
$format = str_replace($match, $this->formatMonth(), $format);
break;
case '%t':
$format = str_replace($match, $this->daysInMonth(), $format);
break;
case '%L':
$format = str_replace($match, (int) $this->isLeapYear(), $format);
break;
case '%Y':
$format = str_replace($match, $this->formatLongYear(), $format);
break;
case '%y':
$format = str_replace($match, $this->formatShortYear(), $format);
break;
// These 4 extensions are useful for re-formatting gedcom dates.
case '%@':
$format = str_replace($match, $this->calendar->gedcomCalendarEscape(), $format);
break;
case '%A':
$format = str_replace($match, $this->formatGedcomDay(), $format);
break;
case '%O':
$format = str_replace($match, $this->formatGedcomMonth(), $format);
break;
case '%E':
$format = str_replace($match, $this->formatGedcomYear(), $format);
break;
}
}
return $format;
}
/**
* Generate the %d format for a date.
*
* @return string
*/
protected function formatDayZeros() {
if ($this->d > 9) {
return I18N::digits($this->d);
} else {
return I18N::digits('0' . $this->d);
}
}
/**
* Generate the %j format for a date.
*
* @return string
*/
protected function formatDay() {
return I18N::digits($this->d);
}
/**
* Generate the %l format for a date.
*
* @return string
*/
protected function formatLongWeekday() {
return $this->dayNames($this->minJD % $this->calendar->daysInWeek());
}
/**
* Generate the %D format for a date.
*
* @return string
*/
protected function formatShortWeekday() {
return $this->dayNamesAbbreviated($this->minJD % $this->calendar->daysInWeek());
}
/**
* Generate the %N format for a date.
*
* @return string
*/
protected function formatIsoWeekday() {
return I18N::digits($this->minJD % 7 + 1);
}
/**
* Generate the %w format for a date.
*
* @return string
*/
protected function formatNumericWeekday() {
return I18N::digits(($this->minJD + 1) % $this->calendar->daysInWeek());
}
/**
* Generate the %z format for a date.
*
* @return string
*/
protected function formatDayOfYear() {
return I18N::digits($this->minJD - $this->calendar->ymdToJd($this->y, 1, 1));
}
/**
* Generate the %n format for a date.
*
* @return string
*/
protected function formatMonth() {
return I18N::digits($this->m);
}
/**
* Generate the %m format for a date.
*
* @return string
*/
protected function formatMonthZeros() {
if ($this->m > 9) {
return I18N::digits($this->m);
} else {
return I18N::digits('0' . $this->m);
}
}
/**
* Generate the %F format for a date.
*
* @param string $case Which grammatical case shall we use
*
* @return string
*/
protected function formatLongMonth($case = 'NOMINATIVE') {
switch ($case) {
case 'GENITIVE':
return $this->monthNameGenitiveCase($this->m, $this->isLeapYear());
case 'NOMINATIVE':
return $this->monthNameNominativeCase($this->m, $this->isLeapYear());
case 'LOCATIVE':
return $this->monthNameLocativeCase($this->m, $this->isLeapYear());
case 'INSTRUMENTAL':
return $this->monthNameInstrumentalCase($this->m, $this->isLeapYear());
default:
throw new \InvalidArgumentException($case);
}
}
/**
* Generate the %M format for a date.
*
* @return string
*/
protected function formatShortMonth() {
return $this->monthNameAbbreviated($this->m, $this->isLeapYear());
}
/**
* Generate the %y format for a date.
*
* NOTE Short year is NOT a 2-digit year. It is for calendars such as hebrew
* which have a 3-digit form of 4-digit years.
*
* @return string
*/
protected function formatShortYear() {
return $this->formatLongYear();
}
/**
* Generate the %A format for a date.
*
* @return string
*/
protected function formatGedcomDay() {
if ($this->d == 0) {
return '';
} else {
return sprintf('%02d', $this->d);
}
}
/**
* Generate the %O format for a date.
*
* @return string
*/
protected function formatGedcomMonth() {
// Our simple lookup table doesn't work correctly for Adar on leap years
if ($this->m == 7 && $this->calendar instanceof JewishCalendar && !$this->calendar->isLeapYear($this->y)) {
return 'ADR';
} else {
return array_search($this->m, static::$MONTH_ABBREV);
}
}
/**
* Generate the %E format for a date.
*
* @return string
*/
protected function formatGedcomYear() {
if ($this->y == 0) {
return '';
} else {
return sprintf('%04d', $this->y);
}
}
/**
* Generate the %Y format for a date.
*
* @return string
*/
protected function formatLongYear() {
return I18N::digits($this->y);
}
/**
* Which months follows this one? Calendars with leap-months should provide their own implementation.
*
* @return int[]
*/
protected function nextMonth() {
return array($this->m === $this->calendar->monthsInYear() ? $this->nextYear($this->y) : $this->y, ($this->m % $this->calendar->monthsInYear()) + 1);
}
/**
* Convert a decimal number to roman numerals
*
* @param int $number
*
* @return string
*/
protected function numberToRomanNumerals($number) {
if ($number < 1) {
// Cannot convert zero/negative numbers
return (string) $number;
}
$roman = '';
foreach (self::$roman_numerals as $key => $value) {
while ($number >= $key) {
$roman .= $value;
$number -= $key;
}
}
return $roman;
}
/**
* Convert a roman numeral to decimal
*
* @param string $roman
*
* @return int
*/
protected function romanNumeralsToNumber($roman) {
$num = 0;
foreach (self::$roman_numerals as $key => $value) {
if (strpos($roman, $value) === 0) {
$num += $key;
$roman = substr($roman, strlen($value));
}
}
return $num;
}
/**
* Get todays date in the current calendar.
*
* @return int[]
*/
public function todayYmd() {
return $this->calendar->jdToYmd(unixtojd());
}
/**
* Convert to todays date.
*
* @return CalendarDate
*/
public function today() {
$tmp = clone $this;
$ymd = $tmp->todayYmd();
$tmp->y = $ymd[0];
$tmp->m = $ymd[1];
$tmp->d = $ymd[2];
$tmp->setJdFromYmd();
return $tmp;
}
/**
* Create a URL that links this date to the WT calendar
*
* @param string $date_format
*
* @return string
*/
public function calendarUrl($date_format) {
if (strpbrk($date_format, 'dDj') && $this->d) {
// If the format includes a day, and the date also includes a day, then use the day view
$view = 'day';
} elseif (strpbrk($date_format, 'FMmn') && $this->m) {
// If the format includes a month, and the date also includes a month, then use the month view
$view = 'month';
} else {
// Use the year view
$view = 'year';
}
return
'calendar.php?cal=' . rawurlencode($this->calendar->gedcomCalendarEscape()) .
'&amp;year=' . $this->formatGedcomYear() .
'&amp;month=' . $this->formatGedcomMonth() .
'&amp;day=' . $this->formatGedcomDay() .
'&amp;view=' . $view;
}
}