]> scripts.mit.edu Git - autoinstalls/mediawiki.git/blob - vendor/wikimedia/timestamp/src/ConvertibleTimestamp.php
MediaWiki 1.30.2-scripts
[autoinstalls/mediawiki.git] / vendor / wikimedia / timestamp / src / ConvertibleTimestamp.php
1 <?php
2 /**
3  * Timestamp
4  *
5  * Copyright (C) 2012 Tyler Romeo <tylerromeo@gmail.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  * http://www.gnu.org/copyleft/gpl.html
21  *
22  * @file
23  * @author Tyler Romeo <tylerromeo@gmail.com>
24  */
25
26 namespace Wikimedia\Timestamp;
27
28 use DateInterval;
29 use DateTime;
30 use DateTimeZone;
31 use Exception;
32
33 /**
34  * Library for creating, parsing, and converting timestamps.
35  */
36 class ConvertibleTimestamp {
37         /**
38          * Standard gmdate() formats for the different timestamp types.
39          */
40         private static $formats = [
41                 TS_UNIX => 'U',
42                 TS_MW => 'YmdHis',
43                 TS_DB => 'Y-m-d H:i:s',
44                 TS_ISO_8601 => 'Y-m-d\TH:i:s\Z',
45                 TS_ISO_8601_BASIC => 'Ymd\THis\Z',
46                 TS_EXIF => 'Y:m:d H:i:s', // This shouldn't ever be used, but is included for completeness
47                 TS_RFC2822 => 'D, d M Y H:i:s',
48                 TS_ORACLE => 'd-m-Y H:i:s.000000', // Was 'd-M-y h.i.s A' . ' +00:00' before r51500
49                 TS_POSTGRES => 'Y-m-d H:i:s',
50         ];
51
52         /**
53          * The actual timestamp being wrapped (DateTime object).
54          * @var DateTime
55          */
56         public $timestamp;
57
58         /**
59          * Make a new timestamp and set it to the specified time,
60          * or the current time if unspecified.
61          *
62          * @param bool|string|int|float|DateTime $timestamp Timestamp to set, or false for current time
63          */
64         public function __construct( $timestamp = false ) {
65                 if ( $timestamp instanceof DateTime ) {
66                         $this->timestamp = $timestamp;
67                 } else {
68                         $this->setTimestamp( $timestamp );
69                 }
70         }
71
72         /**
73          * Set the timestamp to the specified time, or the current time if unspecified.
74          *
75          * Parse the given timestamp into either a DateTime object or a Unix timestamp,
76          * and then store it.
77          *
78          * @param string|bool $ts Timestamp to store, or false for now
79          * @throws TimestampException
80          */
81         public function setTimestamp( $ts = false ) {
82                 $m = [];
83                 $da = [];
84                 $strtime = '';
85
86                 // We want to catch 0, '', null... but not date strings starting with a letter.
87                 if ( !$ts || $ts === "\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ) {
88                         $uts = time();
89                         $strtime = "@$uts";
90                 } elseif ( preg_match( '/^(\d{4})\-(\d\d)\-(\d\d) (\d\d):(\d\d):(\d\d)$/D', $ts, $da ) ) {
91                         # TS_DB
92                 } elseif ( preg_match( '/^(\d{4}):(\d\d):(\d\d) (\d\d):(\d\d):(\d\d)$/D', $ts, $da ) ) {
93                         # TS_EXIF
94                 } elseif ( preg_match( '/^(\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)$/D', $ts, $da ) ) {
95                         # TS_MW
96                 } elseif ( preg_match( '/^(-?\d{1,13})(\.\d+)?$/D', $ts, $m ) ) {
97                         # TS_UNIX
98                         $strtime = "@{$m[1]}"; // http://php.net/manual/en/datetime.formats.compound.php
99                 } elseif ( preg_match( '/^\d{2}-\d{2}-\d{4} \d{2}:\d{2}:\d{2}.\d{6}$/', $ts ) ) {
100                         # TS_ORACLE // session altered to DD-MM-YYYY HH24:MI:SS.FF6
101                         $strtime = preg_replace( '/(\d\d)\.(\d\d)\.(\d\d)(\.(\d+))?/', "$1:$2:$3",
102                                 str_replace( '+00:00', 'UTC', $ts ) );
103                 } elseif ( preg_match(
104                         '/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.*\d*)?Z?$/',
105                         $ts,
106                         $da
107                 ) ) {
108                         # TS_ISO_8601
109                 } elseif ( preg_match(
110                         '/^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})(?:\.*\d*)?Z?$/',
111                         $ts,
112                         $da
113                 ) ) {
114                         # TS_ISO_8601_BASIC
115                 } elseif ( preg_match(
116                         '/^(\d{4})\-(\d\d)\-(\d\d) (\d\d):(\d\d):(\d\d)\.*\d*[\+\- ](\d\d)$/',
117                         $ts,
118                         $da
119                 ) ) {
120                         # TS_POSTGRES
121                 } elseif ( preg_match(
122                         '/^(\d{4})\-(\d\d)\-(\d\d) (\d\d):(\d\d):(\d\d)\.*\d* GMT$/',
123                         $ts,
124                         $da
125                 ) ) {
126                         # TS_POSTGRES
127                 } elseif ( preg_match(
128                 # Day of week
129                         '/^[ \t\r\n]*([A-Z][a-z]{2},[ \t\r\n]*)?' .
130                         # dd Mon yyyy
131                         '\d\d?[ \t\r\n]*[A-Z][a-z]{2}[ \t\r\n]*\d{2}(?:\d{2})?' .
132                         # hh:mm:ss
133                         '[ \t\r\n]*\d\d[ \t\r\n]*:[ \t\r\n]*\d\d[ \t\r\n]*:[ \t\r\n]*\d\d/S',
134                         $ts
135                 ) ) {
136                         # TS_RFC2822, accepting a trailing comment.
137                         # See http://www.squid-cache.org/mail-archive/squid-users/200307/0122.html / r77171
138                         # The regex is a superset of rfc2822 for readability
139                         $strtime = strtok( $ts, ';' );
140                 } elseif ( preg_match( '/^[A-Z][a-z]{5,8}, \d\d-[A-Z][a-z]{2}-\d{2} \d\d:\d\d:\d\d/', $ts ) ) {
141                         # TS_RFC850
142                         $strtime = $ts;
143                 } elseif ( preg_match( '/^[A-Z][a-z]{2} [A-Z][a-z]{2} +\d{1,2} \d\d:\d\d:\d\d \d{4}/', $ts ) ) {
144                         # asctime
145                         $strtime = $ts;
146                 } else {
147                         throw new TimestampException( __METHOD__ . ": Invalid timestamp - $ts" );
148                 }
149
150                 if ( !$strtime ) {
151                         $da = array_map( 'intval', $da );
152                         $da[0] = "%04d-%02d-%02dT%02d:%02d:%02d.00+00:00";
153                         $strtime = call_user_func_array( "sprintf", $da );
154                 }
155
156                 try {
157                         $final = new DateTime( $strtime, new DateTimeZone( 'GMT' ) );
158                 } catch ( Exception $e ) {
159                         throw new TimestampException( __METHOD__ . ': Invalid timestamp format.', $e->getCode(), $e );
160                 }
161
162                 if ( $final === false ) {
163                         throw new TimestampException( __METHOD__ . ': Invalid timestamp format.' );
164                 }
165
166                 $this->timestamp = $final;
167         }
168
169         /**
170          * Convert a timestamp string to a given format.
171          *
172          * @param int $style Constant Output format for timestamp
173          * @param string|int|bool $ts Timestamp
174          * @return string|bool Formatted timestamp or false on failure
175          */
176         public static function convert( $style = TS_UNIX, $ts ) {
177                 try {
178                         $ct = new static( $ts );
179                         return $ct->getTimestamp( $style );
180                 } catch ( TimestampException $e ) {
181                         return false;
182                 }
183         }
184
185         /**
186          * Get the current time in the given format
187          *
188          * @param int $style Constant Output format for timestamp
189          * @return string
190          */
191         public static function now( $style = TS_MW ) {
192                 return static::convert( $style, false );
193         }
194
195         /**
196          * Get the timestamp represented by this object in a certain form.
197          *
198          * Convert the internal timestamp to the specified format and then
199          * return it.
200          *
201          * @param int $style Constant Output format for timestamp
202          * @throws TimestampException
203          * @return string The formatted timestamp
204          */
205         public function getTimestamp( $style = TS_UNIX ) {
206                 if ( !isset( self::$formats[$style] ) ) {
207                         throw new TimestampException( __METHOD__ . ': Illegal timestamp output type.' );
208                 }
209
210                 $output = $this->timestamp->format( self::$formats[$style] );
211
212                 if ( ( $style == TS_RFC2822 ) || ( $style == TS_POSTGRES ) ) {
213                         $output .= ' GMT';
214                 }
215
216                 if ( $style == TS_MW && strlen( $output ) !== 14 ) {
217                         throw new TimestampException( __METHOD__ . ': The timestamp cannot be represented in ' .
218                                 'the specified format' );
219                 }
220
221                 return $output;
222         }
223
224         /**
225          * @return string
226          */
227         public function __toString() {
228                 return $this->getTimestamp();
229         }
230
231         /**
232          * Calculate the difference between two ConvertibleTimestamp objects.
233          *
234          * @param ConvertibleTimestamp $relativeTo Base time to calculate difference from
235          * @return DateInterval|bool The DateInterval object representing the
236          *   difference between the two dates or false on failure
237          */
238         public function diff( ConvertibleTimestamp $relativeTo ) {
239                 return $this->timestamp->diff( $relativeTo->timestamp );
240         }
241
242         /**
243          * Set the timezone of this timestamp to the specified timezone.
244          *
245          * @param string $timezone Timezone to set
246          * @throws TimestampException
247          */
248         public function setTimezone( $timezone ) {
249                 try {
250                         $this->timestamp->setTimezone( new DateTimeZone( $timezone ) );
251                 } catch ( Exception $e ) {
252                         throw new TimestampException( __METHOD__ . ': Invalid timezone.', $e->getCode(), $e );
253                 }
254         }
255
256         /**
257          * Get the timezone of this timestamp.
258          *
259          * @return DateTimeZone The timezone
260          */
261         public function getTimezone() {
262                 return $this->timestamp->getTimezone();
263         }
264
265         /**
266          * Format the timestamp in a given format.
267          *
268          * @param string $format Pattern to format in
269          * @return string The formatted timestamp
270          */
271         public function format( $format ) {
272                 return $this->timestamp->format( $format );
273         }
274 }