3 final class PhabricatorSettingsTimezoneController
4 extends PhabricatorController
{
6 public function handleRequest(AphrontRequest
$request) {
7 $viewer = $this->getViewer();
9 $client_offset = $request->getURIData('offset');
10 $client_offset = (int)$client_offset;
12 $timezones = DateTimeZone
::listIdentifiers();
13 $now = new DateTime('@'.PhabricatorTime
::getNow());
16 'ignore' => pht('Ignore Conflict'),
19 foreach ($timezones as $identifier) {
20 $zone = new DateTimeZone($identifier);
21 $offset = -($zone->getOffset($now) / 60);
22 if ($offset == $client_offset) {
23 $name = PhabricatorTime
::getTimezoneDisplayName($identifier);
24 $options[$identifier] = $name;
29 'You can change your date and time preferences in Settings.');
31 $did_calibrate = false;
32 if ($request->isFormPost()) {
33 $timezone = $request->getStr('timezone');
35 $pref_ignore = PhabricatorTimezoneIgnoreOffsetSetting
::SETTINGKEY
;
36 $pref_timezone = PhabricatorTimezoneSetting
::SETTINGKEY
;
38 if ($timezone == 'ignore') {
41 $pref_ignore => $client_offset,
44 return $this->newDialog()
45 ->setTitle(pht('Conflict Ignored'))
48 'The conflict between your browser and profile timezone '.
49 'settings will be ignored.'))
50 ->appendParagraph($settings_help)
51 ->addCancelButton('/', pht('Done'));
54 if (isset($options[$timezone])) {
58 $pref_timezone => $timezone,
61 $did_calibrate = true;
65 $server_offset = $viewer->getTimeZoneOffset();
67 if (($client_offset == $server_offset) ||
$did_calibrate) {
68 return $this->newDialog()
69 ->setTitle(pht('Timezone Calibrated'))
72 'Your browser timezone and profile timezone are now '.
74 $this->formatOffset($client_offset)))
75 ->appendParagraph($settings_help)
76 ->addCancelButton('/', pht('Done'));
79 // If we have a guess at the timezone from the client, select it as the
81 $guess = $request->getStr('guess');
82 if (empty($options[$guess])) {
86 $current_zone = $viewer->getTimezoneIdentifier();
87 $current_zone = phutil_tag('strong', array(), $current_zone);
89 $form = id(new AphrontFormView())
91 id(new AphrontFormMarkupControl())
92 ->setLabel(pht('Current Setting'))
93 ->setValue($current_zone))
95 id(new AphrontFormSelectControl())
97 ->setLabel(pht('New Setting'))
98 ->setOptions($options)
101 return $this->newDialog()
102 ->setTitle(pht('Adjust Timezone'))
103 ->setWidth(AphrontDialogView
::WIDTH_FORM
)
106 'Your browser timezone (%s) differs from your profile timezone '.
107 '(%s). You can ignore this conflict or adjust your profile setting '.
108 'to match your client.',
109 $this->formatOffset($client_offset),
110 $this->formatOffset($server_offset)))
112 ->addCancelButton(pht('Cancel'))
113 ->addSubmitButton(pht('Change Timezone'));
116 private function formatOffset($offset) {
117 // This controller works with client-side (Javascript) offsets, which have
118 // the opposite sign we might expect -- for example "UTC-3" is a positive
119 // offset. Invert the sign before rendering the offset.
120 $offset = -1 * $offset;
122 $hours = $offset / 60;
123 // Non-integer number of hours off UTC?
125 $minutes = abs($offset %
60);
126 return pht('UTC%+d:%02d', $hours, $minutes);
128 return pht('UTC%+d', $hours);
132 private function writeSettings(array $map) {
133 $request = $this->getRequest();
134 $viewer = $this->getViewer();
136 $preferences = PhabricatorUserPreferences
::loadUserPreferences($viewer);
138 $editor = id(new PhabricatorUserPreferencesEditor())
140 ->setContentSourceFromRequest($request)
141 ->setContinueOnNoEffect(true)
142 ->setContinueOnMissingFields(true);
145 foreach ($map as $key => $value) {
146 $xactions[] = $preferences->newTransaction($key, $value);
149 $editor->applyTransactions($preferences, $xactions);