diff --git a/resources/sql/patches/045.timezone.sql b/resources/sql/patches/045.timezone.sql
new file mode 100644
index 0000000000..49c402b25b
--- /dev/null
+++ b/resources/sql/patches/045.timezone.sql
@@ -0,0 +1,2 @@
+ALTER TABLE phabricator_user.user
+ ADD timezoneIdentifier varchar(255) NOT NULL DEFAULT "America/Los_Angeles";
\ No newline at end of file
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
index a9898fe78c..8e5a404477 100644
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -539,10 +539,13 @@ phutil_register_library_map(array(
'celerity_generate_unique_node_id' => 'infrastructure/celerity/api',
'celerity_register_resource_map' => 'infrastructure/celerity/map',
'javelin_render_tag' => 'infrastructure/javelin/markup',
+ 'phabricator_date' => 'view/utils',
+ 'phabricator_datetime' => 'view/utils',
'phabricator_format_relative_time' => 'view/utils',
'phabricator_format_timestamp' => 'view/utils',
'phabricator_format_units_generic' => 'view/utils',
'phabricator_render_form' => 'infrastructure/javelin/markup',
+ 'phabricator_time' => 'view/utils',
'qsprintf' => 'storage/qsprintf',
'queryfx' => 'storage/queryfx',
'queryfx_all' => 'storage/queryfx',
diff --git a/src/applications/diffusion/controller/commit/DiffusionCommitController.php b/src/applications/diffusion/controller/commit/DiffusionCommitController.php
index ed34a9bf65..7958195639 100644
--- a/src/applications/diffusion/controller/commit/DiffusionCommitController.php
+++ b/src/applications/diffusion/controller/commit/DiffusionCommitController.php
@@ -23,6 +23,7 @@ class DiffusionCommitController extends DiffusionController {
public function processRequest() {
$drequest = $this->getDiffusionRequest();
$request = $this->getRequest();
+ $user = $request->getUser();
$callsign = $drequest->getRepository()->getCallsign();
@@ -56,7 +57,7 @@ class DiffusionCommitController extends DiffusionController {
'
'.
'r'.$callsign.$commit->getCommitIdentifier().
' · '.
- date('F jS, Y g:i A', $commit->getEpoch()).
+ phabricator_datetime($commit->getEpoch(), $user).
'
'.
'Revision Detail
'.
''.
diff --git a/src/applications/diffusion/controller/commit/__init__.php b/src/applications/diffusion/controller/commit/__init__.php
index 60201c6b8a..70cfe04c4c 100644
--- a/src/applications/diffusion/controller/commit/__init__.php
+++ b/src/applications/diffusion/controller/commit/__init__.php
@@ -20,6 +20,7 @@ phutil_require_module('phabricator', 'infrastructure/celerity/api');
phutil_require_module('phabricator', 'storage/queryfx');
phutil_require_module('phabricator', 'view/form/error');
phutil_require_module('phabricator', 'view/layout/panel');
+phutil_require_module('phabricator', 'view/utils');
phutil_require_module('phutil', 'markup');
phutil_require_module('phutil', 'utils');
diff --git a/src/applications/diffusion/controller/home/DiffusionHomeController.php b/src/applications/diffusion/controller/home/DiffusionHomeController.php
index 0caf98370b..c5b7dc1605 100644
--- a/src/applications/diffusion/controller/home/DiffusionHomeController.php
+++ b/src/applications/diffusion/controller/home/DiffusionHomeController.php
@@ -19,6 +19,8 @@
class DiffusionHomeController extends DiffusionController {
public function processRequest() {
+ $request = $this->getRequest();
+ $user = $request->getUser();
$shortcuts = id(new PhabricatorRepositoryShortcut())->loadAll();
if ($shortcuts) {
@@ -94,8 +96,8 @@ class DiffusionHomeController extends DiffusionController {
$date = '-';
$time = '-';
if ($commit) {
- $date = date('M j, Y', $commit->getEpoch());
- $time = date('g:i A', $commit->getEpoch());
+ $date = phabricator_date($commit->getEpoch(), $user);
+ $time = phabricator_time($commit->getEpoch(), $user);
}
$rows[] = array(
diff --git a/src/applications/diffusion/controller/home/__init__.php b/src/applications/diffusion/controller/home/__init__.php
index 56eca20496..af813ab9f4 100644
--- a/src/applications/diffusion/controller/home/__init__.php
+++ b/src/applications/diffusion/controller/home/__init__.php
@@ -15,6 +15,7 @@ phutil_require_module('phabricator', 'applications/repository/storage/shortcut')
phutil_require_module('phabricator', 'storage/queryfx');
phutil_require_module('phabricator', 'view/control/table');
phutil_require_module('phabricator', 'view/layout/panel');
+phutil_require_module('phabricator', 'view/utils');
phutil_require_module('phutil', 'markup');
phutil_require_module('phutil', 'utils');
diff --git a/src/applications/herald/controller/transcriptlist/HeraldTranscriptListController.php b/src/applications/herald/controller/transcriptlist/HeraldTranscriptListController.php
index db69b1612f..c465655c4d 100644
--- a/src/applications/herald/controller/transcriptlist/HeraldTranscriptListController.php
+++ b/src/applications/herald/controller/transcriptlist/HeraldTranscriptListController.php
@@ -21,6 +21,7 @@ class HeraldTranscriptListController extends HeraldController {
public function processRequest() {
$request = $this->getRequest();
+ $user = $request->getUser();
// Get one page of data together with the pager.
// Pull these objects manually since the serialized fields are gigantic.
@@ -98,8 +99,8 @@ class HeraldTranscriptListController extends HeraldController {
$rows = array();
foreach ($data as $xscript) {
$rows[] = array(
- date('F jS', $xscript['time']),
- date('g:i:s A', $xscript['time']),
+ phabricator_date($xscript['time'],$user),
+ phabricator_time($xscript['time'],$user),
$handles[$xscript['objectPHID']]->renderLink(),
$xscript['dryRun'] ? 'Yes' : '',
number_format((int)(1000 * $xscript['duration'])).' ms',
diff --git a/src/applications/herald/controller/transcriptlist/__init__.php b/src/applications/herald/controller/transcriptlist/__init__.php
index 13aacd82dc..def5438def 100644
--- a/src/applications/herald/controller/transcriptlist/__init__.php
+++ b/src/applications/herald/controller/transcriptlist/__init__.php
@@ -14,6 +14,7 @@ phutil_require_module('phabricator', 'storage/queryfx');
phutil_require_module('phabricator', 'view/control/pager');
phutil_require_module('phabricator', 'view/control/table');
phutil_require_module('phabricator', 'view/layout/panel');
+phutil_require_module('phabricator', 'view/utils');
phutil_require_module('phutil', 'markup');
phutil_require_module('phutil', 'utils');
diff --git a/src/applications/metamta/controller/receivedlist/PhabricatorMetaMTAReceivedListController.php b/src/applications/metamta/controller/receivedlist/PhabricatorMetaMTAReceivedListController.php
index 937054e6b3..5ff2093ba5 100644
--- a/src/applications/metamta/controller/receivedlist/PhabricatorMetaMTAReceivedListController.php
+++ b/src/applications/metamta/controller/receivedlist/PhabricatorMetaMTAReceivedListController.php
@@ -22,6 +22,7 @@ class PhabricatorMetaMTAReceivedListController
public function processRequest() {
$request = $this->getRequest();
+ $user = $request->getUser();
$pager = new AphrontPagerView();
$pager->setOffset($request->getInt('page'));
@@ -45,8 +46,8 @@ class PhabricatorMetaMTAReceivedListController
foreach ($mails as $mail) {
$rows[] = array(
$mail->getID(),
- date('M jS Y', $mail->getDateCreated()),
- date('g:i:s A', $mail->getDateCreated()),
+ phabricator_date($mail->getDateCreated(), $user),
+ phabricator_time($mail->getDateCreated(), $user),
$mail->getAuthorPHID()
? $handles[$mail->getAuthorPHID()]->renderLink()
: '-',
diff --git a/src/applications/metamta/controller/receivedlist/__init__.php b/src/applications/metamta/controller/receivedlist/__init__.php
index c111e1ef8f..36de24ff4a 100644
--- a/src/applications/metamta/controller/receivedlist/__init__.php
+++ b/src/applications/metamta/controller/receivedlist/__init__.php
@@ -12,6 +12,7 @@ phutil_require_module('phabricator', 'applications/phid/handle/data');
phutil_require_module('phabricator', 'view/control/pager');
phutil_require_module('phabricator', 'view/control/table');
phutil_require_module('phabricator', 'view/layout/panel');
+phutil_require_module('phabricator', 'view/utils');
phutil_require_module('phutil', 'markup');
phutil_require_module('phutil', 'utils');
diff --git a/src/applications/metamta/controller/view/PhabricatorMetaMTAViewController.php b/src/applications/metamta/controller/view/PhabricatorMetaMTAViewController.php
index 8d716d8331..627cf6ae36 100644
--- a/src/applications/metamta/controller/view/PhabricatorMetaMTAViewController.php
+++ b/src/applications/metamta/controller/view/PhabricatorMetaMTAViewController.php
@@ -27,6 +27,7 @@ class PhabricatorMetaMTAViewController extends PhabricatorMetaMTAController {
public function processRequest() {
$request = $this->getRequest();
+ $user = $request->getUser();
$mail = id(new PhabricatorMetaMTAMail())->load($this->id);
if (!$mail) {
@@ -46,7 +47,7 @@ class PhabricatorMetaMTAViewController extends PhabricatorMetaMTAController {
->appendChild(
id(new AphrontFormStaticControl())
->setLabel('Created')
- ->setValue(date('F jS, Y g:i:s A', $mail->getDateCreated())))
+ ->setValue(phabricator_datetime($mail->getDateCreated(), $user)))
->appendChild(
id(new AphrontFormStaticControl())
->setLabel('Status')
diff --git a/src/applications/metamta/controller/view/__init__.php b/src/applications/metamta/controller/view/__init__.php
index 17e87a642e..d08f948405 100644
--- a/src/applications/metamta/controller/view/__init__.php
+++ b/src/applications/metamta/controller/view/__init__.php
@@ -14,6 +14,7 @@ phutil_require_module('phabricator', 'view/form/control/static');
phutil_require_module('phabricator', 'view/form/control/submit');
phutil_require_module('phabricator', 'view/form/control/textarea');
phutil_require_module('phabricator', 'view/layout/panel');
+phutil_require_module('phabricator', 'view/utils');
phutil_require_module('phutil', 'utils');
diff --git a/src/applications/people/controller/list/PhabricatorPeopleListController.php b/src/applications/people/controller/list/PhabricatorPeopleListController.php
index e3e69e8150..e5f2d6b81e 100644
--- a/src/applications/people/controller/list/PhabricatorPeopleListController.php
+++ b/src/applications/people/controller/list/PhabricatorPeopleListController.php
@@ -53,8 +53,8 @@ class PhabricatorPeopleListController extends PhabricatorPeopleController {
}
$rows[] = array(
- date('M jS, Y', $user->getDateCreated()),
- date('g:i:s A', $user->getDateCreated()),
+ phabricator_date($user->getDateCreated(), $user),
+ phabricator_time($user->getDateCreated(), $user),
phutil_render_tag(
'a',
array(
diff --git a/src/applications/people/controller/list/__init__.php b/src/applications/people/controller/list/__init__.php
index 364bc2dda9..13eb127ea5 100644
--- a/src/applications/people/controller/list/__init__.php
+++ b/src/applications/people/controller/list/__init__.php
@@ -12,6 +12,7 @@ phutil_require_module('phabricator', 'storage/queryfx');
phutil_require_module('phabricator', 'view/control/pager');
phutil_require_module('phabricator', 'view/control/table');
phutil_require_module('phabricator', 'view/layout/panel');
+phutil_require_module('phabricator', 'view/utils');
phutil_require_module('phutil', 'markup');
phutil_require_module('phutil', 'utils');
diff --git a/src/applications/people/controller/logs/PhabricatorPeopleLogsController.php b/src/applications/people/controller/logs/PhabricatorPeopleLogsController.php
index 33810fc3b9..545a2ee27c 100644
--- a/src/applications/people/controller/logs/PhabricatorPeopleLogsController.php
+++ b/src/applications/people/controller/logs/PhabricatorPeopleLogsController.php
@@ -169,8 +169,8 @@ class PhabricatorPeopleLogsController extends PhabricatorPeopleController {
$rows = array();
foreach ($logs as $log) {
$rows[] = array(
- date('M jS, Y', $log->getDateCreated()),
- date('g:i:s A', $log->getDateCreated()),
+ phabricator_date($log->getDateCreated(),$user),
+ phabricator_time($log->getDateCreated(),$user),
$log->getAction(),
$log->getActorPHID()
? phutil_escape_html($handles[$log->getActorPHID()]->getName())
diff --git a/src/applications/people/controller/logs/__init__.php b/src/applications/people/controller/logs/__init__.php
index 824368dac3..3490be2539 100644
--- a/src/applications/people/controller/logs/__init__.php
+++ b/src/applications/people/controller/logs/__init__.php
@@ -19,6 +19,7 @@ phutil_require_module('phabricator', 'view/form/control/text');
phutil_require_module('phabricator', 'view/form/control/tokenizer');
phutil_require_module('phabricator', 'view/layout/listfilter');
phutil_require_module('phabricator', 'view/layout/panel');
+phutil_require_module('phabricator', 'view/utils');
phutil_require_module('phutil', 'markup');
phutil_require_module('phutil', 'utils');
diff --git a/src/applications/people/controller/settings/PhabricatorUserSettingsController.php b/src/applications/people/controller/settings/PhabricatorUserSettingsController.php
index 319066ffc2..d00ed87e66 100644
--- a/src/applications/people/controller/settings/PhabricatorUserSettingsController.php
+++ b/src/applications/people/controller/settings/PhabricatorUserSettingsController.php
@@ -137,6 +137,14 @@ class PhabricatorUserSettingsController extends PhabricatorPeopleController {
$e_realname = 'Required';
}
+ $new_timezone = $request->getStr('timezone');
+ if (in_array($new_timezone, DateTimeZone::listIdentifiers(), true)) {
+ $user->setTimezoneIdentifier($new_timezone);
+ } else {
+ $errors[] =
+ 'The selected timezone is not a valid timezone.';
+ }
+
if (!$errors) {
$user->save();
@@ -324,6 +332,9 @@ class PhabricatorUserSettingsController extends PhabricatorPeopleController {
))));
if ($editable) {
+ $timezone_ids = DateTimeZone::listIdentifiers();
+ $timezone_id_map = array_combine($timezone_ids, $timezone_ids);
+
$form
->appendChild(
id(new AphrontFormFileControl())
@@ -333,6 +344,15 @@ class PhabricatorUserSettingsController extends PhabricatorPeopleController {
->appendChild(
id(new AphrontFormMarkupControl())
->setValue('
'))
+ ->appendChild(
+ id(new AphrontFormSelectControl())
+ ->setLabel('Timezone')
+ ->setName('timezone')
+ ->setOptions($timezone_id_map)
+ ->setValue($user->getTimezoneIdentifier()))
+ ->appendChild(
+ id(new AphrontFormMarkupControl())
+ ->setValue('
'))
->appendChild(
id(new AphrontFormSubmitControl())
->setValue('Save'));
@@ -534,4 +554,4 @@ class PhabricatorUserSettingsController extends PhabricatorPeopleController {
return $notice.$panel->render();
}
-}
\ No newline at end of file
+}
diff --git a/src/applications/people/controller/settings/__init__.php b/src/applications/people/controller/settings/__init__.php
index 0cc7f9d320..1a952ff9c4 100644
--- a/src/applications/people/controller/settings/__init__.php
+++ b/src/applications/people/controller/settings/__init__.php
@@ -22,6 +22,7 @@ phutil_require_module('phabricator', 'view/dialog');
phutil_require_module('phabricator', 'view/form/base');
phutil_require_module('phabricator', 'view/form/control/file');
phutil_require_module('phabricator', 'view/form/control/markup');
+phutil_require_module('phabricator', 'view/form/control/select');
phutil_require_module('phabricator', 'view/form/control/static');
phutil_require_module('phabricator', 'view/form/control/submit');
phutil_require_module('phabricator', 'view/form/control/text');
diff --git a/src/applications/people/storage/user/PhabricatorUser.php b/src/applications/people/storage/user/PhabricatorUser.php
index ab88cdc35e..c5cbe0a121 100644
--- a/src/applications/people/storage/user/PhabricatorUser.php
+++ b/src/applications/people/storage/user/PhabricatorUser.php
@@ -27,6 +27,7 @@ class PhabricatorUser extends PhabricatorUserDAO {
protected $passwordSalt;
protected $passwordHash;
protected $profileImagePHID;
+ protected $timezoneIdentifier;
protected $consoleEnabled = 0;
protected $consoleVisible = 0;
diff --git a/src/view/utils/viewutils.php b/src/view/utils/viewutils.php
index e0f3ec922e..3c18d95154 100644
--- a/src/view/utils/viewutils.php
+++ b/src/view/utils/viewutils.php
@@ -16,6 +16,24 @@
* limitations under the License.
*/
+function phabricator_date($epoch, $user) {
+ $zone = new DateTimeZone($user->getTimezoneIdentifier());
+ $date = new DateTime('@'.$epoch, $zone);
+ return $date->format('M j Y');
+}
+
+function phabricator_time($epoch, $user) {
+ $zone = new DateTimeZone($user->getTimezoneIdentifier());
+ $date = new DateTime('@'.$epoch, $zone);
+ return $date->format('g:i A');
+}
+
+function phabricator_datetime($epoch, $user) {
+ $zone = new DateTimeZone($user->getTimezoneIdentifier());
+ $date = new DateTime('@'.$epoch, $zone);
+ return $date->format('M j Y, g:i A');
+}
+
function phabricator_format_relative_time($duration) {
return phabricator_format_units_generic(
$duration,