diff --git a/src/app/Dates.php b/src/app/Dates.php new file mode 100644 index 0000000..4448f8b --- /dev/null +++ b/src/app/Dates.php @@ -0,0 +1,107 @@ + $singular ? 'less than a minute' : 'less than %i minutes', + DistanceFormat::XMinutes => $singular ? 'a minute' : '%i minutes', + DistanceFormat::AboutXHours => $singular ? 'about an hour' : 'about %i hours', + DistanceFormat::XHours => $singular ? 'an hour' : '%i hours', + DistanceFormat::XDays => $singular ? 'a day' : '%i days', + DistanceFormat::AboutXWeeks => $singular ? 'about a week' : 'about %i weeks', + DistanceFormat::XWeeks => $singular ? 'a week' : '%i weeks', + DistanceFormat::AboutXMonths => $singular ? 'about a month' : 'about %i months', + DistanceFormat::XMonths => $singular ? 'a month' : '%i months', + DistanceFormat::AboutXYears => $singular ? 'about a year' : 'about %i years', + DistanceFormat::XYears => $singular ? 'a year' : '%i years', + DistanceFormat::OverXYears => $singular ? 'over a year' : 'over %i years', + DistanceFormat::AlmostXYears => $singular ? 'almost a year' : 'almost %i years', + }; + } +} + +class Dates +{ + /** Minutes in a day */ + private const A_DAY = 1_440; + + /** Minutes in two days(-ish) */ + private const ALMOST_2_DAYS = 2_520; + + /** Minutes in a month */ + private const A_MONTH = 43_200; + + /** Minutes in two months */ + private const TWO_MONTHS = 86_400; + + /** + * Get a UTC-referenced current date/time + * + * @return \DateTimeImmutable The current date/time with UTC reference + */ + public static function now(): \DateTimeImmutable + { + return new \DateTimeImmutable(timezone: new \DateTimeZone('Etc/UTC')); + } + + /** + * Format the distance between two instants in approximate English terms + * + * @param \DateTimeInterface $startOn The starting date/time for the comparison + * @param \DateTimeInterface $endOn THe ending date/time for the comparison + * @return string The formatted interval + */ + public static function formatDistance(\DateTimeInterface $startOn, \DateTimeInterface $endOn): string + { + $diff = $startOn->diff($endOn); + $minutes = + $diff->i + ($diff->h * 60) + ($diff->d * 60 * 24) + ($diff->m * 60 * 24 * 30) + ($diff->y * 60 * 24 * 365); + $months = round($minutes / self::A_MONTH); + $years = $months / 12; + [ $format, $number ] = match (true) { + $minutes < 1 => [ DistanceFormat::LessThanXMinutes, 1 ], + $minutes < 45 => [ DistanceFormat::XMinutes, $minutes ], + $minutes < 90 => [ DistanceFormat::AboutXHours, 1 ], + $minutes < self::A_DAY => [ DistanceFormat::AboutXHours, round($minutes / 60) ], + $minutes < self::ALMOST_2_DAYS => [ DistanceFormat::XDays, 1 ], + $minutes < self::A_MONTH => [ DistanceFormat::XDays, round($minutes / self::A_DAY) ], + $minutes < self::TWO_MONTHS => [ DistanceFormat::AboutXMonths, round($minutes / self::A_MONTH) ], + $months < 12 => [ DistanceFormat::XMonths, round($minutes / self::A_MONTH) ], + $months % 12 < 3 => [ DistanceFormat::AboutXYears, $years ], + $months % 12 < 9 => [ DistanceFormat::OverXYears, $years ], + default => [ DistanceFormat::AlmostXYears, $years + 1 ], + }; + + $relativeWords = sprintf(DistanceFormat::format($format, $number == 1), $number); + return $startOn > $endOn ? "$relativeWords ago" : "in $relativeWords"; + } +} diff --git a/src/app/index.php b/src/app/index.php index 7d159a3..110c2c7 100644 --- a/src/app/index.php +++ b/src/app/index.php @@ -38,6 +38,16 @@ app()->group('/user', function () { app()->get('/log-off', AppUser::logOff(...)); }); +// Extract the user's time zone from the request, if present +app()->use(new class extends \Leaf\Middleware { + public function call() + { + $_REQUEST['USER_TIME_ZONE'] = new \DateTimeZone( + array_key_exists('HTTP_X_TIME_ZONE', $_SERVER) ? $_SERVER['HTTP_X_TIME_ZONE'] : 'Etc/UTC'); + $this->next(); + } +}); + // TODO: remove before go-live $stdOut = fopen('php://stdout', 'w'); function stdout(string $msg) diff --git a/src/app/pages/components/journal_card.view.php b/src/app/pages/components/journal_card.view.php index 59ad0fc..9458802 100644 --- a/src/app/pages/components/journal_card.view.php +++ b/src/app/pages/components/journal_card.view.php @@ -1,5 +1,18 @@ '; ?> +use MyPrayerJournal\Dates; + +$spacer = ' '; +/** + * Format the activity and relative time + * + * @param string $activity The activity performed (activity or prayed) + * @param \DateTimeImmutable $asOf The date/time the activity was performed + */ +function formatActivity(string $activity, \DateTimeImmutable $asOf) +{ + echo "last $activity setTimezone($_REQUEST['USER_TIME_ZONE'])->format('l, F jS, Y/g:ia T') + . '">' . Dates::formatDistance(Dates::now(), $asOf) . ''; +} ?>
+
Loading your prayer journal…