Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
36.96% covered (danger)
36.96%
17 / 46
16.67% covered (danger)
16.67%
1 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
MWTimestamp
37.78% covered (danger)
37.78%
17 / 45
16.67% covered (danger)
16.67%
1 / 6
34.09
0.00% covered (danger)
0.00%
0 / 1
 getInstance
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 fromMW
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 offsetForUser
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
6
 getRelativeTimestamp
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
2
 getTimezoneMessage
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
 getLocalInstance
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * Creation and parsing of MW-style timestamps.
4 *
5 * @license GPL-2.0-or-later
6 * @file
7 * @since 1.20
8 * @author Tyler Romeo, 2012
9 */
10
11namespace MediaWiki\Utils;
12
13use DateInterval;
14use DateTime;
15use DateTimeZone;
16use MediaWiki\Context\RequestContext;
17use MediaWiki\HookContainer\HookRunner;
18use MediaWiki\Language\Language;
19use MediaWiki\Language\RawMessage;
20use MediaWiki\MainConfigNames;
21use MediaWiki\MediaWikiServices;
22use MediaWiki\Message\Message;
23use MediaWiki\User\User;
24use MediaWiki\User\UserIdentity;
25use MediaWiki\User\UserTimeCorrection;
26use Wikimedia\Timestamp\ConvertibleTimestamp;
27
28/**
29 * Library for creating and parsing MW-style timestamps. Based on the JS
30 * library that does the same thing.
31 *
32 * @newable
33 *
34 * @since 1.20
35 */
36class MWTimestamp extends ConvertibleTimestamp {
37    /**
38     * Get a timestamp instance in GMT
39     *
40     * @param bool|string $ts Timestamp to set, or false for current time
41     */
42    public static function getInstance( $ts = false ): static {
43        return new static( $ts );
44    }
45
46    /**
47     * Convert a TS::MW format string, with optional time zone, to
48     * a MWTimestamp.
49     *
50     * This is more efficient that using the general constructor,
51     * which has a long list of string formats that it attempts to
52     * match against.
53     */
54    public static function fromMW( string $ts_mw, ?DateTimeZone $zone = null ): static {
55        $date = DateTime::createFromFormat(
56            'YmdHis', $ts_mw, $zone ?: new DateTimeZone( 'UTC' )
57        );
58        return new static( $date );
59    }
60
61    /**
62     * Adjust the timestamp depending on the given user's preferences.
63     *
64     * @since 1.22
65     *
66     * @param UserIdentity $user User to take preferences from
67     * @return DateInterval Offset that was applied to the timestamp
68     */
69    public function offsetForUser( UserIdentity $user ) {
70        $option = MediaWikiServices::getInstance()->getUserOptionsLookup()->getOption( $user, 'timecorrection' );
71
72        $value = new UserTimeCorrection(
73            $option,
74            $this->timestamp,
75            MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::LocalTZoffset )
76        );
77        $tz = $value->getTimeZone();
78        if ( $tz ) {
79            $this->timestamp->setTimezone( $tz );
80            return new DateInterval( 'P0Y' );
81        }
82        $interval = $value->getTimeOffsetInterval();
83        $this->timestamp->add( $interval );
84        return $interval;
85    }
86
87    /**
88     * Generate a purely relative timestamp, i.e., represent the time elapsed between
89     * the given base timestamp and this object.
90     *
91     * @param MWTimestamp|null $relativeTo Relative base timestamp (defaults to now)
92     * @param UserIdentity|null $user Use to use offset for
93     * @param Language|null $lang Language to use
94     * @param array $chosenIntervals Intervals to use to represent it
95     * @return string Relative timestamp
96     */
97    public function getRelativeTimestamp(
98        ?MWTimestamp $relativeTo = null,
99        ?UserIdentity $user = null,
100        ?Language $lang = null,
101        array $chosenIntervals = []
102    ) {
103        $relativeTo ??= new self();
104        $user ??= RequestContext::getMain()->getUser();
105        $lang ??= RequestContext::getMain()->getLanguage();
106
107        $ts = '';
108        $diff = $this->diff( $relativeTo );
109
110        $user = User::newFromIdentity( $user ); // For compatibility with the hook signature
111        if ( ( new HookRunner( MediaWikiServices::getInstance()->getHookContainer() ) )->onGetRelativeTimestamp(
112            $ts,
113            $diff,
114            $this,
115            $relativeTo,
116            $user,
117            $lang
118        ) ) {
119            $seconds = ( ( ( $diff->days * 24 + $diff->h ) * 60 + $diff->i ) * 60 + $diff->s );
120            $ts = wfMessage( 'ago', $lang->formatDuration( $seconds, $chosenIntervals ) )->inLanguage( $lang )->text();
121        }
122
123        return $ts;
124    }
125
126    /**
127     * Get the localized timezone message, if available.
128     *
129     * Premade translations are not shipped as format() may return whatever the
130     * system uses, localized or not, so translation must be done through wiki.
131     *
132     * @since 1.27
133     * @return Message The localized timezone message
134     */
135    public function getTimezoneMessage() {
136        $tzMsg = $this->format( 'T' );  // might vary on DST changeover!
137        $key = 'timezone-' . strtolower( trim( $tzMsg ) );
138        $msg = wfMessage( $key );
139        if ( $msg->exists() ) {
140            return $msg;
141        }
142
143        return new RawMessage( $tzMsg );
144    }
145
146    /**
147     * Get a timestamp instance in the server local timezone ($wgLocaltimezone)
148     *
149     * @since 1.22
150     * @param bool|string $ts Timestamp to set, or false for current time
151     * @return MWTimestamp The local instance
152     */
153    public static function getLocalInstance( $ts = false ) {
154        $localtimezone = MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::Localtimezone );
155        $timestamp = new self( $ts );
156        $timestamp->setTimezone( $localtimezone );
157        return $timestamp;
158    }
159}
160
161/** @deprecated class alias since 1.41 */
162class_alias( MWTimestamp::class, 'MWTimestamp' );