@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.)
hq.recaptime.dev/wiki/Phorge
phorge
phabricator
1<?php
2
3function phabricator_date($epoch, PhabricatorUser $user) {
4 return phabricator_format_local_time(
5 $epoch,
6 $user,
7 phutil_date_format($epoch));
8}
9
10function phabricator_relative_date($epoch, $user, $on = false) {
11 static $today;
12 static $yesterday;
13
14 if (!$today || !$yesterday) {
15 $now = time();
16 $today = phabricator_date($now, $user);
17 $yesterday = phabricator_date($now - 86400, $user);
18 }
19
20 $date = phabricator_date($epoch, $user);
21
22 if ($date === $today) {
23 return 'today';
24 }
25
26 if ($date === $yesterday) {
27 return 'yesterday';
28 }
29
30 return (($on ? 'on ' : '').$date);
31}
32
33function phabricator_time($epoch, $user) {
34 $time_key = PhabricatorTimeFormatSetting::SETTINGKEY;
35 return phabricator_format_local_time(
36 $epoch,
37 $user,
38 $user->getUserSetting($time_key));
39}
40
41function phabricator_dual_datetime($epoch, $user) {
42 $screen_view = phabricator_datetime($epoch, $user);
43 $print_view = phabricator_absolute_datetime($epoch, $user);
44
45 $screen_tag = javelin_tag(
46 'span',
47 array(
48 'print' => false,
49 ),
50 $screen_view);
51
52 $print_tag = javelin_tag(
53 'span',
54 array(
55 'print' => true,
56 ),
57 $print_view);
58
59 return array(
60 $screen_tag,
61 $print_tag,
62 );
63}
64
65function phabricator_absolute_datetime($epoch, $user) {
66 $format = 'Y-m-d H:i:s (\\U\\T\\CP)';
67
68 $datetime = phabricator_format_local_time($epoch, $user, $format);
69 $datetime = preg_replace('/(UTC[+-])0?([^:]+)(:00)?/', '\\1\\2', $datetime);
70
71 return $datetime;
72}
73
74function phabricator_datetime($epoch, $user) {
75 $time_key = PhabricatorTimeFormatSetting::SETTINGKEY;
76 return phabricator_format_local_time(
77 $epoch,
78 $user,
79 pht('%s, %s',
80 phutil_date_format($epoch),
81 $user->getUserSetting($time_key)));
82}
83
84function phabricator_datetimezone($epoch, $user) {
85 $datetime = phabricator_datetime($epoch, $user);
86 $timezone = phabricator_format_local_time($epoch, $user, 'T');
87
88 // Some obscure timezones just render as "+03" or "-09". Make these render
89 // as "UTC+3" instead.
90 if (preg_match('/^[+-]/', $timezone)) {
91 $timezone = (int)trim($timezone, '+');
92 if ($timezone < 0) {
93 $timezone = pht('UTC-%s', $timezone);
94 } else {
95 $timezone = pht('UTC+%s', $timezone);
96 }
97 }
98
99 return pht('%s (%s)', $datetime, $timezone);
100}
101
102
103/**
104 * Applies the user's timezone preferences to convert the give
105 * epoch (number of seconds since January 1, 1970) to a DateTime object
106 * @param int $epoch Unix epoch timestamp.
107 * @param PhabricatorUser $user User viewing the timestamp.
108 * @return ?DateTime
109 */
110function phorge_localize_time($epoch, $user) {
111 if (!$epoch) {
112 // If we're missing date information for something, the DateTime class will
113 // throw an exception when we try to construct an object.
114 return null;
115 }
116 $user_zone = $user->getTimezoneIdentifier();
117
118 static $zones = array();
119 if (empty($zones[$user_zone])) {
120 $zones[$user_zone] = new DateTimeZone($user_zone);
121 }
122 $zone = $zones[$user_zone];
123
124 // NOTE: Although DateTime takes a second DateTimeZone parameter to its
125 // constructor, it ignores it if the date string includes timezone
126 // information. Further, it treats epoch timestamps ("@946684800") as having
127 // a UTC timezone. Set the timezone explicitly after constructing the object.
128 try {
129 $date = new DateTime('@'.$epoch);
130 } catch (Exception $ex) {
131 // NOTE: DateTime throws an empty exception if the format is invalid,
132 // just replace it with a useful one.
133 throw new Exception(
134 pht("Construction of a DateTime() with epoch '%s' ".
135 "raised an exception.", $epoch));
136 }
137
138 $date->setTimezone($zone);
139 return $date;
140}
141
142/**
143 * This function does not usually need to be called directly. Instead, call
144 * @{function:phabricator_date}, @{function:phabricator_time}, or
145 * @{function:phabricator_datetime}.
146 *
147
148 * @param string $format Date format, as per DateTime class.
149 * @return string Formatted, local date/time.
150 */
151function phabricator_format_local_time($epoch, $user, $format) {
152 $date = phorge_localize_time($epoch, $user);
153 if (!$date) {
154 // If we're missing date information for something, display that as
155 // an empty string
156 return '';
157 }
158 return PhutilTranslator::getInstance()->translateDate($format, $date);
159}