These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | use SMW\DataValues\ValueFormatters\DataValueFormatter; |
||
4 | use SMW\Libs\Time\Timezone; |
||
5 | |||
6 | /** |
||
7 | * @ingroup SMWDataValues |
||
8 | */ |
||
9 | |||
10 | /** |
||
11 | * This datavalue captures values of dates and times, in many formats, |
||
12 | * throughout history and pre-history. The implementation can handle dates |
||
13 | * across history with full precision for storing, and substantial precision |
||
14 | * for sorting and querying. The range of supported past dates should encompass |
||
15 | * the Beginning of Time according to most of today's theories. The range of |
||
16 | * supported future dates is limited more strictly, but it does also allow |
||
17 | * year numbers in the order of 10^9. |
||
18 | * |
||
19 | * The implementation notices and stores whether parts of a date/time have been |
||
20 | * omitted (as in "2008" or "May 2007"). For all exporting and sorting |
||
21 | * purposes, incomplete dates are completed with defaults (usually using the |
||
22 | * earliest possible time, i.e. interpreting "2008" as "Jan 1 2008 00:00:00"). |
||
23 | * The information on what was unspecified is kept internally for improving |
||
24 | * behavior e.g. for outputs (defaults are not printed when querying for a |
||
25 | * value). This largely uses the precision handling of SMWDITime. |
||
26 | * |
||
27 | * |
||
28 | * Date formats |
||
29 | * |
||
30 | * Dates can be given in many formats, using numbers, month names, and |
||
31 | * abbreviated month names. The preferred interpretation of ambiguous dates |
||
32 | * ("1 2 2008" or even "1 2 3 BC") is controlled by the language file, as is |
||
33 | * the local naming of months. English month names are always supported. |
||
34 | * |
||
35 | * Dates can be given in Gregorian or Julian calendar, set by the token "Jl" |
||
36 | * or "Gr" in the input. If neither is set, a default is chosen: inputs after |
||
37 | * October 15, 1582 (the time when the Gregorian calendar was first inaugurated |
||
38 | * in some parts of the world) are considered Gr, earlier inputs are considered |
||
39 | * Jl. In addition to Jl and Gr, we support "OS" (Old Style English dates that |
||
40 | * refer to the use of Julian calendar with a displaced change of year on March |
||
41 | * 24), JD (direct numerical input in Julian Day notation), and MJD (direct |
||
42 | * numerical input in Modified Julian Day notation as used in aviation and |
||
43 | * space flight). |
||
44 | * |
||
45 | * The class does not support the input of negative year numbers but uses the |
||
46 | * markers "BC"/"BCE" and "AD"/"CE" instead. There is no year 0 in Gregorian or |
||
47 | * Julian calendars, but the class graciously considers this input to mean year |
||
48 | * 1 BC(E). |
||
49 | * |
||
50 | * For prehisoric dates before 9999 BC(E) only year numbers are allowed |
||
51 | * (nothing else makes much sense). At this time, the years of Julian and |
||
52 | * Gregorian calendar still overlap significantly, so the transition to a |
||
53 | * purely solar annotation of prehistoric years is smooth. Technically, the |
||
54 | * class will consider prehistoric dates as Gregorian but very ancient times |
||
55 | * may be interpreted as desired (probably with reference to a physical notion |
||
56 | * of time that is not dependent on revolutions of earth around the sun). |
||
57 | * |
||
58 | * |
||
59 | * Time formats |
||
60 | * |
||
61 | * Times can be in formats like "23:12:45" and "12:30" possibly with additional |
||
62 | * modifiers "am" or "pm". Timezones are supported: the class knows many |
||
63 | * international timezone monikers (e.g. CET or GMT) and also allows time |
||
64 | * offsets directly after a time (e.g. "10:30-3:30" or "14:45:23+2"). Such |
||
65 | * offsets always refer to UTC. Timezones are only used on input and are not |
||
66 | * stored as part of the value. |
||
67 | * |
||
68 | * Time offsets take leap years into account, e.g. the date |
||
69 | * "Feb 28 2004 23:00+2:00" is equivalent to "29 February 2004 01:00:00", while |
||
70 | * "Feb 28 1900 23:00+2:00" is equivalent to "1 March 1900 01:00:00". |
||
71 | * |
||
72 | * Military time format is supported. This consists of 4 or 6 numeric digits |
||
73 | * followed by a one-letter timezone code (e.g. 1240Z is equivalent to 12:40 |
||
74 | * UTC). |
||
75 | * |
||
76 | * |
||
77 | * I18N |
||
78 | * |
||
79 | * Currently, neither keywords like "BCE", "Jl", or "pm", nor timezone monikers |
||
80 | * are internationalized. Timezone monikers may not require this, other than |
||
81 | * possibly for Cyrillic (added when needed). Month names are fully |
||
82 | * internationalized, but English names and abbreviations will also work in all |
||
83 | * languages. The class also supports ordinal day-of-month annotations like |
||
84 | * "st" and "rd", again only for English. |
||
85 | * |
||
86 | * I18N includes the preferred order of dates, e.g. to interpret "5 6 2010". |
||
87 | * |
||
88 | * @todo Theparsing process can encounter many kinds of well-defined problems |
||
89 | * but uses only one error message. More detailed reporting should be done. |
||
90 | * @todo Try to reuse more of MediaWiki's records, e.g. to obtain month names |
||
91 | * or to format dates. The problem is that MW is based on SIO timestamps that |
||
92 | * don't extend to very ancient or future dates, and that MW uses PHP functions |
||
93 | * that are bound to UNIX time. |
||
94 | * |
||
95 | * @author Markus Krötzsch |
||
96 | * @author Fabian Howahl |
||
97 | * @author Terry A. Hurlbut |
||
98 | * @ingroup SMWDataValues |
||
99 | */ |
||
100 | class SMWTimeValue extends SMWDataValue { |
||
101 | protected $m_dataitem_greg = null; |
||
102 | protected $m_dataitem_jul = null; |
||
103 | |||
104 | protected $m_wikivalue; // a suitable wiki input value |
||
105 | |||
106 | // The following are constant (array-valued constants are not supported, hence the declaration as private static variable): |
||
107 | protected static $m_months = array( 'January', 'February', 'March', 'April' , 'May' , 'June' , 'July' , 'August' , 'September' , 'October' , 'November' , 'December' ); |
||
108 | protected static $m_monthsshort = array( 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ); |
||
109 | protected static $m_formats = array( SMW_Y => array( 'y' ), SMW_YM => array( 'y', 'm' ), SMW_MY => array( 'm', 'y' ), SMW_YDM => array( 'y', 'd', 'm' ), SMW_YMD => array( 'y', 'm', 'd' ), SMW_DMY => array( 'd', 'm', 'y' ), SMW_MDY => array( 'm', 'd', 'y' ) ); |
||
110 | |||
111 | /// Moment of switchover to Gregorian calendar. |
||
112 | const J1582 = 2299160.5; |
||
113 | /// Offset of Julian Days for Modified JD inputs. |
||
114 | const MJD_EPOCH = 2400000.5; |
||
115 | /// The year before which we do not accept anything but year numbers and largely discourage calendar models. |
||
116 | const PREHISTORY = -10000; |
||
117 | |||
118 | 42 | protected function parseUserValue( $value ) { |
|
119 | |||
120 | 42 | $value = $this->convertDoubleWidth( $value ); |
|
121 | 42 | $this->m_wikivalue = $value; |
|
122 | |||
123 | 42 | if ( $this->m_caption === false ) { // Store the caption now. |
|
124 | 42 | $this->m_caption = $value; |
|
125 | } |
||
126 | 42 | $this->m_dataitem = null; |
|
127 | |||
128 | 42 | $datecomponents = array(); |
|
129 | 42 | $calendarmodel = $era = $hours = $minutes = $seconds = $microseconds = $timeoffset = $timezone = false; |
|
130 | 42 | if ( $this->isInterpretableAsYearOnly( $value ) ) { |
|
131 | 15 | $this->m_dataitem = new SMWDITime( $this->getCalendarModel( null, $value, null, null ), $value ); |
|
132 | 35 | } elseif ( $this->isInterpretableAsTimestamp( $value ) ) { |
|
133 | 3 | $this->m_dataitem = SMWDITime::newFromTimestamp( $value ); |
|
134 | 35 | } elseif ( $this->parseDateString( $value, $datecomponents, $calendarmodel, $era, $hours, $minutes, $seconds, $microseconds, $timeoffset, $timezone ) ) { |
|
135 | 35 | if ( ( $calendarmodel === false ) && ( $era === false ) && ( count( $datecomponents ) == 1 ) && ( intval( end( $datecomponents ) ) >= 100000 ) ) { |
|
136 | $calendarmodel = 'JD'; // default to JD input if a single number was given as the date |
||
137 | } |
||
138 | |||
139 | 35 | if ( ( $calendarmodel == 'JD' ) || ( $calendarmodel == 'MJD' ) ) { |
|
140 | 1 | if ( ( $era === false ) && ( $hours === false ) && ( $timeoffset == 0 ) ) { |
|
141 | try { |
||
142 | 1 | $jd = floatval( isset( $datecomponents[1] ) ? $datecomponents[0] . '.' . $datecomponents[1] : $datecomponents[0] ); |
|
143 | 1 | if ( $calendarmodel == 'MJD' ) { |
|
144 | 1 | $jd += self::MJD_EPOCH; |
|
145 | } |
||
146 | 1 | $this->m_dataitem = SMWDITime::newFromJD( $jd, SMWDITime::CM_GREGORIAN, SMWDITime::PREC_YMDT, $timezone ); |
|
147 | } catch ( SMWDataItemException $e ) { |
||
148 | 1 | $this->addErrorMsg( array( 'smw-datavalue-time-invalid-jd', $this->m_wikivalue, $e->getMessage() ) ); |
|
149 | } |
||
150 | } else { |
||
151 | 1 | $this->addErrorMsg( array( 'smw-datavalue-time-invalid-jd', $this->m_wikivalue, "NO_EXCEPTION" ) ); |
|
152 | } |
||
153 | } else { |
||
154 | 35 | $this->setDateFromParsedValues( $datecomponents, $calendarmodel, $era, $hours, $minutes, $seconds, $microseconds, $timeoffset, $timezone ); |
|
155 | } |
||
156 | } |
||
157 | |||
158 | 42 | if ( is_null( $this->m_dataitem ) ) { // make sure that m_dataitem is set in any case |
|
159 | 4 | $this->m_dataitem = new SMWDITime( SMWDITime::CM_GREGORIAN, 32202 ); |
|
160 | } |
||
161 | 42 | } |
|
162 | |||
163 | /** |
||
164 | * Parse the given string to check if it a date/time value. |
||
165 | * The function sets the provided call-by-ref values to the respective |
||
166 | * values. If errors are encountered, they are added to the objects |
||
167 | * error list and false is returned. Otherwise, true is returned. |
||
168 | * @param $string string input time representation, e.g. "12 May 2007 13:45:23-3:30" |
||
169 | * @param $datecomponents array of strings that might belong to the specification of a date |
||
170 | * @param $calendarmodesl string if model was set in input, otherwise false |
||
171 | * @param $era string '+' or '-' if provided, otherwise false |
||
172 | * @param $hours integer set to a value between 0 and 24 |
||
173 | * @param $minutes integer set to a value between 0 and 59 |
||
174 | * @param $seconds integer set to a value between 0 and 59, or false if not given |
||
175 | * @param $timeoffset double set to a value for time offset (e.g. 3.5), or false if not given |
||
176 | * @return boolean stating if the parsing succeeded |
||
177 | * @todo This method in principle allows date parsing to be internationalized further. Should be done. |
||
178 | */ |
||
179 | 35 | protected function parseDateString( $string, &$datecomponents, &$calendarmodel, &$era, &$hours, &$minutes, &$seconds, &$microseconds, &$timeoffset, &$timezone ) { |
|
180 | |||
181 | 35 | $calendarmodel = $timezoneoffset = $era = $ampm = false; |
|
182 | 35 | $hours = $minutes = $seconds = $microseconds = $timeoffset = $timezone = false; |
|
183 | |||
184 | // Fetch possible "America/Argentina/Mendoza" |
||
185 | 35 | $timzoneIdentifier = substr( $string, strrpos( $string, ' ' ) + 1 ); |
|
186 | |||
187 | 35 | if ( Timezone::isValid( $timzoneIdentifier ) ) { |
|
188 | 3 | $string = str_replace( $timzoneIdentifier, '', $string ); |
|
189 | 3 | $timezoneoffset = Timezone::getOffsetByAbbreviation( $timzoneIdentifier ) / 3600; |
|
190 | 3 | $timezone = Timezone::getIdByAbbreviation( $timzoneIdentifier ); |
|
191 | } |
||
192 | |||
193 | // crude preprocessing for supporting different date separation characters; |
||
194 | // * this does not allow localized time notations such as "10.34 pm" |
||
195 | // * this creates problems with keywords that contain "." such as "p.m." |
||
196 | // * yet "." is an essential date separation character in languages such as German |
||
197 | 35 | $parsevalue = str_replace( array( '/', '.', ' ', ',', '年', '月', '日', '時', '分' ), array( '-', ' ', ' ', ' ', ' ', ' ', ' ', ':', ' ' ), $string ); |
|
198 | |||
199 | 35 | $matches = preg_split( "/([T]?[0-2]?[0-9]:[\:0-9]+[+\-]?[0-2]?[0-9\:]+|[\p{L}]+|[0-9]+|[ ])/u", $parsevalue, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY ); |
|
200 | 35 | $datecomponents = array(); |
|
201 | 35 | $unclearparts = array(); |
|
202 | 35 | $matchisnumber = false; // used for looking back; numbers are days/months/years by default but may be re-interpreted if certain further symbols are found |
|
203 | 35 | $matchisdate = false; // used for ensuring that date parts are in one block |
|
204 | |||
205 | 35 | foreach ( $matches as $match ) { |
|
206 | 35 | $prevmatchwasnumber = $matchisnumber; |
|
207 | 35 | $prevmatchwasdate = $matchisdate; |
|
208 | 35 | $matchisnumber = $matchisdate = false; |
|
209 | |||
210 | 35 | if ( $match == ' ' ) { |
|
211 | 32 | $matchisdate = $prevmatchwasdate; // spaces in dates do not end the date |
|
212 | 35 | } elseif ( $match == '-' ) { // can only occur separately between date components |
|
213 | 8 | $datecomponents[] = $match; // we check later if this makes sense |
|
214 | 8 | $matchisdate = true; |
|
215 | 35 | } elseif ( is_numeric( $match ) && |
|
216 | 35 | ( $prevmatchwasdate || count( $datecomponents ) == 0 ) ) { |
|
217 | 34 | $datecomponents[] = $match; |
|
218 | 34 | $matchisnumber = true; |
|
219 | 34 | $matchisdate = true; |
|
220 | 32 | } elseif ( $era === false && in_array( $match, array( 'AD', 'CE' ) ) ) { |
|
221 | 2 | $era = '+'; |
|
222 | 32 | } elseif ( $era === false && in_array( $match, array( 'BC', 'BCE' ) ) ) { |
|
223 | 4 | $era = '-'; |
|
224 | 32 | } elseif ( $calendarmodel === false && in_array( $match, array( 'Gr', 'GR' , 'He', 'Jl', 'JL', 'MJD', 'JD', 'OS' ) ) ) { |
|
225 | 3 | $calendarmodel = $match; |
|
226 | 32 | } elseif ( $ampm === false && ( strtolower( $match ) === 'am' || strtolower( $match ) === 'pm' ) ) { |
|
227 | 8 | $ampm = strtolower( $match ); |
|
228 | 32 | } elseif ( $hours === false && self::parseTimeString( $match, $hours, $minutes, $seconds, $timeoffset ) ) { |
|
229 | // nothing to do |
||
230 | 32 | } elseif ( $hours !== false && $timezoneoffset === false && Timezone::isValid( $match ) ) { |
|
231 | // only accept timezone if time has already been set |
||
232 | $timezoneoffset = Timezone::getOffsetByAbbreviation( $match ) / 3600; |
||
233 | $timezone = Timezone::getIdByAbbreviation( $match ); |
||
234 | 32 | } elseif ( $prevmatchwasnumber && $hours === false && $timezoneoffset === false && |
|
235 | 32 | Timezone::isMilitary( $match ) && |
|
236 | 32 | self::parseMilTimeString( end( $datecomponents ), $hours, $minutes, $seconds ) ) { |
|
237 | // military timezone notation is found after a number -> re-interpret the number as military time |
||
238 | array_pop( $datecomponents ); |
||
239 | $timezoneoffset = Timezone::getOffsetByAbbreviation( $match ) / 3600; |
||
240 | $timezone = Timezone::getIdByAbbreviation( $match ); |
||
241 | 32 | } elseif ( ( $prevmatchwasdate || count( $datecomponents ) == 0 ) && |
|
242 | 32 | $this->parseMonthString( $match, $monthname ) ) { |
|
243 | 31 | $datecomponents[] = $monthname; |
|
244 | 31 | $matchisdate = true; |
|
245 | 4 | } elseif ( $prevmatchwasnumber && $prevmatchwasdate && in_array( $match, array( 'st', 'nd', 'rd', 'th' ) ) ) { |
|
246 | $datecomponents[] = 'd' . strval( array_pop( $datecomponents ) ); // must be a day; add standard marker |
||
247 | $matchisdate = true; |
||
248 | 4 | } elseif ( count( $match ) == 1 ) { |
|
249 | 4 | $microseconds = $match; |
|
250 | } else { |
||
251 | 35 | $unclearparts[] = $match; |
|
252 | } |
||
253 | } |
||
254 | |||
255 | |||
256 | // Useful for debugging: |
||
257 | // print "\n\n Results \n\n"; |
||
258 | // debug_zval_dump( $datecomponents ); |
||
0 ignored issues
–
show
|
|||
259 | // print "\ncalendarmodel: $calendarmodel \ntimezoneoffset: $timezoneoffset \nera: $era \nampm: $ampm \nh: $hours \nm: $minutes \ns:$seconds \ntimeoffset: $timeoffset \n"; |
||
260 | // debug_zval_dump( $unclearparts ); |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
50% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them.
Loading history...
|
|||
261 | |||
262 | // Abort if we found unclear or over-specific information: |
||
263 | 35 | if ( count( $unclearparts ) != 0 ) { |
|
264 | $this->addErrorMsg( array( 'smw-datavalue-time-invalid-values', $this->m_wikivalue, implode( ', ', $unclearparts ) ) ); |
||
265 | return false; |
||
266 | } |
||
267 | |||
268 | 35 | if ( ( $timezoneoffset !== false && $timeoffset !== false ) ) { |
|
269 | $this->addErrorMsg( array( 'smw-datavalue-time-invalid-offset-zone-usage', $this->m_wikivalue ) ); |
||
270 | return false; |
||
271 | } |
||
272 | |||
273 | 35 | if ( ( $timezoneoffset !== false && $timeoffset !== false ) ) { |
|
274 | $this->addErrorMsg( array( 'smw-datavalue-time-invalid-offset-zone-usage', $this->m_wikivalue ) ); |
||
275 | return false; |
||
276 | } |
||
277 | |||
278 | 35 | $timeoffset = $timeoffset + $timezoneoffset; |
|
279 | // Check if the a.m. and p.m. information is meaningful |
||
280 | |||
281 | 35 | if ( $ampm !== false && ( $hours > 12 || $hours == 0 ) ) { // Note: the == 0 check subsumes $hours===false |
|
282 | 1 | $this->addErrorMsg( array( 'smw-datavalue-time-invalid-ampm', $this->m_wikivalue, $hours ) ); |
|
283 | 1 | return false; |
|
284 | 35 | } elseif ( $ampm == 'am' && $hours == 12 ) { |
|
285 | $hours = 0; |
||
286 | 35 | } elseif ( $ampm == 'pm' && $hours < 12 ) { |
|
287 | 8 | $hours += 12; |
|
288 | } |
||
289 | |||
290 | 35 | return true; |
|
291 | } |
||
292 | |||
293 | /** |
||
294 | * Parse the given string to check if it encodes an international time. |
||
295 | * If successful, the function sets the provided call-by-ref values to |
||
296 | * the respective numbers and returns true. Otherwise, it returns |
||
297 | * false and does not set any values. |
||
298 | * @note This method is only temporarily public for enabling SMWCompatibilityHelpers. Do not use it directly in your code. |
||
299 | * |
||
300 | * @param $string string input time representation, e.g. "13:45:23-3:30" |
||
301 | * @param $hours integer between 0 and 24 |
||
302 | * @param $minutes integer between 0 and 59 |
||
303 | * @param $seconds integer between 0 and 59, or false if not given |
||
304 | * @param $timeoffset double for time offset (e.g. 3.5), or false if not given |
||
305 | * @return boolean stating if the parsing succeeded |
||
306 | */ |
||
307 | 32 | public static function parseTimeString( $string, &$hours, &$minutes, &$seconds, &$timeoffset ) { |
|
308 | 32 | if ( !preg_match( "/^[T]?([0-2]?[0-9]):([0-5][0-9])(:[0-5][0-9])?(([+\-][0-2]?[0-9])(:(30|00))?)?$/u", $string, $match ) ) { |
|
309 | 32 | return false; |
|
310 | } else { |
||
311 | 17 | $nhours = intval( $match[1] ); |
|
312 | 17 | $nminutes = $match[2] ? intval( $match[2] ) : false; |
|
313 | 17 | if ( ( count( $match ) > 3 ) && ( $match[3] !== '' ) ) { |
|
314 | 7 | $nseconds = intval( substr( $match[3], 1 ) ); |
|
315 | } else { |
||
316 | 14 | $nseconds = false; |
|
317 | } |
||
318 | 17 | if ( ( $nhours < 25 ) && ( ( $nhours < 24 ) || ( $nminutes + $nseconds == 0 ) ) ) { |
|
319 | 17 | $hours = $nhours; |
|
320 | 17 | $minutes = $nminutes; |
|
321 | 17 | $seconds = $nseconds; |
|
322 | 17 | if ( ( count( $match ) > 5 ) && ( $match[5] !== '' ) ) { |
|
323 | 3 | $timeoffset = intval( $match[5] ); |
|
324 | 3 | if ( ( count( $match ) > 7 ) && ( $match[7] == '30' ) ) { |
|
325 | 3 | $timeoffset += 0.5; |
|
326 | } |
||
327 | } else { |
||
328 | 17 | $timeoffset = false; |
|
329 | } |
||
330 | 17 | return true; |
|
331 | } else { |
||
332 | return false; |
||
333 | } |
||
334 | } |
||
335 | } |
||
336 | |||
337 | /** |
||
338 | * Parse the given string to check if it encodes a "military time". |
||
339 | * If successful, the function sets the provided call-by-ref values to |
||
340 | * the respective numbers and returns true. Otherwise, it returns |
||
341 | * false and does not set any values. |
||
342 | * @param $string string input time representation, e.g. "134523" |
||
343 | * @param $hours integer between 0 and 24 |
||
344 | * @param $minutes integer between 0 and 59 |
||
345 | * @param $seconds integer between 0 and 59, or false if not given |
||
346 | * @return boolean stating if the parsing succeeded |
||
347 | */ |
||
348 | protected static function parseMilTimeString( $string, &$hours, &$minutes, &$seconds ) { |
||
349 | if ( !preg_match( "/^([0-2][0-9])([0-5][0-9])([0-5][0-9])?$/u", $string, $match ) ) { |
||
350 | return false; |
||
351 | } else { |
||
352 | $nhours = intval( $match[1] ); |
||
353 | $nminutes = $match[2] ? intval( $match[2] ) : false; |
||
354 | $nseconds = ( ( count( $match ) > 3 ) && $match[3] ) ? intval( $match[3] ) : false; |
||
355 | if ( ( $nhours < 25 ) && ( ( $nhours < 24 ) || ( $nminutes + $nseconds == 0 ) ) ) { |
||
356 | $hours = $nhours; |
||
357 | $minutes = $nminutes; |
||
358 | $seconds = $nseconds; |
||
359 | return true; |
||
360 | } else { |
||
361 | return false; |
||
362 | } |
||
363 | } |
||
364 | } |
||
365 | |||
366 | /** |
||
367 | * Parse the given string to check if it refers to the string name ot |
||
368 | * abbreviation of a month name. If yes, it is replaced by a normalized |
||
369 | * month name (placed in the call-by-ref parameter) and true is |
||
370 | * returned. Otherwise, false is returned and $monthname is not changed. |
||
371 | * @param $string string month name or abbreviation to parse |
||
372 | * @param $monthname string with standard 3-letter English month abbreviation |
||
373 | * @return boolean stating whether a month was found |
||
374 | */ |
||
375 | 32 | protected static function parseMonthString( $string, &$monthname ) { |
|
376 | /** |
||
377 | * @var SMWLanguage $smwgContLang |
||
378 | */ |
||
379 | 32 | global $smwgContLang; |
|
380 | |||
381 | 32 | $monthnum = $smwgContLang->findMonth( $string ); // takes precedence over English month names! |
|
382 | |||
383 | 32 | if ( $monthnum !== false ) { |
|
384 | 31 | $monthnum -= 1; |
|
385 | } else { |
||
386 | 4 | $monthnum = array_search( $string, self::$m_months ); // check English names |
|
387 | } |
||
388 | |||
389 | 32 | if ( $monthnum !== false ) { |
|
390 | 31 | $monthname = self::$m_monthsshort[$monthnum]; |
|
391 | 31 | return true; |
|
392 | 3 | } elseif ( array_search( $string, self::$m_monthsshort ) !== false ) { |
|
393 | $monthname = $string; |
||
394 | return true; |
||
395 | } else { |
||
396 | 3 | return false; |
|
397 | } |
||
398 | } |
||
399 | |||
400 | /** |
||
401 | * Validate and interpret the date components as retrieved when parsing |
||
402 | * a user input. The method takes care of guessing how a list of values |
||
403 | * such as "10 12 13" is to be interpreted using the current language |
||
404 | * settings. The result is stored in the call-by-ref parameter |
||
405 | * $date that uses keys 'y', 'm', 'd' and contains the respective |
||
406 | * numbers as values, or false if not specified. If errors occur, error |
||
407 | * messages are added to the objects list of errors, and false is |
||
408 | * returned. Otherwise, true is returned. |
||
409 | * @param $datecomponents array of strings that might belong to the specification of a date |
||
410 | * @param $date array set to result |
||
411 | * @return boolean stating if successful |
||
412 | */ |
||
413 | 35 | protected function interpretDateComponents( $datecomponents, &$date ) { |
|
414 | 35 | global $smwgContLang; |
|
415 | // The following code segment creates a bit vector to encode |
||
416 | // which role each digit of the entered date can take (day, |
||
417 | // year, month). The vector starts with 1 and contains three |
||
418 | // bits per date component, set ot true whenever this component |
||
419 | // could be a month, a day, or a year (this is the order). |
||
420 | // Examples: |
||
421 | // 100 component could only be a month |
||
422 | // 010 component could only be a day |
||
423 | // 001 component could only be a year |
||
424 | // 011 component could be a day or a year but no month etc. |
||
425 | // For three components, we thus get a 10 digit bit vector. |
||
426 | 35 | $datevector = 1; |
|
427 | 35 | $propercomponents = array(); |
|
428 | 35 | $justfounddash = true; // avoid two dashes in a row, or dashes at the end |
|
429 | 35 | $error = false; |
|
430 | 35 | $numvalue = 0; |
|
431 | 35 | foreach ( $datecomponents as $component ) { |
|
432 | 34 | if ( $component == "-" ) { |
|
433 | 8 | if ( $justfounddash ) { |
|
434 | 1 | $error = true; |
|
435 | 1 | break; |
|
436 | } |
||
437 | 7 | $justfounddash = true; |
|
438 | } else { |
||
439 | 34 | $justfounddash = false; |
|
440 | 34 | $datevector = ( $datevector << 3 ) | $this->checkDateComponent( $component, $numvalue ); |
|
441 | 34 | $propercomponents[] = $numvalue; |
|
442 | } |
||
443 | } |
||
444 | |||
445 | 35 | if ( ( $error ) || ( $justfounddash ) || ( count( $propercomponents ) == 0 ) || ( count( $propercomponents ) > 3 ) ) { |
|
446 | |||
447 | 3 | $msgKey = 'smw-datavalue-time-invalid-date-components'; |
|
448 | |||
449 | 3 | if ( $justfounddash ) { |
|
450 | 3 | $msgKey .= '-dash'; |
|
451 | } elseif ( count( $propercomponents ) == 0 ) { |
||
452 | $msgKey .= '-empty'; |
||
453 | } elseif ( count( $propercomponents ) > 3 ) { |
||
454 | $msgKey .= '-three'; |
||
455 | } else{ |
||
456 | $msgKey .= '-common'; |
||
457 | } |
||
458 | |||
459 | 3 | $this->addErrorMsg( array( $msgKey, $this->m_wikivalue ) ); |
|
460 | 3 | return false; |
|
461 | } |
||
462 | |||
463 | // Now use the bitvector to find the preferred interpretation of the date components: |
||
464 | 34 | $dateformats = $smwgContLang->getDateFormats(); |
|
465 | 34 | $date = array( 'y' => false, 'm' => false, 'd' => false ); |
|
466 | 34 | foreach ( $dateformats[count( $propercomponents ) - 1] as $formatvector ) { |
|
467 | 34 | if ( !( ~$datevector & $formatvector ) ) { // check if $formatvector => $datevector ("the input supports the format") |
|
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
50% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them.
Loading history...
|
|||
468 | 34 | $i = 0; |
|
469 | 34 | foreach ( self::$m_formats[$formatvector] as $fieldname ) { |
|
470 | 34 | $date[$fieldname] = $propercomponents[$i]; |
|
471 | 34 | $i += 1; |
|
472 | } |
||
473 | 34 | break; |
|
474 | } |
||
475 | } |
||
476 | 34 | if ( $date['y'] === false ) { // no band matches the entered date |
|
477 | $this->addErrorMsg( array( 'smw-datavalue-time-invalid-date-components-sequence', $this->m_wikivalue ) ); |
||
478 | return false; |
||
479 | } |
||
480 | 34 | return true; |
|
481 | } |
||
482 | |||
483 | /** |
||
484 | * Initialise data from the provided intermediate results after |
||
485 | * parsing, assuming that a conventional date notation is used. |
||
486 | * If errors occur, error messages are added to the objects list of |
||
487 | * errors, and false is returned. Otherwise, true is returned. |
||
488 | * @param $datecomponents array of strings that might belong to the specification of a date |
||
489 | * @param $calendarmodesl string if model was set in input, otherwise false |
||
490 | * @param $era string '+' or '-' if provided, otherwise false |
||
491 | * @param $hours integer value between 0 and 24 |
||
492 | * @param $minutes integer value between 0 and 59 |
||
493 | * @param $seconds integer value between 0 and 59, or false if not given |
||
494 | * @param $timeoffset double value for time offset (e.g. 3.5), or false if not given |
||
495 | * @return boolean stating if successful |
||
496 | */ |
||
497 | 35 | protected function setDateFromParsedValues( $datecomponents, $calendarmodel, $era, $hours, $minutes, $seconds, $microseconds, $timeoffset, $timezone ) { |
|
498 | 35 | $date = false; |
|
499 | 35 | if ( !$this->interpretDateComponents( $datecomponents, $date ) ) { |
|
500 | 3 | return false; |
|
501 | } |
||
502 | |||
503 | // Handle BC: the year is negative. |
||
504 | 34 | if ( ( $era == '-' ) && ( $date['y'] > 0 ) ) { // see class documentation on BC, "year 0", and ISO conformance ... |
|
505 | 4 | $date['y'] = -( $date['y'] ); |
|
506 | } |
||
507 | |||
508 | // Keep information about the era |
||
509 | 34 | if ( ( $era == '+' ) && ( $date['y'] > 0 ) ) { |
|
510 | 1 | $date['y'] = $era . $date['y']; |
|
511 | } |
||
512 | |||
513 | // Old Style is a special case of Julian calendar model where the change of the year was 25 March: |
||
514 | 34 | if ( ( $calendarmodel == 'OS' ) && |
|
515 | 34 | ( ( $date['m'] < 3 ) || ( ( $date['m'] == 3 ) && ( $date['d'] < 25 ) ) ) ) { |
|
516 | $date['y']++; |
||
517 | } |
||
518 | |||
519 | 34 | $calmod = $this->getCalendarModel( $calendarmodel, $date['y'], $date['m'], $date['d'] ); |
|
520 | try { |
||
521 | 34 | $this->m_dataitem = new SMWDITime( $calmod, $date['y'], $date['m'], $date['d'], $hours, $minutes, $seconds . '.' . $microseconds, $timezone ); |
|
522 | } catch ( SMWDataItemException $e ) { |
||
523 | $this->addErrorMsg( array( 'smw-datavalue-time-invalid', $this->m_wikivalue, $e->getMessage() ) ); |
||
524 | return false; |
||
525 | } |
||
526 | |||
527 | // Having more than years or specifying a calendar model does |
||
528 | // not make sense for prehistoric dates, and our calendar |
||
529 | // conversion would not be reliable if JD numbers get too huge: |
||
530 | 34 | if ( ( $date['y'] <= self::PREHISTORY ) && |
|
531 | 34 | ( ( $this->m_dataitem->getPrecision() > SMWDITime::PREC_Y ) || ( $calendarmodel !== false ) ) ) { |
|
532 | $this->addErrorMsg( array( 'smw-datavalue-time-invalid-prehistoric', $this->m_wikivalue ) ); |
||
533 | return false; |
||
534 | } |
||
535 | 34 | if ( $timeoffset != 0 ) { |
|
536 | 3 | $newjd = $this->m_dataitem->getJD() - $timeoffset / 24; |
|
537 | try { |
||
538 | 3 | $this->m_dataitem = SMWDITime::newFromJD( $newjd, $calmod, $this->m_dataitem->getPrecision(), $timezone ); |
|
539 | } catch ( SMWDataItemException $e ) { |
||
540 | $this->addErrorMsg( array( 'smw-datavalue-time-invalid-jd', $this->m_wikivalue, $e->getMessage() ) ); |
||
541 | return false; |
||
542 | } |
||
543 | } |
||
544 | 34 | return true; |
|
545 | } |
||
546 | |||
547 | /** |
||
548 | * Check which roles a string component might play in a date, and |
||
549 | * set the call-by-ref parameter to the proper numerical |
||
550 | * representation. The component string has already been normalized to |
||
551 | * be either a plain number, a month name, or a plain number with "d" |
||
552 | * pre-pended. The result is a bit vector to indicate the possible |
||
553 | * interpretations. |
||
554 | * @param $component string |
||
555 | * @param $numvalue integer representing the components value |
||
556 | * @return integer that encodes a three-digit bit vector |
||
557 | */ |
||
558 | 34 | protected static function checkDateComponent( $component, &$numvalue ) { |
|
559 | 34 | if ( $component === '' ) { // should not happen |
|
560 | $numvalue = 0; |
||
561 | return 0; |
||
562 | 34 | } elseif ( is_numeric( $component ) ) { |
|
563 | 34 | $numvalue = intval( $component ); |
|
564 | 34 | if ( ( $numvalue >= 1 ) && ( $numvalue <= 12 ) ) { |
|
565 | 29 | return SMW_DAY_MONTH_YEAR; // can be a month, day or year |
|
566 | 34 | } elseif ( ( $numvalue >= 1 ) && ( $numvalue <= 31 ) ) { |
|
567 | 19 | return SMW_DAY_YEAR; // can be day or year |
|
568 | } else { // number can just be a year |
||
569 | 34 | return SMW_YEAR; |
|
570 | } |
||
571 | 31 | } elseif ( $component { 0 } == 'd' ) { // already marked as day |
|
572 | if ( is_numeric( substr( $component, 1 ) ) ) { |
||
573 | $numvalue = intval( substr( $component, 1 ) ); |
||
574 | return ( ( $numvalue >= 1 ) && ( $numvalue <= 31 ) ) ? SMW_DAY : 0; |
||
575 | } else { |
||
576 | return 0; |
||
577 | } |
||
578 | } else { |
||
579 | 31 | $monthnum = array_search( $component, self::$m_monthsshort ); |
|
580 | 31 | if ( $monthnum !== false ) { |
|
581 | 31 | $numvalue = $monthnum + 1; |
|
582 | 31 | return SMW_MONTH; |
|
583 | } else { |
||
584 | return 0; |
||
585 | } |
||
586 | } |
||
587 | } |
||
588 | |||
589 | /** |
||
590 | * Determine the calender model under which an input should be |
||
591 | * interpreted based on the given input data. |
||
592 | * @param $presetmodel mixed string related to a user input calendar model (OS, Jl, Gr) or false |
||
593 | * @param $year integer of the given year (adjusted for BC(E), i.e. possibly negative) |
||
594 | * @param $month mixed integer of the month or false |
||
595 | * @param $day mixed integer of the day or false |
||
596 | * @return integer either SMWDITime::CM_GREGORIAN or SMWDITime::CM_JULIAN |
||
597 | */ |
||
598 | 41 | protected function getCalendarModel( $presetmodel, $year, $month, $day ) { |
|
599 | 41 | if ( $presetmodel == 'OS' ) { // Old Style is a notational convention of Julian dates only |
|
600 | $presetmodel = 'Jl'; |
||
601 | } |
||
602 | 41 | if ( $presetmodel === 'Gr' || $presetmodel === 'GR' ) { |
|
603 | 3 | return SMWDITime::CM_GREGORIAN; |
|
604 | 41 | } elseif ( $presetmodel === 'Jl' || $presetmodel === 'JL' ) { |
|
605 | 3 | return SMWDITime::CM_JULIAN; |
|
606 | } |
||
607 | 40 | if ( ( $year > 1582 ) || |
|
608 | 12 | ( ( $year == 1582 ) && ( $month > 10 ) ) || |
|
609 | 40 | ( ( $year == 1582 ) && ( $month == 10 ) && ( $day > 4 ) ) ) { |
|
610 | 40 | return SMWDITime::CM_GREGORIAN; |
|
611 | 12 | } elseif ( $year > self::PREHISTORY ) { |
|
612 | 12 | return SMWDITime::CM_JULIAN; |
|
613 | } else { |
||
614 | // proleptic Julian years at some point deviate from the count of complete revolutions of the earth around the sun |
||
615 | // hence assume that earlier date years are Gregorian (where this effect is very weak only) |
||
616 | // This is mostly for internal use since we will not allow users to specify calendar models at this scale |
||
617 | 3 | return SMWDITime::CM_GREGORIAN; |
|
618 | } |
||
619 | } |
||
620 | |||
621 | /** |
||
622 | * @see SMWDataValue::loadDataItem |
||
623 | * |
||
624 | * {@inheritDoc} |
||
625 | */ |
||
626 | 58 | protected function loadDataItem( SMWDataItem $dataItem ) { |
|
627 | |||
628 | 58 | if ( $dataItem->getDIType() !== SMWDataItem::TYPE_TIME ) { |
|
629 | return false; |
||
630 | } |
||
631 | |||
632 | 58 | $this->m_dataitem = $dataItem; |
|
633 | 58 | $this->m_caption = false; |
|
634 | 58 | $this->m_wikivalue = false; |
|
635 | |||
636 | 58 | return true; |
|
637 | } |
||
638 | |||
639 | /** |
||
640 | * @see SMWDataValue::getShortWikiText |
||
641 | * |
||
642 | * {@inheritDoc} |
||
643 | */ |
||
644 | 31 | public function getShortWikiText( $linker = null ) { |
|
645 | 31 | return $this->getDataValueFormatter()->format( DataValueFormatter::WIKI_SHORT, $linker ); |
|
646 | } |
||
647 | |||
648 | /** |
||
649 | * @see SMWDataValue::getShortHTMLText |
||
650 | * |
||
651 | * {@inheritDoc} |
||
652 | */ |
||
653 | public function getShortHTMLText( $linker = null ) { |
||
654 | return $this->getDataValueFormatter()->format( DataValueFormatter::HTML_SHORT, $linker ); |
||
655 | } |
||
656 | |||
657 | /** |
||
658 | * @see SMWDataValue::getLongWikiText |
||
659 | * |
||
660 | * {@inheritDoc} |
||
661 | */ |
||
662 | 13 | public function getLongWikiText( $linker = null ) { |
|
663 | 13 | return $this->getDataValueFormatter()->format( DataValueFormatter::WIKI_LONG, $linker ); |
|
664 | } |
||
665 | |||
666 | /** |
||
667 | * @see SMWDataValue::getLongHTMLText |
||
668 | * |
||
669 | * {@inheritDoc} |
||
670 | */ |
||
671 | 3 | public function getLongHTMLText( $linker = null ) { |
|
672 | 3 | return $this->getDataValueFormatter()->format( DataValueFormatter::HTML_LONG, $linker ); |
|
673 | } |
||
674 | |||
675 | /** |
||
676 | * @todo The preferred caption may not be suitable as a wiki value (i.e. not parsable). |
||
677 | * @see SMWDataValue::getLongHTMLText |
||
678 | * |
||
679 | * {@inheritDoc} |
||
680 | */ |
||
681 | 10 | public function getWikiValue() { |
|
682 | 10 | return $this->m_wikivalue ? $this->m_wikivalue : strip_tags( $this->getLongWikiText() ); |
|
683 | } |
||
684 | |||
685 | /** |
||
686 | * @see SMWDataValue::isNumeric |
||
687 | * |
||
688 | * {@inheritDoc} |
||
689 | */ |
||
690 | public function isNumeric() { |
||
691 | return true; |
||
692 | } |
||
693 | |||
694 | /** |
||
695 | * Return the year number in the given calendar model, or false if |
||
696 | * this number is not available (typically when attempting to get |
||
697 | * prehistoric Julian calendar dates). As everywhere in this class, |
||
698 | * there is no year 0. |
||
699 | * @param $calendarmodel integer either SMWDITime::CM_GREGORIAN or SMWDITime::CM_JULIAN |
||
700 | * @return mixed typically a number but possibly false |
||
701 | */ |
||
702 | 1 | public function getYear( $calendarmodel = SMWDITime::CM_GREGORIAN ) { |
|
703 | 1 | $di = $this->getDataItemForCalendarModel( $calendarmodel ); |
|
704 | 1 | if ( !is_null( $di ) ) { |
|
705 | 1 | return $di->getYear(); |
|
706 | } else { |
||
707 | return false; |
||
708 | } |
||
709 | } |
||
710 | |||
711 | /** |
||
712 | * Return the month number in the given calendar model, or false if |
||
713 | * this number is not available (typically when attempting to get |
||
714 | * prehistoric Julian calendar dates). |
||
715 | * @param $calendarmodel integer either SMWDITime::CM_GREGORIAN or SMWDITime::CM_JULIAN |
||
716 | * @param $default value to return if month is not set at our level of precision |
||
717 | * @return mixed typically a number but possibly anything given as $default |
||
718 | */ |
||
719 | 1 | public function getMonth( $calendarmodel = SMWDITime::CM_GREGORIAN, $default = 1 ) { |
|
720 | 1 | $di = $this->getDataItemForCalendarModel( $calendarmodel ); |
|
721 | 1 | if ( !is_null( $di ) ) { |
|
722 | 1 | return ( $di->getPrecision() >= SMWDITime::PREC_YM ) ? $di->getMonth() : $default; |
|
723 | } else { |
||
724 | return false; |
||
725 | } |
||
726 | } |
||
727 | |||
728 | /** |
||
729 | * Return the day number in the given calendar model, or false if this |
||
730 | * number is not available (typically when attempting to get |
||
731 | * prehistoric Julian calendar dates). |
||
732 | * @param $calendarmodel integer either SMWDITime::CM_GREGORIAN or SMWDITime::CM_JULIAN |
||
733 | * @param $default value to return if day is not set at our level of precision |
||
734 | * @return mixed typically a number but possibly anything given as $default |
||
735 | */ |
||
736 | 1 | public function getDay( $calendarmodel = SMWDITime::CM_GREGORIAN, $default = 1 ) { |
|
737 | 1 | $di = $this->getDataItemForCalendarModel( $calendarmodel ); |
|
738 | 1 | if ( !is_null( $di ) ) { |
|
739 | 1 | return ( $di->getPrecision() >= SMWDITime::PREC_YMD ) ? $di->getDay() : $default; |
|
740 | } else { |
||
741 | return false; |
||
742 | } |
||
743 | } |
||
744 | |||
745 | /** |
||
746 | * @see TimeValueFormatter::getTimeStringFromDataItem |
||
747 | * |
||
748 | * @return |
||
749 | */ |
||
750 | 1 | public function getTimeString( $default = '00:00:00' ) { |
|
751 | 1 | return $this->getDataValueFormatter()->getTimeString( $default ); |
|
752 | } |
||
753 | |||
754 | /** |
||
755 | * @deprecated This method is now called getISO8601Date(). It will vanish before SMW 1.7. |
||
756 | */ |
||
757 | public function getXMLSchemaDate( $mindefault = true ) { |
||
758 | return $this->getISO8601Date( $mindefault ); |
||
759 | } |
||
760 | |||
761 | /** |
||
762 | * @see TimeValueFormatter::getISO8601DateFromDataItem |
||
763 | * |
||
764 | * @param $mindefault boolean determining whether values below the |
||
765 | * precision of our input should be completed with minimal or maximal |
||
766 | * conceivable values |
||
767 | * |
||
768 | * @return string |
||
769 | */ |
||
770 | 45 | public function getISO8601Date( $mindefault = true ) { |
|
771 | 45 | return $this->getDataValueFormatter()->getISO8601Date( $mindefault ); |
|
772 | } |
||
773 | |||
774 | /** |
||
775 | * @see TimeValueFormatter::getMediaWikiDateFromDataItem |
||
776 | * |
||
777 | * @return string |
||
778 | */ |
||
779 | 1 | public function getMediaWikiDate() { |
|
780 | 1 | return $this->getDataValueFormatter()->getMediaWikiDate(); |
|
781 | } |
||
782 | |||
783 | /** |
||
784 | * Get the current data in the specified calendar model. Conversion is |
||
785 | * not done for prehistoric dates (where it might lead to precision |
||
786 | * errors and produce results that are not meaningful). In this case, |
||
787 | * null might be returned if no data in the specified format is |
||
788 | * available. |
||
789 | * @param $calendarmodel integer one of SMWDITime::CM_GREGORIAN or SMWDITime::CM_JULIAN |
||
790 | * @return SMWDITime |
||
791 | */ |
||
792 | 57 | public function getDataItemForCalendarModel( $calendarmodel ) { |
|
793 | 57 | if ( $this->m_dataitem->getYear() <= self::PREHISTORY ) { |
|
794 | 3 | return ( $this->m_dataitem->getCalendarModel() == $calendarmodel ) ? $this->m_dataitem : null; |
|
795 | 57 | } elseif ( $calendarmodel == SMWDITime::CM_GREGORIAN ) { |
|
796 | 57 | if ( is_null( $this->m_dataitem_greg ) ) { |
|
797 | 57 | $this->m_dataitem_greg = $this->m_dataitem->getForCalendarModel( SMWDITime::CM_GREGORIAN ); |
|
798 | } |
||
799 | 57 | return $this->m_dataitem_greg; |
|
800 | } else { |
||
801 | 5 | if ( is_null( $this->m_dataitem_jul ) ) { |
|
802 | 5 | $this->m_dataitem_jul = $this->m_dataitem->getForCalendarModel( SMWDITime::CM_JULIAN ); |
|
803 | } |
||
804 | 5 | return $this->m_dataitem_jul; |
|
805 | } |
||
806 | } |
||
807 | |||
808 | 42 | private function isInterpretableAsYearOnly( $value ) { |
|
809 | 42 | return strpos( $value, ' ' ) === false && is_numeric( strval( $value ) ) && ( strval( $value ) < 0 || strlen( $value ) < 6 ); |
|
810 | } |
||
811 | |||
812 | 35 | private function isInterpretableAsTimestamp( $value ) { |
|
813 | // 1200-11-02T12:03:25 or 20120320055913 |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
58% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them.
Loading history...
|
|||
814 | 35 | return ( ( strlen( $value ) > 4 && substr( $value, 10, 1 ) === 'T' ) || strlen( $value ) == 14 ) && wfTimestamp( TS_MW, $value ) !== false; |
|
815 | } |
||
816 | |||
817 | } |
||
818 |
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.