mirror of
https://github.com/Sarjuuk/aowow.git
synced 2025-11-29 15:58:16 +08:00
223 lines
7.0 KiB
PHP
223 lines
7.0 KiB
PHP
<?php
|
|
|
|
namespace Aowow;
|
|
|
|
if (!defined('AOWOW_REVISION'))
|
|
die('illegal access');
|
|
|
|
|
|
class DateTime extends \DateTimeImmutable
|
|
{
|
|
// in msec yr mo w d h m s ms
|
|
private const /* array */ RANGE = [31557600000, 2629800000, 604800000, 86400000, 3600000, 60000, 1000, 1];
|
|
private const /* string */ NBSP = "\u{00A0}"; // \u00A0 is usable by js
|
|
|
|
public function __construct(int $seconds = 0)
|
|
{
|
|
$datetime = $seconds ? date(DATE_ATOM, $seconds) : 'now';
|
|
parent::__construct($datetime);
|
|
}
|
|
|
|
/**
|
|
* Adaptive, human-readable format of a date
|
|
* exact date if larger than 1 month
|
|
* relative days/time if smaller than 1 month
|
|
*
|
|
* @param int $timestamp unix timestamp to display
|
|
* @param bool $withTime [optional] append time on exact dates
|
|
* @return string adaptive date/time string
|
|
*/
|
|
public function formatDate(int $timestamp, bool $withTime = false) : string
|
|
{
|
|
$txt = '';
|
|
$elapsed = abs($this->getTimestamp() - $timestamp);
|
|
|
|
$today = new DateTime();
|
|
$eventDay = new DateTime(time() - $elapsed);
|
|
|
|
$todayMidnight = $today->setTime(0, 0);
|
|
$eventDayMidnight = $eventDay->setTime(0, 0);
|
|
|
|
$delta = $todayMidnight->diff($eventDayMidnight, true)->days;
|
|
|
|
if ($elapsed >= 2592000) /* More than a month ago */
|
|
$txt = Lang::main('date_on') . $eventDay->formatDateSimple($withTime);
|
|
else if ($delta > 1)
|
|
$txt = Lang::main('ddaysago', [$delta]);
|
|
else if ($elapsed >= 43200)
|
|
{
|
|
if ($today->format('j') == $eventDay->format('j'))
|
|
$txt = Lang::main('today');
|
|
else
|
|
$txt = Lang::main('yesterday');
|
|
|
|
$txt = $eventDay->formatTimeSimple($txt);
|
|
}
|
|
else /* Less than 12 hours ago */
|
|
$txt = Lang::main('date_ago', [self::formatTimeElapsed($elapsed * 1000)]);
|
|
|
|
return $txt;
|
|
}
|
|
|
|
/**
|
|
* Human-readable format of a date. Optionally append time of day.
|
|
*
|
|
* @param bool $withTime [optional] affixes day time
|
|
* @return string a formatted date string.
|
|
*/
|
|
public function formatDateSimple(bool $withTime = false) : string
|
|
{
|
|
$txt = '';
|
|
$day = $this->format('d');
|
|
$month = $this->format('m');
|
|
$year = $this->format('Y');
|
|
|
|
if ($year <= 1970)
|
|
$txt .= Lang::main('unknowndate_stc');
|
|
else
|
|
$txt .= Lang::main('date_simple', [$day, $month, $year]);
|
|
|
|
if ($withTime)
|
|
$txt = $this->formatTimeSimple($txt);
|
|
|
|
return $txt;
|
|
}
|
|
|
|
/**
|
|
* Human-readable format of the time of day.
|
|
*
|
|
* @param string $txt [optional] text to affeix the day time to
|
|
* @param bool $noPrefix [optional] don't use " at " to affix time of day to $txt
|
|
* @return string a formatted time of day string.
|
|
*/
|
|
public function formatTimeSimple(string $txt = '', bool $noPrefix = false) : string
|
|
{
|
|
$hours = $this->format('G');
|
|
$minutes = $this->format('i');
|
|
|
|
$txt .= ($noPrefix ? ' ' : Lang::main('date_at'));
|
|
|
|
if ($hours == 12)
|
|
$txt .= Lang::main('noon');
|
|
else if ($hours == 0)
|
|
$txt .= Lang::main('midnight');
|
|
else if ($hours > 12)
|
|
$txt .= ($hours - 12) . ':' . $minutes . ' ' . Lang::main('pm');
|
|
else
|
|
$txt .= $hours . ':' . $minutes . ' ' . Lang::main('am');
|
|
|
|
return $txt;
|
|
}
|
|
|
|
/**
|
|
* Calculate component values from timestamp
|
|
*
|
|
* @param int $msec time in milliseconds to parse
|
|
* @return int[] [msec, sec, min, hr, day]
|
|
*/
|
|
public static function parse(int $msec) : array
|
|
{
|
|
$time = [0, 0, 0, 0, 0];
|
|
$msec = abs($msec);
|
|
|
|
for ($i = 3; $i < count(self::RANGE); ++$i)
|
|
{
|
|
if ($msec < self::RANGE[$i])
|
|
continue;
|
|
|
|
$time[7 - $i] = intVal($msec / self::RANGE[$i]);
|
|
$msec %= self::RANGE[$i];
|
|
}
|
|
|
|
return $time;
|
|
}
|
|
|
|
/**
|
|
* Human-readable longform format of a timespan.
|
|
*
|
|
* @param int $delay time in milliseconds to format
|
|
* @return string a formatted time string. If an error occured "n/a" (localized) is returned
|
|
*/
|
|
public static function formatTimeElapsedFloat(int $delay) : string
|
|
{
|
|
$delay = abs($delay);
|
|
$nbsp = Lang::getLocale()->isLogographic() ? '' : self::NBSP;
|
|
|
|
for ($i = 0; $i < count(self::RANGE); ++$i)
|
|
{
|
|
if ($delay < self::RANGE[$i])
|
|
continue;
|
|
|
|
$v = round($delay / self::RANGE[$i], 2);
|
|
return $v . $nbsp . Lang::timeUnits($v === 1.0 ? 'sg' : 'pl', $i);
|
|
}
|
|
|
|
return '0' . $nbsp . Lang::timeUnits('pl', 6); // 0 seconds
|
|
}
|
|
|
|
/**
|
|
* Human-readable format of a timespan.
|
|
*
|
|
* @param int $delay time in milliseconds to format
|
|
* @param int $maxRange [optional] time unit index - 0 (year) ... 7 (milliseconds)
|
|
* @return string a formatted time string. If an error occured "n/a" (localized) is returned
|
|
*/
|
|
public static function formatTimeElapsed(int $delay, int $maxRange = 3) : string
|
|
{
|
|
if ($maxRange > 7 || $maxRange < 0)
|
|
$maxRange = 3; // default: days
|
|
|
|
$subunit = [1, 3, 3, -1, 5, -1, 7, -1];
|
|
$delay = max($delay, 1);
|
|
|
|
for ($i = $maxRange; $i < count(self::RANGE); ++$i)
|
|
{
|
|
if ($delay >= self::RANGE[$i])
|
|
{
|
|
$i1 = $i;
|
|
$v1 = floor($delay / self::RANGE[$i1]);
|
|
|
|
if ($subunit[$i1] != -1)
|
|
{
|
|
$i2 = $subunit[$i1];
|
|
$delay %= self::RANGE[$i1];
|
|
$v2 = floor($delay / self::RANGE[$i2]);
|
|
$nbsp = Lang::getLocale()->isLogographic() ? '' : self::NBSP;
|
|
|
|
if ($v2 > 0)
|
|
return self::OMG($v1, $i1, true) . $nbsp . self::OMG($v2, $i2, true);
|
|
}
|
|
|
|
return self::OMG($v1, $i1, false);
|
|
}
|
|
}
|
|
|
|
return Lang::main('n_a');
|
|
}
|
|
|
|
/**
|
|
* internal number formatter
|
|
*
|
|
* @param int $value unit value
|
|
* @param int $unit time unit index 0 (year) ... 7 (milliseconds)
|
|
* @param bool $abbrv use abbreviation
|
|
* @return string value + unit
|
|
*/
|
|
private static function OMG(int $value, int $unit, bool $abbrv) : string
|
|
{
|
|
if ($abbrv && !Lang::timeUnits('ab', $unit))
|
|
$abbrv = false;
|
|
|
|
$nbsp = Lang::getLocale()->isLogographic() ? '' : self::NBSP;
|
|
|
|
return $value .= $nbsp . match(true)
|
|
{
|
|
$abbrv => Lang::timeUnits('ab', $unit),
|
|
$value == 1 => Lang::timeUnits('sg', $unit),
|
|
default => Lang::timeUnits('pl', $unit)
|
|
};
|
|
}
|
|
}
|
|
|
|
?>
|