r44915 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r44914‎ | r44915 | r44916 >
Date:21:55, 22 December 2008
Author:brion
Status:ok (Comments)
Tags:
Comment:
* (bug 505) Time zones can now be specified by location in user preferences,
avoiding the need to manually update for DST. Patch by Brad Jorsch.
Modified paths:
  • /trunk/phase3/RELEASE-NOTES (modified) (history)
  • /trunk/phase3/includes/DefaultSettings.php (modified) (history)
  • /trunk/phase3/includes/specials/SpecialPreferences.php (modified) (history)
  • /trunk/phase3/languages/Language.php (modified) (history)
  • /trunk/phase3/languages/messages/MessagesEn.php (modified) (history)
  • /trunk/phase3/skins/common/prefs.js (modified) (history)

Diff [purge]

Index: trunk/phase3/skins/common/prefs.js
@@ -95,6 +95,7 @@
9696 if (tzb) {
9797 tzb.style.display = 'inline';
9898 }
 99+ updateTimezoneSelection(false);
99100 }
100101
101102 // in [-]HH:MM format...
@@ -113,7 +114,51 @@
114115
115116 function guessTimezone(box) {
116117 document.getElementsByName("wpHourDiff")[0].value = fetchTimezone();
 118+ updateTimezoneSelection(true);
117119 }
118120
 121+function updateTimezoneSelection(force_offset) {
 122+ var wpTimeZone = document.getElementsByName("wpTimeZone")[0];
 123+ var wpHourDiff = document.getElementsByName("wpHourDiff")[0];
 124+ var wpLocalTime = document.getElementById("wpLocalTime");
 125+ var wpServerTime = document.getElementsByName("wpServerTime")[0];
 126+ var minDiff = 0;
 127+
 128+ if (force_offset) wpTimeZone.selectedIndex = 1;
 129+ if (wpTimeZone.selectedIndex == 1) {
 130+ wpHourDiff.disabled = false;
 131+ var diffArr = wpHourDiff.value.split(':');
 132+ if (diffArr.length == 1) {
 133+ minDiff = parseInt(diffArr[0], 10) * 60;
 134+ } else {
 135+ minDiff = Math.abs(parseInt(diffArr[0], 10))*60 + parseInt(diffArr[1], 10);
 136+ if (parseInt(diffArr[0], 10) < 0) minDiff = -minDiff;
 137+ }
 138+ } else {
 139+ wpHourDiff.disabled = true;
 140+ var diffArr = wpTimeZone.options[wpTimeZone.selectedIndex].value.split('|');
 141+ minDiff = parseInt(diffArr[1], 10);
 142+ }
 143+ if (isNaN(minDiff)) minDiff = 0;
 144+ var localTime = parseInt(wpServerTime.value, 10) + minDiff;
 145+ while (localTime < 0) localTime += 1440;
 146+ while (localTime >= 1440) localTime -= 1440;
 147+
 148+ var hour = String(Math.floor(localTime/60));
 149+ if (hour.length<2) hour = '0'+hour;
 150+ var min = String(localTime%60);
 151+ if (min.length<2) min = '0'+min;
 152+ changeText(wpLocalTime, hour+':'+min);
 153+
 154+ if (wpTimeZone.selectedIndex != 1) {
 155+ hour = String(Math.abs(Math.floor(minDiff/60)));
 156+ if (hour.length<2) hour = '0'+hour;
 157+ if (minDiff < 0) hour = '-'+hour;
 158+ min = String(minDiff%60);
 159+ if (min.length<2) min = '0'+min;
 160+ wpHourDiff.value = hour+':'+min;
 161+ }
 162+}
 163+
119164 hookEvent("load", unhidetzbutton);
120165 hookEvent("load", tabbedprefs);
Index: trunk/phase3/includes/DefaultSettings.php
@@ -1444,7 +1444,7 @@
14451445 * to ensure that client-side caches don't keep obsolete copies of global
14461446 * styles.
14471447 */
1448 -$wgStyleVersion = '191';
 1448+$wgStyleVersion = '192';
14491449
14501450
14511451 # Server-side caching:
Index: trunk/phase3/includes/specials/SpecialPreferences.php
@@ -24,7 +24,7 @@
2525 var $mQuickbar, $mStubs;
2626 var $mRows, $mCols, $mSkin, $mMath, $mDate, $mUserEmail, $mEmailFlag, $mNick;
2727 var $mUserLanguage, $mUserVariant;
28 - var $mSearch, $mRecent, $mRecentDays, $mHourDiff, $mSearchLines, $mSearchChars, $mAction;
 28+ var $mSearch, $mRecent, $mRecentDays, $mTimeZone, $mHourDiff, $mSearchLines, $mSearchChars, $mAction;
