duration formatter, makes time in sec easy to read
authorJeroen De Dauw <jeroendedauw@gmail.com>
Tue, 10 Apr 2012 13:37:03 +0000 (15:37 +0200)
committerjeroendedauw <jeroendedauw@gmail.com>
Fri, 13 Apr 2012 11:54:04 +0000 (13:54 +0200)
The Language::formatDuration() method introduced by this patch let us
easily render an amount of seconds for easier human reading.

 $ maintenance/eval.php
 > var_dump( $wgLang->formatDuration( 1000 );
 string(25) "16 minutes and 40 seconds"

Also ran rebuildLanguage.php on Siebrands request

Change-Id: If287fb10e897d3d2374cf6eeae3bc5be00cdfc01

languages/Language.php
languages/messages/MessagesEn.php
maintenance/language/messages.inc
tests/phpunit/languages/LanguageTest.php

index 463ea19..e6feb45 100644 (file)
@@ -139,6 +139,22 @@ class Language {
                'hijri-calendar-m10', 'hijri-calendar-m11', 'hijri-calendar-m12'
        );
 
+       /**
+        * @since 1.20
+        * @var array
+        */
+       static public $durationIntervals = array(
+               'millennia' => 31557600000,
+               'centuries' => 3155760000,
+               'decades' => 315576000,
+               'years' => 31557600, // 86400 * 365.25
+               'weeks' => 604800,
+               'days' => 86400,
+               'hours' => 3600,
+               'minutes' => 60,
+               'seconds' => 1,
+       );
+
        /**
         * Get a cached language object for a given language code
         * @param $code String
@@ -1908,6 +1924,63 @@ class Language {
                return $this->sprintfDate( $df, $ts );
        }
 
+       /**
+        * Takes a number of seconds and turns it into a text using values such as hours and minutes.
+        *
+        * @since 1.20
+        *
+        * @param integer $seconds The amount of seconds.
+        * @param array $chosenIntervals The intervals to enable.
+        *
+        * @return string
+        */
+       public function formatDuration( $seconds, array $chosenIntervals = array() ) {
+               $intervals = $this->getDurationIntervals( $seconds, $chosenIntervals );
+
+               $segments = array();
+
+               foreach ( $intervals as $intervalName => $intervalValue ) {
+                       $message = new Message( 'duration-' . $intervalName, array( $intervalValue ) );
+                       $segments[] = $message->inLanguage( $this )->escaped();
+               }
+
+               return $this->listToText( $segments );
+       }
+
+       /**
+        * Takes a number of seconds and returns an array with a set of corresponding intervals.
+        * For example 65 will be turned into array( minutes => 1, seconds => 5 ).
+        *
+        * @since 1.20
+        *
+        * @param integer $seconds The amount of seconds.
+        * @param array $chosenIntervals The intervals to enable.
+        *
+        * @return array
+        */
+       public function getDurationIntervals( $seconds, array $chosenIntervals = array() ) {
+               if ( empty( $chosenIntervals ) ) {
+                       $chosenIntervals = array( 'millennia', 'centuries', 'decades', 'years', 'days', 'hours', 'minutes', 'seconds' );
+               }
+
+               $intervals = array_intersect_key( self::$durationIntervals, array_flip( $chosenIntervals ) );
+               $sortedNames = array_keys( $intervals );
+               $smallestInterval = array_pop( $sortedNames );
+
+               $segments = array();
+
+               foreach ( $intervals as $name => $length ) {
+                       $value = floor( $seconds / $length );
+
+                       if ( $value > 0 || ( $name == $smallestInterval && empty( $segments ) ) ) {
+                               $seconds -= $value * $length;
+                               $segments[$name] = $value;
+                       }
+               }
+
+               return $segments;
+       }
+
        /**
         * Internal helper function for userDate(), userTime() and userTimeAndDate()
         *
index 6b07bc6..1055554 100644 (file)
@@ -999,9 +999,6 @@ Please report this to an [[Special:ListUsers/sysop|administrator]], making note
 'directorycreateerror' => 'Could not create directory "$1".',
 'filenotfound'         => 'Could not find file "$1".',
 'fileexistserror'      => 'Unable to write to file "$1": File exists.',
-'filereadonlyerror'    => 'Unable to modify the file "$1" because the file repository "$2" is in read-only mode.
-
-The administrator who locked it offered this explanation: "$3".',
 'unexpected'           => 'Unexpected value: "$1"="$2".',
 'formerror'            => 'Error: Could not submit form.',
 'badarticleerror'      => 'This action cannot be performed on this page.',
@@ -1039,6 +1036,9 @@ $2',
 'ns-specialprotected'  => 'Special pages cannot be edited.',
 'titleprotected'       => 'This title has been protected from creation by [[User:$1|$1]].
 The reason given is "\'\'$2\'\'".',
+'filereadonlyerror'    => 'Unable to the modify the file "$1" because the file repository "$2" is in read-only mode.
+
+The administrator who locked it offered this explanation: "$3".',
 
 # Virus scanner
 'virus-badscanner'     => "Bad configuration: Unknown virus scanner: ''$1''",
@@ -2282,7 +2282,6 @@ If the problem persists, contact an [[Special:ListUsers/sysop|administrator]].',
 'backend-fail-contenttype'   => 'Could not determine the content type of the file to store at "$1".',
 'backend-fail-batchsize'     => 'Storage backend given a batch of $1 file {{PLURAL:$1|operation|operations}}; the limit is $2 {{PLURAL:$2|operation|operations}}.',
 
-# File journal
 'filejournal-fail-dbconnect' => 'Could not connect to the journal database for storage backend "$1".',
 'filejournal-fail-dbquery'   => 'Could not update the journal database for storage backend "$1".',
 
@@ -2653,23 +2652,23 @@ You can narrow down the view by selecting a log type, the username (case-sensiti
 'log-title-wildcard'   => 'Search titles starting with this text',
 
 # Special:AllPages
-'allpages'          => 'All pages',
-'allpages-summary'  => '', # do not translate or duplicate this message to other languages
-'alphaindexline'    => '$1 to $2',
-'nextpage'          => 'Next page ($1)',
-'prevpage'          => 'Previous page ($1)',
-'allpagesfrom'      => 'Display pages starting at:',
-'allpagesto'        => 'Display pages ending at:',
-'allarticles'       => 'All pages',
-'allinnamespace'    => 'All pages ($1 namespace)',
-'allnotinnamespace' => 'All pages (not in $1 namespace)',
-'allpagesprev'      => 'Previous',
-'allpagesnext'      => 'Next',
-'allpagessubmit'    => 'Go',
-'allpagesprefix'    => 'Display pages with prefix:',
-'allpagesbadtitle'  => 'The given page title was invalid or had an inter-language or inter-wiki prefix.
+'allpages'                => 'All pages',
+'allpages-summary'        => '', # do not translate or duplicate this message to other languages
+'alphaindexline'          => '$1 to $2',
+'nextpage'                => 'Next page ($1)',
+'prevpage'                => 'Previous page ($1)',
+'allpagesfrom'            => 'Display pages starting at:',
+'allpagesto'              => 'Display pages ending at:',
+'allarticles'             => 'All pages',
+'allinnamespace'          => 'All pages ($1 namespace)',
+'allnotinnamespace'       => 'All pages (not in $1 namespace)',
+'allpagesprev'            => 'Previous',
+'allpagesnext'            => 'Next',
+'allpagessubmit'          => 'Go',
+'allpagesprefix'          => 'Display pages with prefix:',
+'allpagesbadtitle'        => 'The given page title was invalid or had an inter-language or inter-wiki prefix.
 It may contain one or more characters which cannot be used in titles.',
-'allpages-bad-ns'   => '{{SITENAME}} does not have namespace "$1".',
+'allpages-bad-ns'         => '{{SITENAME}} does not have namespace "$1".',
 'allpages-hide-redirects' => 'Hide redirects',
 
 # Special:Categories
@@ -4832,4 +4831,15 @@ Otherwise, you can use the easy form below. Your comment will be added to the pa
 'api-error-uploaddisabled'                => 'Uploading is disabled on this wiki.',
 'api-error-verification-error'            => 'This file might be corrupt, or have the wrong extension.',
 
+# Durations
+'duration-seconds'   => '$1 {{PLURAL:$1|second|seconds}}',
+'duration-minutes'   => '$1 {{PLURAL:$1|minute|minutes}}',
+'duration-hours'     => '$1 {{PLURAL:$1|hour|hours}}',
+'duration-days'      => '$1 {{PLURAL:$1|day|days}}',
+'duration-weeks'     => '$1 {{PLURAL:$1|week|weeks}}',
+'duration-years'     => '$1 {{PLURAL:$1|year|years}}',
+'duration-decades'   => '$1 {{PLURAL:$1|decade|decades}}',
+'duration-centuries' => '$1 {{PLURAL:$1|century|centuries}}',
+'duration-millennia' => '$1 {{PLURAL:$1|millennium|millennia}}',
+
 );
index 4984495..d4184eb 100644 (file)
@@ -3693,6 +3693,17 @@ $wgMessageStructure = array(
                'api-error-uploaddisabled',
                'api-error-verification-error',
        ),
+       'duration' => array(
+               'duration-seconds',
+               'duration-minutes',
+               'duration-hours',
+               'duration-days',
+               'duration-weeks',
+               'duration-years',
+               'duration-decades',
+               'duration-centuries',
+               'duration-millennia'
+       ),
 );
 
 /** Comments for each block */
@@ -3931,4 +3942,5 @@ Variants for Chinese language",
        'logging-irc'           => 'For IRC, see bug 34508. Do not change',
        'feedback'              => 'Feedback',
        'apierrors'             => 'API errors',
+       'duration'              => 'Durations',
 );
