X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;ds=sidebyside;f=src%2FUtil%2FTemporal.php;h=acafb66ab60538949a9b0cacd2540b19b2bc7382;hb=7b02585b978f7aef9d5c5a2c5d2b238cb674a4b7;hp=bc7639b3b740f102b2f6b32e162413c1e961f7ca;hpb=dc35d2f2f352b1f378a00dae37c6be3044c9a0a0;p=friendica.git diff --git a/src/Util/Temporal.php b/src/Util/Temporal.php index bc7639b3b7..acafb66ab6 100644 --- a/src/Util/Temporal.php +++ b/src/Util/Temporal.php @@ -1,60 +1,75 @@ . + * */ namespace Friendica\Util; use DateTime; use DateTimeZone; -use Friendica\Core\Config; -use Friendica\Core\L10n; -use Friendica\Core\PConfig; +use Friendica\Core\Renderer; use Friendica\Database\DBA; - -require_once 'boot.php'; -require_once 'include/text.php'; +use Friendica\DI; +use Friendica\Util\Clock\SystemClock; +use Psr\Clock\ClockInterface; /** - * @brief Temporal class + * Temporal class */ class Temporal { /** - * @brief Two-level sort for timezones. + * Two-level sort for timezones. * * @param string $a * @param string $b + * * @return int */ - private static function timezoneCompareCallback($a, $b) + private static function timezoneCompareCallback(string $a, string $b): int { if (strstr($a, '/') && strstr($b, '/')) { - if (L10n::t($a) == L10n::t($b)) { + if (DI::l10n()->t($a) == DI::l10n()->t($b)) { return 0; } - return (L10n::t($a) < L10n::t($b)) ? -1 : 1; + return (DI::l10n()->t($a) < DI::l10n()->t($b)) ? -1 : 1; } if (strstr($a, '/')) { return -1; } elseif (strstr($b, '/')) { return 1; - } elseif (L10n::t($a) == L10n::t($b)) { + } elseif (DI::l10n()->t($a) == DI::l10n()->t($b)) { return 0; } - return (L10n::t($a) < L10n::t($b)) ? -1 : 1; + return (DI::l10n()->t($a) < DI::l10n()->t($b)) ? -1 : 1; } /** - * @brief Emit a timezone selector grouped (primarily) by continent + * Emit a timezone selector grouped (primarily) by continent * * @param string $current Timezone + * * @return string Parsed HTML output */ - public static function getTimezoneSelect($current = 'America/Los_Angeles') + public static function getTimezoneSelect(string $current = 'America/Los_Angeles'): string { $timezone_identifiers = DateTimeZone::listIdentifiers(); @@ -70,7 +85,7 @@ class Temporal $o .= ''; } $continent = $ex[0]; - $o .= ''; + $o .= ''; } if (count($ex) > 2) { $city = substr($value, strpos($value, '/') + 1); @@ -79,13 +94,13 @@ class Temporal } } else { $city = $ex[0]; - if ($continent != L10n::t('Miscellaneous')) { + if ($continent != DI::l10n()->t('Miscellaneous')) { $o .= ''; - $continent = L10n::t('Miscellaneous'); - $o .= ''; + $continent = DI::l10n()->t('Miscellaneous'); + $o .= ''; } } - $city = str_replace('_', ' ', L10n::t($city)); + $city = str_replace('_', ' ', DI::l10n()->t($city)); $selected = (($value == $current) ? " selected=\"selected\" " : ""); $o .= ""; } @@ -94,62 +109,67 @@ class Temporal } /** - * @brief Generating a Timezone selector + * Generating a Timezone selector * * Return a select using 'field_select_raw' template, with timezones * grouped (primarily) by continent * arguments follow convention as other field_* template array: * 'name', 'label', $value, 'help' * - * @param string $name Name of the selector - * @param string $label Label for the selector + * @param string $name Name of the selector + * @param string $label Label for the selector * @param string $current Timezone - * @param string $help Help text + * @param string $help Help text * * @return string Parsed HTML + * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function getTimezoneField($name = 'timezone', $label = '', $current = 'America/Los_Angeles', $help = '') + public static function getTimezoneField(string $name = 'timezone', string $label = '', string $current = 'America/Los_Angeles', string $help = ''): string { $options = self::getTimezoneSelect($current); $options = str_replace('', '', $options); - $tpl = get_markup_template('field_select_raw.tpl'); - return replace_macros($tpl, [ + $tpl = Renderer::getMarkupTemplate('field_select_raw.tpl'); + return Renderer::replaceMacros($tpl, [ '$field' => [$name, $label, $current, $help, $options], ]); } /** - * @brief Wrapper for date selector, tailored for use in birthday fields. + * Wrapper for date selector, tailored for use in birthday fields. * * @param string $dob Date of Birth + * @param string $timezone + * * @return string Formatted HTML + * @throws \Exception */ - public static function getDateofBirthField($dob) + public static function getDateofBirthField(string $dob, string $timezone = 'UTC'): string { - $a = get_app(); - list($year, $month, $day) = sscanf($dob, '%4d-%2d-%2d'); if ($dob < '0000-01-01') { $value = ''; + $age = 0; + } elseif ($dob < '0001-00-00') { + $value = substr($dob, 5); + $age = 0; } else { - $value = DateTimeFormat::utc(($year > 1000) ? $dob : '1000-' . $month . '-' . $day, 'Y-m-d'); + $value = DateTimeFormat::utc($dob, 'Y-m-d'); + $age = self::getAgeByTimezone($value, $timezone); } - $age = (intval($value) ? self::getAgeByTimezone($value, $a->user["timezone"], $a->user["timezone"]) : ""); - - $tpl = get_markup_template("field_input.tpl"); - $o = replace_macros($tpl, + $tpl = Renderer::getMarkupTemplate("field_input.tpl"); + $o = Renderer::replaceMacros($tpl, [ '$field' => [ 'dob', - L10n::t('Birthday:'), + DI::l10n()->t('Birthday:'), $value, - intval($age) > 0 ? L10n::t('Age: ') . $age : "", + intval($age) > 0 ? DI::l10n()->t('Age: ') . DI::l10n()->tt('%d year old', '%d years old', $age) : '', '', - 'placeholder="' . L10n::t('YYYY-MM-DD or MM-DD') . '"' + 'placeholder="' . DI::l10n()->t('YYYY-MM-DD or MM-DD') . '"' ] ]); @@ -157,40 +177,43 @@ class Temporal } /** - * @brief Returns a date selector + * Returns a date selector * - * @param string $min Unix timestamp of minimum date - * @param string $max Unix timestap of maximum date - * @param string $default Unix timestamp of default date - * @param string $id ID and name of datetimepicker (defaults to "datetimepicker") + * @param DateTime $min Minimum date + * @param DateTime $max Maximum date + * @param DateTime $default Default date + * @param string $id ID and name of datetimepicker (defaults to "datetimepicker") * * @return string Parsed HTML output. + * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function getDateField($min, $max, $default, $id = 'datepicker') + public static function getDateField(DateTime $min, DateTime $max, DateTime $default, string $id = 'datepicker'): string { return self::getDateTimeField($min, $max, $default, '', $id, true, false, '', ''); } /** - * @brief Returns a time selector + * Returns a time selector * * @param string $h Already selected hour * @param string $m Already selected minute * @param string $id ID and name of datetimepicker (defaults to "timepicker") * * @return string Parsed HTML output. + * @throws \Exception */ - public static function getTimeField($h, $m, $id = 'timepicker') + public static function getTimeField(string $h, string $m, string $id = 'timepicker'): string { return self::getDateTimeField(new DateTime(), new DateTime(), new DateTime("$h:$m"), '', $id, false, true); } /** - * @brief Returns a datetime selector. + * Returns a datetime selector. * * @param DateTime $minDate Minimum date * @param DateTime $maxDate Maximum date * @param DateTime $defaultDate Default date + * @param $label * @param string $id Id and name of datetimepicker (defaults to "datetimepicker") * @param bool $pickdate true to show date picker (default) * @param bool $picktime true to show time picker (default) @@ -200,30 +223,31 @@ class Temporal * * @return string Parsed HTML output. * - * @todo Once browser support is better this could probably be replaced with + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @todo Once browser support is better this could probably be replaced with * native HTML5 date picker. */ public static function getDateTimeField( DateTime $minDate, DateTime $maxDate, - DateTime $defaultDate, + DateTime $defaultDate = null, $label, - $id = 'datetimepicker', - $pickdate = true, - $picktime = true, - $minfrom = '', - $maxfrom = '', - $required = false) + string $id = 'datetimepicker', + bool $pickdate = true, + bool $picktime = true, + string $minfrom = '', + string $maxfrom = '', + bool $required = false): string { // First day of the week (0 = Sunday) - $firstDay = PConfig::get(local_user(), 'system', 'first_day_of_week', 0); + $firstDay = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'calendar', 'first_day_of_week', 0); - $lang = substr(L10n::getCurrentLang(), 0, 2); + $lang = substr(DI::l10n()->getCurrentLang(), 0, 2); // Check if the detected language is supported by the picker if (!in_array($lang, - ["ar", "ro", "id", "bg", "fa", "ru", "uk", "en", "el", "de", "nl", "tr", "fr", "es", "th", "pl", "pt", "ch", "se", "kr", - "it", "da", "no", "ja", "vi", "sl", "cs", "hu"])) { + ['ar', 'ro', 'id', 'bg', 'fa', 'ru', 'uk', 'en', 'el', 'de', 'nl', 'tr', 'fr', 'es', 'th', 'pl', 'pt', 'ch', 'se', 'kr', + 'it', 'da', 'no', 'ja', 'vi', 'sl', 'cs', 'hu'])) { $lang = 'en'; } @@ -246,13 +270,17 @@ class Temporal $readable_format = str_replace(['Y', 'm', 'd', 'H', 'i'], ['yyyy', 'mm', 'dd', 'HH', 'MM'], $dateformat); - $tpl = get_markup_template('field_datetime.tpl'); - $o .= replace_macros($tpl, [ + $tpl = Renderer::getMarkupTemplate('field_datetime.tpl'); + $o .= Renderer::replaceMacros($tpl, [ '$field' => [ $id, $label, $input_text, - '', + DI::l10n()->t( + 'Time zone: %s Change in Settings', + str_replace('_', ' ', DI::app()->getTimeZone()) . ' (GMT ' . DateTimeFormat::localNow('P') . ')', + DI::baseUrl() . '/settings' + ), $required ? '*' : '', 'placeholder="' . $readable_format . '"' ], @@ -265,41 +293,54 @@ class Temporal 'lang' => $lang, 'minfrom' => $minfrom, 'maxfrom' => $maxfrom, - ] + ], ]); return $o; } /** - * @brief Returns a relative date string. + * Returns a relative date string. * * Implements "3 seconds ago" etc. * Based on $posted_date, (UTC). * Results relative to current timezone. * Limited to range of timestamps. * - * @param string $posted_date MySQL-formatted date string (YYYY-MM-DD HH:MM:SS) - * @param string $format (optional) Parsed with sprintf() - * %1$d %2$s ago, e.g. 22 hours ago, 1 minute ago + * @param string|null $posted_date MySQL-formatted date string (YYYY-MM-DD HH:MM:SS) + * @param bool $compare_time Compare date (false) or date and time (true). "true" is default. + * @param ClockInterface|null $clock + * %1$d %2$s ago, e.g. 22 hours ago, 1 minute ago * * @return string with relative date */ - public static function getRelativeDate($posted_date, $format = null) + public static function getRelativeDate(string $posted_date = null, bool $compare_time = true, ClockInterface $clock = null): string { - $localtime = $posted_date . ' UTC'; + if (empty($posted_date) || $posted_date <= DBA::NULL_DATETIME) { + return DI::l10n()->t('never'); + } + + $clock = $clock ?? new SystemClock(); + $localtime = $posted_date . ' UTC'; $abs = strtotime($localtime); - if (is_null($posted_date) || $posted_date <= DBA::NULL_DATETIME || $abs === false) { - return L10n::t('never'); + if ($abs === false) { + return DI::l10n()->t('never'); + } + + $now = $clock->now()->getTimestamp(); + + if (!$compare_time) { + $now = mktime(0, 0, 0, date('m', $now), date('d', $now), date('Y', $now)); + $abs = mktime(0, 0, 0, date('m', $abs), date('d', $abs), date('Y', $abs)); } $isfuture = false; - $etime = time() - $abs; + $etime = $now - $abs; - if ($etime < 1 && $etime >= 0) { - return L10n::t('less than a second ago'); + if ($etime >= 0 && $etime < 1) { + return $compare_time ? DI::l10n()->t('less than a second ago') : DI::l10n()->t('today'); } if ($etime < 0){ @@ -307,27 +348,26 @@ class Temporal $isfuture = true; } - $a = [12 * 30 * 24 * 60 * 60 => [L10n::t('year'), L10n::t('years')], - 30 * 24 * 60 * 60 => [L10n::t('month'), L10n::t('months')], - 7 * 24 * 60 * 60 => [L10n::t('week'), L10n::t('weeks')], - 24 * 60 * 60 => [L10n::t('day'), L10n::t('days')], - 60 * 60 => [L10n::t('hour'), L10n::t('hours')], - 60 => [L10n::t('minute'), L10n::t('minutes')], - 1 => [L10n::t('second'), L10n::t('seconds')] + $a = [ + 12 * 30 * 24 * 60 * 60 => [DI::l10n()->t('year'), DI::l10n()->t('years')], + 30 * 24 * 60 * 60 => [DI::l10n()->t('month'), DI::l10n()->t('months')], + 7 * 24 * 60 * 60 => [DI::l10n()->t('week'), DI::l10n()->t('weeks')], + 24 * 60 * 60 => [DI::l10n()->t('day'), DI::l10n()->t('days')], + 60 * 60 => [DI::l10n()->t('hour'), DI::l10n()->t('hours')], + 60 => [DI::l10n()->t('minute'), DI::l10n()->t('minutes')], + 1 => [DI::l10n()->t('second'), DI::l10n()->t('seconds')], ]; foreach ($a as $secs => $str) { $d = $etime / $secs; if ($d >= 1) { - $r = round($d); + $r = floor($d); // translators - e.g. 22 hours ago, 1 minute ago - if (!$format) { - if($isfuture){ - $format = L10n::t('in %1$d %2$s'); - } - else { - $format = L10n::t('%1$d %2$s ago'); - } + if($isfuture){ + $format = DI::l10n()->t('in %1$d %2$s'); + } + else { + $format = DI::l10n()->t('%1$d %2$s ago'); } return sprintf($format, $r, (($r == 1) ? $str[0] : $str[1])); @@ -336,53 +376,33 @@ class Temporal } /** - * @brief Returns timezone correct age in years. + * Returns timezone correct age in years. * - * Returns the age in years, given a date of birth, the timezone of the person - * whose date of birth is provided, and the timezone of the person viewing the - * result. + * Returns the age in years, given a date of birth and the timezone of the person + * whose date of birth is provided. * - * Why? Bear with me. Let's say I live in Mittagong, Australia, and my birthday - * is on New Year's. You live in San Bruno, California. - * When exactly are you going to see my age increase? - * - * A: 5:00 AM Dec 31 San Bruno time. That's precisely when I start celebrating - * and become a year older. If you wish me happy birthday on January 1 - * (San Bruno time), you'll be a day late. - * - * @param string $dob Date of Birth - * @param string $owner_tz (optional) Timezone of the person of interest - * @param string $viewer_tz (optional) Timezone of the person viewing + * @param string $dob Date of Birth + * @param string $timezone Timezone of the person of interest * * @return int Age in years + * @throws \Exception */ - public static function getAgeByTimezone($dob, $owner_tz = '', $viewer_tz = '') + public static function getAgeByTimezone(string $dob, string $timezone): int { if (!intval($dob)) { return 0; } - if (!$owner_tz) { - $owner_tz = date_default_timezone_get(); - } - if (!$viewer_tz) { - $viewer_tz = date_default_timezone_get(); - } - $birthdate = DateTimeFormat::convert($dob . ' 00:00:00+00:00', $owner_tz, 'UTC', 'Y-m-d'); - list($year, $month, $day) = explode("-", $birthdate); - $year_diff = DateTimeFormat::timezoneNow($viewer_tz, 'Y') - $year; - $curr_month = DateTimeFormat::timezoneNow($viewer_tz, 'm'); - $curr_day = DateTimeFormat::timezoneNow($viewer_tz, 'd'); + $birthdate = new DateTime($dob . ' 00:00:00', new DateTimeZone($timezone)); + $currentDate = new DateTime('now', new DateTimeZone('UTC')); - if (($curr_month < $month) || (($curr_month == $month) && ($curr_day < $day))) { - $year_diff--; - } + $interval = $birthdate->diff($currentDate); - return $year_diff; + return (int) $interval->format('%y'); } /** - * @brief Get days of a month in a given year. + * Get days of a month in a given year. * * Returns number of days in the month of the given year. * $m = 1 is 'January' to match human usage. @@ -392,13 +412,13 @@ class Temporal * * @return int Number of days in the given month */ - public static function getDaysInMonth($y, $m) + public static function getDaysInMonth(int $y, int $m): int { return date('t', mktime(0, 0, 0, $m, 1, $y)); } /** - * @brief Returns the first day in month for a given month, year. + * Returns the first day in month for a given month, year. * * Months start at 1. * @@ -406,8 +426,9 @@ class Temporal * @param int $m Month (1=January, 12=December) * * @return string day 0 = Sunday through 6 = Saturday + * @throws \Exception */ - private static function getFirstDayInMonth($y, $m) + private static function getFirstDayInMonth(int $y, int $m): string { $d = sprintf('%04d-%02d-01 00:00', intval($y), intval($m)); @@ -415,23 +436,24 @@ class Temporal } /** - * @brief Output a calendar for the given month, year. + * Output a calendar for the given month, year. * * If $links are provided (array), e.g. $links[12] => 'http://mylink' , * date 12 will be linked appropriately. Today's date is also noted by * altering td class. * Months count from 1. * - * @param int $y Year - * @param int $m Month + * @param int $y Year + * @param int $m Month * @param array $links (default null) * @param string $class * * @return string * - * @todo Provide (prev, next) links, define class variations for different size calendars + * @throws \Exception + * @todo Provide (prev, next) links, define class variations for different size calendars */ - public static function getCalendarTable($y = 0, $m = 0, $links = null, $class = '') + public static function getCalendarTable(int $y = 0, int $m = 0, array $links = null, string $class = ''): string { // month table - start at 1 to match human usage. $mtab = [' ', @@ -462,11 +484,11 @@ class Temporal $tddate = intval(DateTimeFormat::localNow('j')); } - $str_month = day_translate($mtab[$m]); + $str_month = DI::l10n()->getDay($mtab[$m]); $o = ''; $o .= ""; for ($a = 0; $a < 7; $a ++) { - $o .= ''; + $o .= ''; } $o .= ''; @@ -480,7 +502,7 @@ class Temporal $o .= "
$str_month $y
' . mb_substr(day_translate($dn[$a]), 0, 3, 'UTF-8') . '' . mb_substr(DI::l10n()->getDay($dn[$a]), 0, 3, 'UTF-8') . '
"; $day = str_replace(' ', ' ', sprintf('%2.2d', $d)); if ($started) { - if (x($links, $d) !== false) { + if (isset($links[$d])) { $o .= "$day"; } else { $o .= $day;