2929 var $mReset, $mPosted, $mToggles, $mSearchNs, $mRealName, $mImageSize;
3030 var $mUnderline, $mWatchlistEdits;
3131
@@ -51,6 +51,7 @@
5252 $this->mSearch = $request->getVal( 'wpSearch' );
5353 $this->mRecent = $request->getVal( 'wpRecent' );
5454 $this->mRecentDays = $request->getVal( 'wpRecentDays' );
 55+ $this->mTimeZone = $request->getVal( 'wpTimeZone' );
5556 $this->mHourDiff = $request->getVal( 'wpHourDiff' );
5657 $this->mSearchLines = $request->getVal( 'wpSearchLines' );
5758 $this->mSearchChars = $request->getVal( 'wpSearchChars' );
@@ -170,34 +171,37 @@
171172
172173 /**
173174 * Used to validate the user inputed timezone before saving it as
174 - * 'timecorrection', will return '00:00' if fed bogus data.
175 - * Note: It's not a 100% correct implementation timezone-wise, it will
176 - * accept stuff like '14:30',
 175+ * 'timecorrection', will return 'System' if fed bogus data.
177176 * @access private
178 - * @param string $s the user input
 177+ * @param string $tz the user input Zoneinfo timezone
 178+ * @param string $s the user input offset string
179179 * @return string
180180 */
181 - function validateTimeZone( $s ) {
182 - if ( $s !== '' ) {
183 - if ( strpos( $s, ':' ) ) {
184 - # HH:MM
185 - $array = explode( ':' , $s );
186 - $hour = intval( $array[0] );
187 - $minute = intval( $array[1] );
188 - } else {
189 - $minute = intval( $s * 60 );
190 - $hour = intval( $minute / 60 );
191 - $minute = abs( $minute ) % 60;
192 - }
193 - # Max is +14:00 and min is -12:00, see:
194 - # http://en.wikipedia.org/wiki/Timezone
195 - $hour = min( $hour, 14 );
196 - $hour = max( $hour, -12 );
197 - $minute = min( $minute, 59 );
198 - $minute = max( $minute, 0 );
199 - $s = sprintf( "%02d:%02d", $hour, $minute );
 181+ function validateTimeZone( $tz, $s ) {
 182+ $data = explode( '|', $tz, 3 );
 183+ switch ( $data[0] ) {
 184+ case 'ZoneInfo':
 185+ case 'System':
 186+ return $tz;
 187+ case 'Offset':
 188+ default:
 189+ $data = explode( ':', $s, 2 );
 190+ $minDiff = 0;
 191+ if( count( $data ) == 2 ) {
 192+ $data[0] = intval( $data[0] );
 193+ $data[1] = intval( $data[1] );
 194+ $minDiff = abs( $data[0] ) * 60 + $data[1];
 195+ if ( $data[0] < 0 ) $minDiff = -$minDiff;
 196+ } else {
 197+ $minDiff = intval( $data[0] ) * 60;
 198+ }
 199+
 200+ # Max is +14:00 and min is -12:00, see:
 201+ # http://en.wikipedia.org/wiki/Timezone
 202+ $minDiff = min( $minDiff, 840 ); # 14:00
 203+ $minDiff = max( $minDiff, -720 ); # -12:00
 204+ return 'Offset|'.$minDiff;
200205 }
201 - return $s;
202206 }
203207
204208 /**
@@ -259,7 +263,7 @@
260264 $wgUser->setOption( 'rows', $this->validateInt( $this->mRows, 4, 1000 ) );
261265 $wgUser->setOption( 'cols', $this->validateInt( $this->mCols, 4, 1000 ) );
262266 $wgUser->setOption( 'stubthreshold', $this->validateIntOrNull( $this->mStubs ) );
263 - $wgUser->setOption( 'timecorrection', $this->validateTimeZone( $this->mHourDiff, -12, 14 ) );
 267+ $wgUser->setOption( 'timecorrection', $this->validateTimeZone( $this->mTimeZone, $this->mHourDiff ) );
264268 $wgUser->setOption( 'imagesize', $this->mImageSize );
265269 $wgUser->setOption( 'thumbsize', $this->mThumbSize );
266270 $wgUser->setOption( 'underline', $this->validateInt($this->mUnderline, 0, 2) );
@@ -344,7 +348,7 @@
345349 * @access private
346350 */
347351 function resetPrefs() {
348 - global $wgUser, $wgLang, $wgContLang, $wgContLanguageCode, $wgAllowRealName;
 352+ global $wgUser, $wgLang, $wgContLang, $wgContLanguageCode, $wgAllowRealName, $wgLocalTZoffset;
349353
350354 $this->mUserEmail = $wgUser->getEmail();
351355 $this->mUserEmailAuthenticationtimestamp = $wgUser->getEmailAuthenticationtimestamp();
@@ -364,7 +368,47 @@
365369 $this->mRows = $wgUser->getOption( 'rows' );
366370 $this->mCols = $wgUser->getOption( 'cols' );
367371 $this->mStubs = $wgUser->getOption( 'stubthreshold' );
368 - $this->mHourDiff = $wgUser->getOption( 'timecorrection' );
 372+
 373+ $tz = $wgUser->getOption( 'timecorrection' );
 374+ $data = explode( '|', $tz, 3 );
 375+ $minDiff = null;
 376+ switch ( $data[0] ) {
 377+ case 'ZoneInfo':
 378+ $this->mTimeZone = $tz;
 379+ # Check if the specified TZ exists, and change to 'Offset' if
 380+ # not.
 381+ if ( !function_exists('timezone_open') || @timezone_open( $data[2] ) === false ) {
 382+ $this->mTimeZone = 'Offset';
 383+ $minDiff = intval( $data[1] );
 384+ }
 385+ break;
 386+ case '':
 387+ case 'System':
 388+ $this->mTimeZone = 'System|'.$wgLocalTZoffset;
 389+ break;
 390+ case 'Offset':
 391+ $this->mTimeZone = 'Offset';
 392+ $minDiff = intval( $data[1] );
 393+ break;
 394+ default:
 395+ $this->mTimeZone = 'Offset';
 396+ $data = explode( ':', $tz, 2 );
 397+ if( count( $data ) == 2 ) {
 398+ $data[0] = intval( $data[0] );
 399+ $data[1] = intval( $data[1] );
 400+ $minDiff = abs( $data[0] ) * 60 + $data[1];
 401+ if ( $data[0] < 0 ) $minDiff = -$minDiff;
 402+ } else {
 403+ $minDiff = intval( $data[0] ) * 60;
 404+ }
 405+ break;
 406+ }
 407+ if ( is_null( $minDiff ) ) {
 408+ $this->mHourDiff = '';
 409+ } else {
 410+ $this->mHourDiff = sprintf( '%+03d:%02d', floor($minDiff/60), abs($minDiff)%60 );
 411+ }
 412+
369413 $this->mSearch = $wgUser->getOption( 'searchlimit' );
370414 $this->mSearchLines = $wgUser->getOption( 'contextlines' );
371415 $this->mSearchChars = $wgUser->getOption( 'contextchars' );
@@ -490,7 +534,7 @@
491535 global $wgRCShowWatchingUsers, $wgEnotifRevealEditorAddress;
492536 global $wgEnableEmail, $wgEnableUserEmail, $wgEmailAuthentication;
493537 global $wgContLanguageCode, $wgDefaultSkin, $wgCookieExpiration;
494 - global $wgEmailConfirmToEdit, $wgEnableMWSuggest;
 538+ global $wgEmailConfirmToEdit, $wgEnableMWSuggest, $wgLocalTZoffset;
495539
496540 $wgOut->setPageTitle( wfMsg( 'preferences' ) );
497541 $wgOut->setArticleRelated( false );
@@ -908,18 +952,61 @@
909953 $wgOut->addHTML( Xml::closeElement( 'fieldset' ) . "\n" );
910954 }
911955
912 - $nowlocal = $wgLang->time( $now = wfTimestampNow(), true );
913 - $nowserver = $wgLang->time( $now, false );
 956+ $nowlocal = Xml::openElement( 'span', array( 'id' => 'wpLocalTime' ) ) .
 957+ $wgLang->time( $now = wfTimestampNow(), true ) .
 958+ Xml::closeElement( 'span' );
 959+ $nowserver = $wgLang->time( $now, false ) .
 960+ Xml::hidden( 'wpServerTime', substr( $now, 8, 2 ) * 60 + substr( $now, 10, 2 ) );
914961
915962 $wgOut->addHTML(
916963 Xml::openElement( 'fieldset' ) .
917964 Xml::element( 'legend', null, wfMsg( 'timezonelegend' ) ) .
918965 Xml::openElement( 'table' ) .
919966 $this->addRow( wfMsg( 'servertime' ), $nowserver ) .
920 - $this->addRow( wfMsg( 'localtime' ), $nowlocal ) .
 967+ $this->addRow( wfMsg( 'localtime' ), $nowlocal )
 968+ );
 969+ $opt = Xml::openElement( 'select', array(
 970+ 'name' => 'wpTimeZone',
 971+ 'id' => 'wpTimeZone',
 972+ 'onchange' => 'javascript:updateTimezoneSelection(false)' ) );
 973+ $opt .= Xml::option( wfMsg( 'timezoneuseserverdefault' ), "System|$wgLocalTZoffset", $this->mTimeZone === "System|$wgLocalTZoffset" );
 974+ $opt .= Xml::option( wfMsg( 'timezoneuseoffset' ), 'Offset', $this->mTimeZone === 'Offset' );
 975+ if ( function_exists( 'timezone_identifiers_list' ) ) {
 976+ $optgroup = '';
 977+ $tzs = timezone_identifiers_list();
 978+ sort( $tzs );
 979+ $selZone = explode( '|', $this->mTimeZone, 3);
 980+ $selZone = ( $selZone[0] == 'ZoneInfo' ) ? $selZone[2] : null;
 981+ $now = date_create( 'now' );
 982+ foreach ( $tzs as $tz ) {
 983+ $z = explode( '/', $tz, 2 );
 984+ # timezone_identifiers_list() returns a number of
 985+ # backwards-compatibility entries. This filters them out of the
 986+ # list presented to the user.
 987+ if ( count( $z ) != 2 || !in_array( $z[0], array( 'Africa', 'America', 'Antarctica', 'Arctic', 'Asia', 'Atlantic', 'Australia', 'Europe', 'Indian', 'Pacific' ) ) ) continue;
 988+ if ( $optgroup != $z[0] ) {
 989+ if ( $optgroup !== '' ) $opt .= Xml::closeElement( 'optgroup' );
 990+ $optgroup = $z[0];
 991+ $opt .= Xml::openElement( 'optgroup', array( 'label' => $z[0] ) );
 992+ }
 993+ $minDiff = floor( timezone_offset_get( timezone_open( $tz ), $now ) / 60 );
 994+ $opt .= Xml::option( str_replace( '_', ' ', $tz ), "ZoneInfo|$minDiff|$tz", $selZone === $tz, array( 'label' => $z[1] ) );
 995+ }
 996+ if ( $optgroup !== '' ) $opt .= Xml::closeElement( 'optgroup' );
 997+ }
 998+ $opt .= Xml::closeElement( 'select' );
 999+ $wgOut->addHTML(
9211000 $this->addRow(
 1001+ Xml::label( wfMsg( 'timezoneselect' ), 'wpTimeZone' ),
 1002+ $opt )
 1003+ );
 1004+ $wgOut->addHTML(
 1005+ $this->addRow(
9221006 Xml::label( wfMsg( 'timezoneoffset' ), 'wpHourDiff' ),
923 - Xml::input( 'wpHourDiff', 6, $this->mHourDiff, array( 'id' => 'wpHourDiff' ) ) ) .
 1007+ Xml::input( 'wpHourDiff', 6, $this->mHourDiff, array(
 1008+ 'id' => 'wpHourDiff',
 1009+ 'onfocus' => 'javascript:updateTimezoneSelection(true)',
 1010+ 'onblur' => 'javascript:updateTimezoneSelection(false)' ) ) ) .
9241011 "<tr>
9251012 <td></td>
9261013 <td class='mw-submit'>" .
Index: trunk/phase3/languages/messages/MessagesEn.php
@@ -1566,6 +1566,9 @@
15671567 'timezonelegend' => 'Time zone',
15681568 'timezonetext' => '¹The number of hours your local time differs from server time (UTC).',
15691569 'localtime' => 'Local time',
 1570+'timezoneselect' => 'Timezone',
 1571+'timezoneuseserverdefault' => 'Use server default',
 1572+'timezoneuseoffset' => 'Other (specify offset)',
15701573 'timezoneoffset' => 'Offset¹',
15711574 'servertime' => 'Server time',
15721575 'guesstimezone' => 'Fill in from browser',
Index: trunk/phase3/languages/Language.php
@@ -479,39 +479,50 @@
480480 function userAdjust( $ts, $tz = false ) {
481481 global $wgUser, $wgLocalTZoffset;
482482
483 - if (!$tz) {
 483+ if ( $tz === false ) {
484484 $tz = $wgUser->getOption( 'timecorrection' );
485485 }
486486
487 - # minutes and hours differences:
 487+ $data = explode( '|', $tz, 3 );
 488+
 489+ if ( $data[0] == 'ZoneInfo' ) {
 490+ if ( function_exists( 'timezone_open' ) && @timezone_open( $data[2] ) !== false ) {
 491+ $date = date_create( $ts, timezone_open( 'UTC' ) );
 492+ date_timezone_set( $date, timezone_open( $data[2] ) );
 493+ $date = date_format( $date, 'YmdHis' );
 494+ return $date;
 495+ }
 496+ # Unrecognized timezone, default to 'Offset' with the stored offset.
 497+ $data[0] = 'Offset';
 498+ }
 499+
488500 $minDiff = 0;
489 - $hrDiff = 0;
490 -
491 - if ( $tz === '' ) {
 501+ if ( $data[0] == 'System' || $tz == '' ) {
492502 # Global offset in minutes.
493 - if( isset($wgLocalTZoffset) ) {
494 - if( $wgLocalTZoffset >= 0 ) {
495 - $hrDiff = floor($wgLocalTZoffset / 60);
496 - } else {
497 - $hrDiff = ceil($wgLocalTZoffset / 60);
498 - }
499 - $minDiff = $wgLocalTZoffset % 60;
 503+ if( isset($wgLocalTZoffset) ) $minDiff = $wgLocalTZoffset;
 504+ } else if ( $data[0] == 'Offset' ) {
 505+ $minDiff = intval( $data[1] );
 506+ } else {
 507+ $data = explode( ':', $tz );
 508+ if( count( $data ) == 2 ) {
 509+ $data[0] = intval( $data[0] );
 510+ $data[1] = intval( $data[1] );
 511+ $minDiff = abs( $data[0] ) * 60 + $data[1];
 512+ if ( $data[0] < 0 ) $minDiff = -$minDiff;
 513+ } else {
 514+ $minDiff = intval( $data[0] ) * 60;
500515 }
501 - } elseif ( strpos( $tz, ':' ) !== false ) {
502 - $tzArray = explode( ':', $tz );
503 - $hrDiff = intval($tzArray[0]);
504 - $minDiff = intval($hrDiff < 0 ? -$tzArray[1] : $tzArray[1]);
505 - } else {
506 - $hrDiff = intval( $tz );
507516 }
508517
509518 # No difference ? Return time unchanged
510 - if ( 0 == $hrDiff && 0 == $minDiff ) { return $ts; }
 519+ if ( 0 == $minDiff ) return $ts;
511520
512521 wfSuppressWarnings(); // E_STRICT system time bitching
513 - # Generate an adjusted date
 522+ # Generate an adjusted date; take advantage of the fact that mktime
 523+ # will normalize out-of-range values so we don't have to split $minDiff
 524+ # into hours and minutes.
514525 $t = mktime( (
515 - (int)substr( $ts, 8, 2) ) + $hrDiff, # Hours
 526+ (int)substr( $ts, 8, 2) ), # Hours
516527 (int)substr( $ts, 10, 2 ) + $minDiff, # Minutes
517528 (int)substr( $ts, 12, 2 ), # Seconds
518529 (int)substr( $ts, 4, 2 ), # Month
Index: trunk/phase3/RELEASE-NOTES
@@ -239,7 +239,10 @@
240240 * Added 'UserCryptPassword' and 'UserComparePasswords' hooks to allow extensions to implement
241241 their own password hashing methods.
242242 * (bug 16760) Add CSS-class to action links of Special:Log
 243+* (bug 505) Time zones can now be specified by location in user preferences,
 244+ avoiding the need to manually update for DST. Patch by Brad Jorsch.
243245
 246+
244247 === Bug fixes in 1.14 ===
245248
246249 * (bug 14907) DatabasePostgres::fieldType now defined.

Follow-up revisions

RevisionCommit summaryAuthorDate
r44916Follow up r44915: Add new messages to messages.incraymond22:10, 22 December 2008

Comments

#Comment by Aaron Schulz (talk | contribs)   23:17, 22 December 2008

Seems to work. Might have some duplication.

Also, the timezone_identifiers_list() filter stuff could perhaps be split off a bit.

#Comment by Kwj2772 (talk | contribs)   06:19, 25 December 2008

Timezone name can't be localized now. It is a problem.

#Comment by Nikerabbit (talk | contribs)   13:21, 25 December 2008

That is also a thing that we could pull out of cldr data instead of duplicating the effort.

Status & tagging log