* internationalisation, a reduced set of format characters, and a better
* escaping format.
*
- * Supported format characters are dDjlNwzWFmMntLoYyaAgGhHiscrU. See the
- * PHP manual for definitions. There are a number of extensions, which
+ * Supported format characters are dDjlNwzWFmMntLoYyaAgGhHiscrUeIOPTZ. See
+ * the PHP manual for definitions. There are a number of extensions, which
* start with "x":
*
* xn Do not translate digits of the next numeric format character
* Backslash escaping is also supported.
*
* Input timestamp is assumed to be pre-normalized to the desired local
- * time zone, if any.
+ * time zone, if any. Note that the format characters crUeIOPTZ will assume
+ * $ts is UTC if $zone is not given.
*
* @param $format String
* @param $ts String: 14-character timestamp
* YYYYMMDDHHMMSS
* 01234567890123
+ * @param $zone DateTimeZone: Timezone of $ts
* @todo handling of "o" format character for Iranian, Hebrew, Hijri & Thai?
*
* @return string
*/
- function sprintfDate( $format, $ts ) {
+ function sprintfDate( $format, $ts, DateTimeZone $zone = null ) {
$s = '';
$raw = false;
$roman = false;
$hebrewNum = false;
- $unix = false;
+ $dateTimeObj = false;
$rawToggle = false;
$iranian = false;
$hebrew = false;
$num = substr( $ts, 6, 2 );
break;
case 'D':
- if ( !$unix ) $unix = wfTimestamp( TS_UNIX, $ts );
- $s .= $this->getWeekdayAbbreviation( gmdate( 'w', $unix ) + 1 );
+ if ( !$dateTimeObj ) {
+ $dateTimeObj = DateTime::createFromFormat(
+ 'YmdHis', $ts, $zone ?: new DateTimeZone( 'UTC' )
+ );
+ }
+ $s .= $this->getWeekdayAbbreviation( $dateTimeObj->format( 'w' ) + 1 );
break;
case 'j':
$num = intval( substr( $ts, 6, 2 ) );
$num = $hebrew[2];
break;
case 'l':
- if ( !$unix ) {
- $unix = wfTimestamp( TS_UNIX, $ts );
- }
- $s .= $this->getWeekdayName( gmdate( 'w', $unix ) + 1 );
- break;
- case 'N':
- if ( !$unix ) {
- $unix = wfTimestamp( TS_UNIX, $ts );
- }
- $w = gmdate( 'w', $unix );
- $num = $w ? $w : 7;
- break;
- case 'w':
- if ( !$unix ) {
- $unix = wfTimestamp( TS_UNIX, $ts );
- }
- $num = gmdate( 'w', $unix );
- break;
- case 'z':
- if ( !$unix ) {
- $unix = wfTimestamp( TS_UNIX, $ts );
- }
- $num = gmdate( 'z', $unix );
- break;
- case 'W':
- if ( !$unix ) {
- $unix = wfTimestamp( TS_UNIX, $ts );
+ if ( !$dateTimeObj ) {
+ $dateTimeObj = DateTime::createFromFormat(
+ 'YmdHis', $ts, $zone ?: new DateTimeZone( 'UTC' )
+ );
}
- $num = gmdate( 'W', $unix );
+ $s .= $this->getWeekdayName( $dateTimeObj->format( 'w' ) + 1 );
break;
case 'F':
$s .= $this->getMonthName( substr( $ts, 4, 2 ) );
}
$num = $hebrew[1];
break;
- case 't':
- if ( !$unix ) {
- $unix = wfTimestamp( TS_UNIX, $ts );
- }
- $num = gmdate( 't', $unix );
- break;
case 'xjt':
if ( !$hebrew ) {
$hebrew = self::tsToHebrew( $ts );
}
$num = $hebrew[3];
break;
- case 'L':
- if ( !$unix ) {
- $unix = wfTimestamp( TS_UNIX, $ts );
- }
- $num = gmdate( 'L', $unix );
- break;
- case 'o':
- if ( !$unix ) {
- $unix = wfTimestamp( TS_UNIX, $ts );
- }
- $num = gmdate( 'o', $unix );
- break;
case 'Y':
$num = substr( $ts, 0, 4 );
break;
$num = substr( $ts, 12, 2 );
break;
case 'c':
- if ( !$unix ) {
- $unix = wfTimestamp( TS_UNIX, $ts );
- }
- $s .= gmdate( 'c', $unix );
- break;
case 'r':
- if ( !$unix ) {
- $unix = wfTimestamp( TS_UNIX, $ts );
+ case 'e':
+ case 'O':
+ case 'P':
+ case 'T':
+ // Pass through string from $dateTimeObj->format()
+ if ( !$dateTimeObj ) {
+ $dateTimeObj = DateTime::createFromFormat(
+ 'YmdHis', $ts, $zone ?: new DateTimeZone( 'UTC' )
+ );
}
- $s .= gmdate( 'r', $unix );
+ $s .= $dateTimeObj->format( $code );
break;
+ case 'w':
+ case 'N':
+ case 'z':
+ case 'W':
+ case 't':
+ case 'L':
+ case 'o':
case 'U':
- if ( !$unix ) {
- $unix = wfTimestamp( TS_UNIX, $ts );
+ case 'I':
+ case 'Z':
+ // Pass through number from $dateTimeObj->format()
+ if ( !$dateTimeObj ) {
+ $dateTimeObj = DateTime::createFromFormat(
+ 'YmdHis', $ts, $zone ?: new DateTimeZone( 'UTC' )
+ );
}
- $num = $unix;
+ $num = $dateTimeObj->format( $code );
break;
case '\\':
# Backslash escaping
}
/**
- * bug 33454. sprintfDate should always use UTC.
+ * sprintfDate should always use UTC when no zone is given.
* @dataProvider provideSprintfDateSamples
*/
- function testSprintfDateTZ( $format, $ts, $expected, $msg ) {
+ function testSprintfDateNoZone( $format, $ts, $expected, $ignore, $msg ) {
$oldTZ = date_default_timezone_get();
$res = date_default_timezone_set( 'Asia/Seoul' );
if ( !$res ) {
date_default_timezone_set( $oldTZ );
}
+ /**
+ * sprintfDate should use passed timezone
+ * @dataProvider provideSprintfDateSamples
+ */
+ function testSprintfDateTZ( $format, $ts, $ignore, $expected, $msg ) {
+ $tz = new DateTimeZone( 'Asia/Seoul' );
+ if ( !$tz ) {
+ $this->markTestSkipped( "Error getting Timezone" );
+ }
+
+ $this->assertEquals(
+ $expected,
+ $this->getLang()->sprintfDate( $format, $ts, $tz ),
+ "sprintfDate('$format', '$ts', 'Asia/Seoul'): $msg"
+ );
+ }
+
public static function provideSprintfDateSamples() {
return array(
array(
'xiY',
'20111212000000',
'1390', // note because we're testing English locale we get Latin-standard digits
+ '1390',
'Iranian calendar full year'
),
array(
'xiy',
'20111212000000',
'90',
+ '90',
'Iranian calendar short year'
),
array(
'o',
'20120101235000',
'2011',
+ '2011',
'ISO 8601 (week) year'
),
array(
'W',
'20120101235000',
'52',
+ '52',
'Week number'
),
array(
'W',
'20120102235000',
'1',
+ '1',
'Week number'
),
array(
'o-\\WW-N',
'20091231235000',
'2009-W53-4',
+ '2009-W53-4',
'leap week'
),
// What follows is mostly copied from http://www.mediawiki.org/wiki/Help:Extension:ParserFunctions#.23time
'Y',
'20120102090705',
'2012',
+ '2012',
'Full year'
),
array(
'y',
'20120102090705',
'12',
+ '12',
'2 digit year'
),
array(
'L',
'20120102090705',
'1',
+ '1',
'Leap year'
),
array(
'n',
'20120102090705',
'1',
+ '1',
'Month index, not zero pad'
),
array(
'N',
'20120102090705',
'01',
+ '01',
'Month index. Zero pad'
),
array(
'M',
'20120102090705',
'Jan',
+ 'Jan',
'Month abbrev'
),
array(
'F',
'20120102090705',
'January',
+ 'January',
'Full month'
),
array(
'xg',
'20120102090705',
'January',
+ 'January',
'Genitive month name (same in EN)'
),
array(
'j',
'20120102090705',
'2',
+ '2',
'Day of month (not zero pad)'
),
array(
'd',
'20120102090705',
'02',
+ '02',
'Day of month (zero-pad)'
),
array(
'z',
'20120102090705',
'1',
+ '1',
'Day of year (zero-indexed)'
),
array(
'D',
'20120102090705',
'Mon',
+ 'Mon',
'Day of week (abbrev)'
),
array(
'l',
'20120102090705',
'Monday',
+ 'Monday',
'Full day of week'
),
array(
'N',
'20120101090705',
'7',
+ '7',
'Day of week (Mon=1, Sun=7)'
),
array(
'w',
'20120101090705',
'0',
+ '0',
'Day of week (Sun=0, Sat=6)'
),
array(
'N',
'20120102090705',
'1',
+ '1',
'Day of week'
),
array(
'a',
'20120102090705',
'am',
+ 'am',
'am vs pm'
),
array(
'A',
'20120102120000',
'PM',
+ 'PM',
'AM vs PM'
),
array(
'a',
'20120102000000',
'am',
+ 'am',
'AM vs PM'
),
array(
'g',
'20120102090705',
'9',
+ '9',
'12 hour, not Zero'
),
array(
'h',
'20120102090705',
'09',
+ '09',
'12 hour, zero padded'
),
array(
'G',
'20120102090705',
'9',
+ '9',
'24 hour, not zero'
),
array(
'H',
'20120102090705',
'09',
+ '09',
'24 hour, zero'
),
array(
'H',
'20120102110705',
'11',
+ '11',
'24 hour, zero'
),
array(
'i',
'20120102090705',
'07',
+ '07',
'Minutes'
),
array(
's',
'20120102090705',
'05',
+ '05',
'seconds'
),
array(
'U',
'20120102090705',
'1325495225',
+ '1325462825',
'unix time'
),
array(
't',
'20120102090705',
'31',
+ '31',
'Days in current month'
),
array(
'c',
'20120102090705',
'2012-01-02T09:07:05+00:00',
+ '2012-01-02T09:07:05+09:00',
'ISO 8601 timestamp'
),
array(
'r',
'20120102090705',
'Mon, 02 Jan 2012 09:07:05 +0000',
+ 'Mon, 02 Jan 2012 09:07:05 +0900',
'RFC 5322'
),
+ array(
+ 'e',
+ '20120102090705',
+ 'UTC',
+ 'Asia/Seoul',
+ 'Timezone identifier'
+ ),
+ array(
+ 'I',
+ '19880602090705',
+ '0',
+ '1',
+ 'DST indicator'
+ ),
+ array(
+ 'O',
+ '20120102090705',
+ '+0000',
+ '+0900',
+ 'Timezone offset'
+ ),
+ array(
+ 'P',
+ '20120102090705',
+ '+00:00',
+ '+09:00',
+ 'Timezone offset with colon'
+ ),
+ array(
+ 'T',
+ '20120102090705',
+ 'UTC',
+ 'KST',
+ 'Timezone abbreviation'
+ ),
+ array(
+ 'Z',
+ '20120102090705',
+ '0',
+ '32400',
+ 'Timezone offset in seconds'
+ ),
array(
'xmj xmF xmn xmY',
'20120102090705',
'7 Safar 2 1433',
+ '7 Safar 2 1433',
'Islamic'
),
array(
'xij xiF xin xiY',
'20120102090705',
'12 Dey 10 1390',
+ '12 Dey 10 1390',
'Iranian'
),
array(
'xjj xjF xjn xjY',
'20120102090705',
'7 Tevet 4 5772',
+ '7 Tevet 4 5772',
'Hebrew'
),
array(
'xjt',
'20120102090705',
'29',
+ '29',
'Hebrew number of days in month'
),
array(
'xjx',
'20120102090705',
'Tevet',
+ 'Tevet',
'Hebrew genitive month name (No difference in EN)'
),
array(
'xkY',
'20120102090705',
'2555',
+ '2555',
'Thai year'
),
array(
'xoY',
'20120102090705',
'101',
+ '101',
'Minguo'
),
array(
'xtY',
'20120102090705',
'平成24',
+ '平成24',
'nengo'
),
array(
'xrxkYY',
'20120102090705',
'MMDLV2012',
+ 'MMDLV2012',
'Roman numerals'
),
array(
'xhxjYY',
'20120102090705',
'ה\'תשע"ב2012',
+ 'ה\'תשע"ב2012',
'Hebrew numberals'
),
array(
'xnY',
'20120102090705',
'2012',
+ '2012',
'Raw numerals (doesn\'t mean much in EN)'
),
array(
'[[Y "(yea"\\r)]] \\"xx\\"',
'20120102090705',
'[[2012 (year)]] "x"',
+ '[[2012 (year)]] "x"',
'Various escaping'
),