index c089c31..4239670 100644 (file)
@@ -654,4 +654,141 @@ class LanguageTest extends MediaWikiTestCase {
                        ),
                );
        }
+
+
+
+       /**
+        * @dataProvider provideFormatDuration
+        */
+       function testFormatDuration( $duration, $expected, $intervals = array() ) {
+               $this->assertEquals(
+                       $expected,
+                       $this->lang->formatDuration( $duration, $intervals ),
+                       "formatDuration('$duration'): $expected"
+               );
+       }
+
+       function provideFormatDuration() {
+               return array(
+                       array(
+                               0,
+                               '0 seconds',
+                       ),
+                       array(
+                               1,
+                               '1 second',
+                       ),
+                       array(
+                               2,
+                               '2 seconds',
+                       ),
+                       array(
+                               60,
+                               '1 minute',
+                       ),
+                       array(
+                               2 * 60,
+                               '2 minutes',
+                       ),
+                       array(
+                               3600,
+                               '1 hour',
+                       ),
+                       array(
+                               2 * 3600,
+                               '2 hours',
+                       ),
+                       array(
+                               24 * 3600,
+                               '1 day',
+                       ),
+                       array(
+                               2 * 86400,
+                               '2 days',
+                       ),
+                       array(
+                               365.25 * 86400, // 365.25 * 86400 = 31557600
+                               '1 year',
+                       ),
+                       array(
+                               2 * 31557600,
+                               '2 years',
+                       ),
+                       array(
+                               10 * 31557600,
+                               '1 decade',
+                       ),
+                       array(
+                               20 * 31557600,
+                               '2 decades',
+                       ),
+                       array(
+                               100 * 31557600,
+                               '1 century',
+                       ),
+                       array(
+                               200 * 31557600,
+                               '2 centuries',
+                       ),
+                       array(
+                               1000 * 31557600,
+                               '1 millennium',
+                       ),
+                       array(
+                               2000 * 31557600,
+                               '2 millennia',
+                       ),
+                       array(
+                               9001,
+                               '2 hours, 30 minutes and 1 second'
+                       ),
+                       array(
+                               3601,
+                               '1 hour and 1 second'
+                       ),
+                       array(
+                               31557600 + 2 * 86400 + 9000,
+                               '1 year, 2 days, 2 hours and 30 minutes'
+                       ),
+                       array(
+                               42 * 1000 * 31557600 + 42,
+                               '42 millennia and 42 seconds'
+                       ),
+                       array(
+                               60,
+                               '60 seconds',
+                               array( 'seconds' ),
+                       ),
+                       array(
+                               61,
+                               '61 seconds',
+                               array( 'seconds' ),
+                       ),
+                       array(
+                               1,
+                               '1 second',
+                               array( 'seconds' ),
+                       ),
+                       array(
+                               31557600 + 2 * 86400 + 9000,
+                               '1 year, 2 days and 150 minutes',
+                               array( 'years', 'days', 'minutes' ),
+                       ),
+                       array(
+                               42,
+                               '0 days',
+                               array( 'years', 'days' ),
+                       ),
+                       array(
+                               31557600 + 2 * 86400 + 9000,
+                               '1 year, 2 days and 150 minutes',
+                               array( 'minutes', 'days', 'years' ),
+                       ),
+                       array(
+                               42,
+                               '0 days',
+                               array( 'days', 'years' ),
+                       ),
+               );
+       }
 }