MediaWiki master
HTMLTimezoneField.php
Go to the documentation of this file.
1<?php
2
4
5use DateTime;
6use DateTimeZone;
7use InvalidArgumentException;
14
21 private const FIELD_CLASS = 'mw-htmlform-timezone-field';
22
24 private $msgFormatter;
25
31 public function __construct( $params ) {
32 if ( isset( $params['options'] ) ) {
33 throw new InvalidArgumentException( "Options should not be provided to " . __CLASS__ );
34 }
35 $params['placeholder-message'] ??= 'timezone-useoffset-placeholder';
36 $params['options'] = [];
37 parent::__construct( $params );
38 $langCode = $this->mParent->getLanguage()->getCode();
39 $this->msgFormatter = MediaWikiServices::getInstance()->getMessageFormatterFactory()
40 ->getTextFormatter( $langCode );
41 $this->mOptions = $this->getTimezoneOptions();
42 }
43
47 private function getTimezoneOptions(): array {
48 $opt = [];
49
50 $localTZoffset = MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::LocalTZoffset );
51 $timeZoneList = $this->getTimeZoneList();
52
53 $timestamp = MWTimestamp::getLocalInstance();
54 // Check that the LocalTZoffset is the same as the local time zone offset
55 if ( $localTZoffset === (int)$timestamp->format( 'Z' ) / 60 ) {
56 $timezoneName = $timestamp->getTimezone()->getName();
57 // Localize timezone
58 if ( isset( $timeZoneList[$timezoneName] ) ) {
59 $timezoneName = $timeZoneList[$timezoneName]['name'];
60 }
61 $server_tz_msg = $this->msgFormatter->format(
62 MessageValue::new( 'timezoneuseserverdefault', [ $timezoneName ] )
63 );
64 } else {
65 $tzstring = UserTimeCorrection::formatTimezoneOffset( $localTZoffset );
66 $server_tz_msg = $this->msgFormatter->format(
67 MessageValue::new( 'timezoneuseserverdefault', [ $tzstring ] )
68 );
69 }
70 $opt[$server_tz_msg] = "System|$localTZoffset";
71 $opt[$this->msgFormatter->format( MessageValue::new( 'timezoneuseoffset' ) )] = 'other';
72 $opt[$this->msgFormatter->format( MessageValue::new( 'guesstimezone' ) )] = 'guess';
73
74 foreach ( $timeZoneList as $timeZoneInfo ) {
75 $region = $timeZoneInfo['region'];
76 if ( !isset( $opt[$region] ) ) {
77 $opt[$region] = [];
78 }
79 $opt[$region][$timeZoneInfo['name']] = $timeZoneInfo['timecorrection'];
80 }
81 return $opt;
82 }
83
90 private function getTimeZoneList(): array {
91 $identifiers = DateTimeZone::listIdentifiers();
92 '@phan-var array|false $identifiers'; // See phan issue #3162
93 if ( $identifiers === false ) {
94 return [];
95 }
96 sort( $identifiers );
97
98 $tzRegions = [
99 'Africa' => $this->msgFormatter->format( MessageValue::new( 'timezoneregion-africa' ) ),
100 'America' => $this->msgFormatter->format( MessageValue::new( 'timezoneregion-america' ) ),
101 'Antarctica' => $this->msgFormatter->format( MessageValue::new( 'timezoneregion-antarctica' ) ),
102 'Arctic' => $this->msgFormatter->format( MessageValue::new( 'timezoneregion-arctic' ) ),
103 'Asia' => $this->msgFormatter->format( MessageValue::new( 'timezoneregion-asia' ) ),
104 'Atlantic' => $this->msgFormatter->format( MessageValue::new( 'timezoneregion-atlantic' ) ),
105 'Australia' => $this->msgFormatter->format( MessageValue::new( 'timezoneregion-australia' ) ),
106 'Europe' => $this->msgFormatter->format( MessageValue::new( 'timezoneregion-europe' ) ),
107 'Indian' => $this->msgFormatter->format( MessageValue::new( 'timezoneregion-indian' ) ),
108 'Pacific' => $this->msgFormatter->format( MessageValue::new( 'timezoneregion-pacific' ) ),
109 ];
110 asort( $tzRegions );
111
112 $timeZoneList = [];
113
114 $now = new DateTime();
115
116 foreach ( $identifiers as $identifier ) {
117 $parts = explode( '/', $identifier, 2 );
118
119 // DateTimeZone::listIdentifiers() returns a number of
120 // backwards-compatibility entries. This filters them out of the
121 // list presented to the user.
122 if ( count( $parts ) !== 2 || !array_key_exists( $parts[0], $tzRegions ) ) {
123 continue;
124 }
125
126 // Localize region
127 $parts[0] = $tzRegions[$parts[0]];
128
129 $dateTimeZone = new DateTimeZone( $identifier );
130 $minDiff = floor( $dateTimeZone->getOffset( $now ) / 60 );
131
132 $display = str_replace( '_', ' ', $parts[0] . '/' . $parts[1] );
133 $value = "ZoneInfo|$minDiff|$identifier";
134
135 $timeZoneList[$identifier] = [
136 'name' => $display,
137 'timecorrection' => $value,
138 'region' => $parts[0],
139 ];
140 }
141
142 return $timeZoneList;
143 }
144
148 public function validate( $value, $alldata ) {
149 $p = parent::validate( $value, $alldata );
150 if ( $p !== true ) {
151 return $p;
152 }
153
154 if ( !( new UserTimeCorrection( $value ) )->isValid() ) {
155 return $this->mParent->msg( 'timezone-invalid' )->escaped();
156 }
157
158 return true;
159 }
160
164 protected function getFieldClasses(): array {
165 $classes = parent::getFieldClasses();
166 $classes[] = self::FIELD_CLASS;
167 return $classes;
168 }
169}
170
172class_alias( HTMLTimezoneField::class, 'HTMLTimezoneField' );
Select dropdown field, with an additional "other" textbox.
Dropdown widget that allows the user to select a timezone, either by choosing a geographic zone,...
validate( $value, $alldata)
Override this function to add specific validation checks on the field input.Don't forget to call pare...
getFieldClasses()
Returns a list of classes that should be applied to the widget itself.Unfortunately,...
A class containing constants representing the names of configuration variables.
const LocalTZoffset
Name constant for the LocalTZoffset setting, for use with Config::get()
Service locator for MediaWiki core services.
static getInstance()
Returns the global default instance of the top level service locator.
Utility class to parse the TimeCorrection string value.
static formatTimezoneOffset(int $offset)
Converts a timezone offset in minutes (e.g., "120") to an hh:mm string like "+02:00".
Library for creating and parsing MW-style timestamps.
Value object representing a message for i18n.