'hijri-calendar-m10', 'hijri-calendar-m11', 'hijri-calendar-m12'
);
+ // For pretty timestamps
+ // Cutoff for specifying "weekday at XX:XX" format
+ protected $mWeekdayAtCutoff = 432000; // 5 days
+
/**
* @since 1.20
* @var array
* @param $usePrefs Mixed: if true, the user's preference is used
* if false, the site/language default is used
* if int/string, assumed to be a format.
+ * if User object, assumed to be a User to get preference from
* @return string
*/
function dateFormat( $usePrefs = true ) {
} else {
$datePreference = (string)User::getDefaultOption( 'date' );
}
+ } elseif ( $usePrefs instanceof User ) {
+ $datePreference = $usePrefs->getDatePreference();
} else {
$datePreference = (string)$usePrefs;
}
$df = self::$dataCache->getSubitem( $this->mCode, 'dateFormats', "$pref $type" );
} else {
$df = self::$dataCache->getSubitem( $this->mCode, 'dateFormats', "$pref $type" );
+
+ if ( $type === 'shortdate' && is_null( $df ) ) {
+ $df = $this->getDateFormatString( 'date', $pref );
+ }
+
if ( is_null( $df ) ) {
$pref = $this->getDefaultDateFormat();
$df = self::$dataCache->getSubitem( $this->mCode, 'dateFormats', "$pref $type" );
}
}
+
$this->dateFormatStrings[$type][$pref] = $df;
}
return $this->dateFormatStrings[$type][$pref];
return $this->internalUserTimeAndDate( 'both', $ts, $user, $options );
}
+ /**
+ * Formats a timestamp in a pretty, human-readable format.
+ * Instead of "13:04, 16 July 2012", we have:
+ * - Just now
+ * - 35 minutes ago
+ * - At 13:04
+ * - Yesterday at 13:04
+ * - Wednesday at 13:04
+ * - July 16, 13:04
+ * - July 16 2012 at 13:04
+ *
+ * @todo Port to JavaScript
+ *
+ * @param $ts Mixed: the time format which needs to be turned into a
+ * date('YmdHis') format with wfTimestamp(TS_MW,$ts)
+ * @param $relativeTo Mixed: The timestamp to use as "now"
+ * @param $user User: The user to format for (needed for timezone information)
+ * @since 1.20
+ * @return string Formatted timestamp
+ */
+ public function prettyTimestamp( $timestamp, $relativeTo = false, $user ) {
+ // Parameter defaults
+ if ( $relativeTo === false ) {
+ $relativeTo = wfTimestampNow();
+ }
+
+ // Normalise input to UNIX time
+ $relativeTo = wfTimestamp( TS_UNIX, $relativeTo );
+ $timestamp = wfTimestamp( TS_UNIX, $timestamp );
+ $timeAgo = $relativeTo - $timestamp;
+
+ $adjustedRelativeTo = $this->userAdjust( wfTimestamp( TS_MW, $relativeTo ), $user->getOption('timecorrection') );
+ $adjustedRelativeTo = wfTimestamp( TS_UNIX, $adjustedRelativeTo );
+ $relativeToYear = gmdate( 'Y', $adjustedRelativeTo );
+
+ $adjustedTimestamp = $this->userAdjust( wfTimestamp( TS_MW, $timestamp ), $user->getOption('timecorrection') );
+ $adjustedTimestamp = wfTimestamp( TS_UNIX, $adjustedTimestamp );
+ $timestampYear = gmdate( 'Y', $adjustedTimestamp );
+
+ if ( $timeAgo < 0 ) {
+ throw new MWException( "Future timestamps not currently supported" );
+ } elseif ( $timeAgo < 30 ) {
+ return wfMessage( 'just-now' )
+ ->inLanguage( $this )
+ ->text();
+ } elseif ( $timeAgo < 5400 ) {
+ // Less than 90 minutes ago. Return number of hours, minutes or seconds ago.
+ return $this->formatRelativeTime( $timeAgo );
+ } elseif ( // Same day
+ intval( $adjustedRelativeTo / (24*60*60) ) ===
+ intval( $adjustedTimestamp / (24*60*60) )
+ ) {
+ // Today at XX:XX
+ $time = $this->time( $adjustedTimestamp );
+ return wfMessage( 'today-at' )
+ ->inLanguage( $this )
+ ->params( $time )
+ ->text();
+ } elseif ( // Previous day
+ intval( $adjustedRelativeTo / (24*60*60) ) ===
+ ( intval( $adjustedTimestamp / (24*60*60) ) + 1 )
+ ) {
+ // Yesterday at XX:XX
+ $time = $this->time( $adjustedTimestamp );
+
+ return wfMessage( 'yesterday-at' )
+ ->inLanguage( $this )
+ ->params( $time )
+ ->text();
+ } elseif ( $timeAgo < ( $this->mWeekdayAtCutoff ) ) { // Less than 5 days ago
+ // Xday at XX:XX
+ return $this->formatPastWeekTimestamp( $adjustedTimestamp, $adjustedRelativeTo );
+ } elseif ( $relativeToYear == $timestampYear ) {
+ // XX XMonth
+ $df = $this->getDateFormatString( 'shortdate', $this->dateFormat( $user ) );
+ $mwTimestamp = wfTimestamp( TS_MW, $timestamp );
+ return $this->sprintfDate( $df, $mwTimestamp );
+ } else {
+ // Full timestamp
+ $mwTimestamp = wfTimestamp( TS_MW, $timestamp );
+ return $this->userDate( $mwTimestamp, $user );
+ }
+ }
+
+ /**
+ * For pretty timestamps: Formats the "X {hours,minutes,seconds} ago" message.
+ *
+ * @param $timeAgo The number of seconds ago the event occurred
+ * @return Formatted string
+ */
+ protected function formatRelativeTime( $timeAgo ) {
+ $count = false;
+ if ( $timeAgo < 60 ) {
+ $unit = 'seconds';
+ $count = $timeAgo;
+ } elseif ( $timeAgo < 3600 ) {
+ $unit = 'minutes';
+ $count = intval( $timeAgo / 60 );
+ } else {
+ $unit = 'hours';
+ $count = intval( $timeAgo / 3600 );
+ }
+
+ return wfMessage( "{$unit}-ago" )->inLanguage( $this )->params( $count )->text();
+ }
+
+ /**
+ * For pretty timestamps: Formats the timestamp for events that occurred
+ * "in the last few days".
+ * (cutoff is configurable by the member variable $mWeekdayAtCutoff)
+ *
+ * @param $eventTimestamp The timestamp of the event, adjusted to
+ * the user's local timezone, in UNIX format (# of seconds since epoch)
+ * @param $relativeTo The timestamp to format relative to, adjusted to
+ * the user's local timezone, in UNIX format (# of seconds since epoch)
+ * @return String: The date formatted in a human-friendly way.
+ */
+ protected function formatPastWeekTimestamp( $adjustedTimestamp, $relativeTo ) {
+ $day = date( 'w', $adjustedTimestamp );
+ $weekday = self::$mWeekdayMsgs[$day];
+ $time = $this->time( $adjustedTimestamp );
+
+ return wfMessage( "$weekday-at" )
+ ->inLanguage( $this )
+ ->params( $time )
+ ->text();
+ }
+
/**
* @param $key string
* @return array|null
'mdy time' => 'H:i',
'mdy date' => 'F j, Y',
'mdy both' => 'H:i, F j, Y',
+ 'mdy shortdate' => 'F j',
'dmy time' => 'H:i',
'dmy date' => 'j F Y',
'dmy both' => 'H:i, j F Y',
+ 'dmy shortdate' => 'j F',
'ymd time' => 'H:i',
'ymd date' => 'Y F j',
'ymd both' => 'H:i, Y F j',
+ 'ymd shortdate' => 'F j',
'ISO 8601 time' => 'xnH:xni:xns',
'ISO 8601 date' => 'xnY-xnm-xnd',
'ISO 8601 both' => 'xnY-xnm-xnd"T"xnH:xni:xns',
+ // 'ISO 8601 shortdate' => 'xnm-xnd', // This is just confusing
);
/**
'days' => '{{PLURAL:$1|$1 day|$1 days}}',
'ago' => '$1 ago',
+'hours-ago' => '$1 {{PLURAL:$1|hour|hours}} ago',
+'minutes-ago' => '$1 {{PLURAL:$1|minute|minutes}} ago',
+'seconds-ago' => '$1 {{PLURAL:$1|seconds|seconds}} ago',
+
+'monday-at' => 'Monday at $1',
+'tuesday-at' => 'Tuesday at $1',
+'wednesday-at' => 'Wednesday at $1',
+'thursday-at' => 'Thursday at $1',
+'friday-at' => 'Friday at $1',
+'saturday-at' => 'Saturday at $1',
+'sunday-at' => 'Sunday at $1',
+
+'today-at' => '$1',
+'yesterday-at' => 'Yesterday at $1',
+'just-now' => 'Just now',
+
# Bad image list
'bad_image_list' => 'The format is as follows:
*{{msg-mw|Hours}}
*{{msg-mw|Days}}',
+'hours-ago' => 'Phrase for indicating that something occurred a certain number of hours ago',
+'minutes-ago' => 'Phrase for indicating that something occurred a certain number of minutes ago',
+'seconds-ago' => 'Phrase for indicating that something occurred a certain number of seconds ago',
+
+'monday-at' => 'Phrase for indicating that something occurred at a particular time on the most recent Monday. $1 is the time.',
+'tuesday-at' => 'Phrase for indicating that something occurred at a particular time on the most recent Tuesday. $1 is the time.',
+'wednesday-at' => 'Phrase for indicating that something occurred at a particular time on the most recent Wednesday. $1 is the time.',
+'thursday-at' => 'Phrase for indicating that something occurred at a particular time on the most recent Thursday. $1 is the time.',
+'friday-at' => 'Phrase for indicating that something occurred at a particular time on the most recent Friday. $1 is the time.',
+'saturday-at' => 'Phrase for indicating that something occurred at a particular time on the most recent Saturday. $1 is the time.',
+'sunday-at' => 'Phrase for indicating that something occurred at a particular time on the most recent Sunday. $1 is the time.',
+'today-at' => 'Phrase for indicating that something occurred at a particular time today. $1 is the time.',
+'yesterday-at' => 'Phrase for indicating that something occurred at a particular time yesterday. $1 is the time.',
+'just-now' => 'Phrase for indicating that something occurred very recently (for example, less than 30 seconds ago)',
+
# Bad image list
'bad_image_list' => 'This message only appears to guide administrators to add links with the right format. This will not appear anywhere else in MediaWiki.',
) ),
);
}
-}
+ /**
+ * @test
+ * @dataProvider providePrettyTimestampTests
+ */
+ public function testPrettyTimestamp(
+ $tsTime, // The timestamp to format
+ $currentTime, // The time to consider "now"
+ $timeCorrection, // The time offset to use
+ $dateFormat, // The date preference to use
+ $expectedOutput, // The expected output
+ $desc // Description
+ ) {
+ $user = new User;
+ $user->setOption( 'timecorrection', $timeCorrection );
+ $user->setOption( 'date', $dateFormat );
+
+ $this->assertEquals(
+ $expectedOutput,
+ $this->lang->prettyTimestamp( $tsTime, $currentTime, $user ),
+ $desc
+ );
+ }
+
+ public function providePrettyTimestampTests() {
+ return array(
+ array(
+ '20111231170000',
+ '20120101000000',
+ 'Offset|0',
+ 'mdy',
+ 'Yesterday at 17:00',
+ '"Yesterday" across years',
+ ),
+ array(
+ '20120717190900',
+ '20120717190929',
+ 'Offset|0',
+ 'mdy',
+ 'Just now',
+ '"Just now"',
+ ),
+ array(
+ '20120717190900',
+ '20120717191530',
+ 'Offset|0',
+ 'mdy',
+ '6 minutes ago',
+ 'X minutes ago',
+ ),
+ array(
+ '20121006173100',
+ '20121006173200',
+ 'Offset|0',
+ 'mdy',
+ '1 minute ago',
+ '"1 minute ago"',
+ ),
+ array(
+ '20120617190900',
+ '20120717190900',
+ 'Offset|0',
+ 'mdy',
+ 'June 17',
+ 'Another month'
+ ),
+ array(
+ '19910130151500',
+ '20120716193700',
+ 'Offset|0',
+ 'mdy',
+ 'January 30, 1991',
+ 'Different year',
+ ),
+ array(
+ '20120101050000',
+ '20120101080000',
+ 'Offset|-360',
+ 'mdy',
+ 'Yesterday at 23:00',
+ '"Yesterday" across years with time correction',
+ ),
+ array(
+ '20120714184300',
+ '20120716184300',
+ 'Offset|-420',
+ 'mdy',
+ 'Saturday at 11:43',
+ 'Recent weekday with time correction',
+ ),
+ array(
+ '20120714184300',
+ '20120715040000',
+ 'Offset|-420',
+ 'mdy',
+ '11:43',
+ 'Today at another time with time correction',
+ ),
+ array(
+ '20120617190900',
+ '20120717190900',
+ 'Offset|0',
+ 'dmy',
+ '17 June',
+ 'Another month with dmy'
+ ),
+ array(
+ '20120617190900',
+ '20120717190900',
+ 'Offset|0',
+ 'ISO 8601',
+ '2012-06-17',
+ 'Another month with ISO-8601'
+ ),
+ array(
+ '19910130151500',
+ '20120716193700',
+ 'Offset|0',
+ 'ISO 8601',
+ '1991-01-30',
+ 'Different year with ISO-8601',
+ ),
+ );
+ }
+}