Completed
Push — master ( b51007...cd2f8d )
by mw
37:59 queued 02:53
created

SMWDITime   C

Complexity

Total Complexity 78

Size/Duplication

Total Lines 522
Duplicated Lines 0 %

Coupling/Cohesion

Components 3
Dependencies 3

Test Coverage

Coverage 88.26%
Metric Value
wmc 78
lcom 3
cbo 3
dl 0
loc 522
ccs 188
cts 213
cp 0.8826
rs 5.4563

25 Methods

Rating   Name   Duplication   Size   Complexity  
A getDIType() 0 3 1
A getCalendarModel() 0 3 1
A getHour() 0 3 1
A newFromJD() 0 3 1
F __construct() 0 45 24
A getPrecision() 0 3 1
A getEra() 0 3 1
A getYear() 0 3 1
A getMonth() 0 3 1
A getDay() 0 3 1
A getMinute() 0 3 1
A getSecond() 0 3 1
A getCalendarModelLiteral() 0 9 1
B newFromDateTime() 0 16 7
A asDateTime() 0 23 2
A newFromTimestamp() 0 17 2
A getMwTimestamp() 0 13 1
A getForCalendarModel() 0 7 2
A getSortKey() 0 8 3
A getJD() 0 8 2
B getSerialization() 0 17 5
C doUnserialize() 0 28 8
B isLeapYear() 0 9 5
A getDayNumberForMonth() 0 9 3
A equals() 0 7 2

How to fix   Complexity   

Complex Class

Complex classes like SMWDITime often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use SMWDITime, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
use SMW\DataItemException;
4
use SMW\JulianDay;
5
6
/**
7
 * This class implements time data items.
8
 * Such data items represent a unique point in time, given in either Julian or
9
 * Gregorian notation (possibly proleptic), and a precision setting that states
10
 * which of the components year, month, day, time were specified expicitly.
11
 * Even when not specified, the data item always assumes default values for the
12
 * missing parts, so the item really captures one point in time, no intervals.
13
 * Times are always assumed to be in UTC.
14
 *
15
 * "Y0K issue": Neither the Gregorian nor the Julian calendar assume a year 0,
16
 * i.e. the year 1 BC(E) was followed by 1 AD/CE. See
17
 * http://en.wikipedia.org/wiki/Year_zero
18
 * This implementation adheres to this convention and disallows year 0. The
19
 * stored year numbers use positive numbers for CE and negative numbers for
20
 * BCE. This is not just relevant for the question of how many years have
21
 * (exactly) passed since a given date, but also for the location of leap
22
 * years.
23
 *
24
 * @since 1.6
25
 *
26
 * @author Markus Krötzsch
27
 * @ingroup SMWDataItems
28
 */
29
class SMWDITime extends SMWDataItem {
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
30
31
	const CM_GREGORIAN = 1;
32
	const CM_JULIAN = 2;
33
34
	const PREC_Y    = 0;
35
	const PREC_YM   = 1;
36
	const PREC_YMD  = 2;
37
	const PREC_YMDT = 3;
38
39
	/**
40
	 * The year before which we do not accept anything but year numbers and
41
	 * largely discourage calendar models.
42
	 */
43
	const PREHISTORY = -10000;
44
45
	/**
46
	 * Maximal number of days in a given month.
47
	 * @var array
48
	 */
49
	protected static $m_daysofmonths = array( 1 => 31, 2 => 29, 3 => 31, 4 => 30, 5 => 31, 6 => 30, 7 => 31, 8 => 31, 9 => 30, 10 => 31, 11 => 30, 12 => 31 );
50
51
	/**
52
	 * Precision SMWDITime::PREC_Y, SMWDITime::PREC_YM,
53
	 * SMWDITime::PREC_YMD, or SMWDITime::PREC_YMDT.
54
	 * @var integer
55
	 */
56
	protected $m_precision;
57
	/**
58
	 * Calendar model: SMWDITime::CM_GREGORIAN or SMWDITime::CM_JULIAN.
59
	 * @var integer
60
	 */
61
	protected $m_model;
62
	/**
63
	 * Number of year, possibly negative.
64
	 * @var integer
65
	 */
66
	protected $m_year;
67
	/**
68
	 * Number of month.
69
	 * @var integer
70
	 */
71
	protected $m_month;
72
	/**
73
	 * Number of day.
74
	 * @var integer
75
	 */
76
	protected $m_day;
77
	/**
78
	 * Hours of the day.
79
	 * @var integer
80
	 */
81
	protected $m_hours;
82
	/**
83
	 * Minutes of the hour.
84
	 * @var integer
85
	 */
86
	protected $m_minutes;
87
	/**
88
	 * Seconds of the minute.
89
	 * @var integer
90
	 */
91
	protected $m_seconds;
92
93
	/**
94
	 * @var integer
95
	 */
96
	protected $timezone;
97
98
	/**
99
	 * @var integer|null
100
	 */
101
	protected $era = null;
102
103
	/**
104
	 * @var integer
105
	 */
106
	protected $julianDay = null;
107
108
	/**
109
	 * Create a time data item. All time components other than the year can
110 144
	 * be false to indicate that they are not specified. This will affect
111
	 * the internal precision setting. The missing values are initialised
112
	 * to minimal values (0 or 1) for internal calculations.
113 144
	 *
114
	 * @param $calendarmodel integer one of SMWDITime::CM_GREGORIAN or SMWDITime::CM_JULIAN
115
	 * @param $year integer number of the year (possibly negative)
116
	 * @param $month mixed integer number or false
117 144
	 * @param $day mixed integer number or false
118
	 * @param $hour mixed integer number or false
119
	 * @param $minute mixed integer number or false
120
	 * @param $second mixed integer number or false
121 144
	 * @param integer|false $timezone
122 144
	 *
123 144
	 * @todo Implement more validation here.
124 144
	 */
125 144
	public function __construct( $calendarmodel, $year, $month = false, $day = false,
126 144
	                             $hour = false, $minute = false, $second = false, $timezone = false ) {
127 144
128
		if ( ( $calendarmodel != self::CM_GREGORIAN ) && ( $calendarmodel != self::CM_JULIAN ) ) {
129 144
			throw new DataItemException( "Unsupported calendar model constant \"$calendarmodel\"." );
130
		}
131 144
132 144
		if ( $year == 0 ) {
133 144
			throw new DataItemException( "There is no year 0 in Gregorian and Julian calendars." );
134 144
		}
135
136
		$this->m_model   = $calendarmodel;
137
		$this->m_year    = intval( $year );
138 144
		$this->m_month   = $month != false ? intval( $month ) : 1;
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison !== instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
139
		$this->m_day     = $day != false ? intval( $day ) : 1;
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison !== instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
140
		$this->m_hours   = $hour !== false ? intval( $hour ) : 0;
141
		$this->m_minutes = $minute !== false ? intval( $minute ) : 0;
142 144
		$this->m_seconds = $second !== false ? floatval( $second ) : 0;
0 ignored issues
show
Documentation Bug introduced by
It seems like $second !== false ? floatval($second) : 0 can also be of type double. However, the property $m_seconds is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
143 16
144 144
		$this->timezone = $timezone !== false ? intval( $timezone ) : 0;
145 2
		$year = strval( $year );
146 139
		$this->era      = $year{0} === '+' ? 1 : ( $year{0} === '-' ? -1 : 0 );
147 21
148 21
149 138
		if ( ( $this->m_hours < 0 ) || ( $this->m_hours > 23 ) ||
150
		     ( $this->m_minutes < 0 ) || ( $this->m_minutes > 59 ) ||
151 144
		     ( $this->m_seconds < 0 ) || ( $this->m_seconds > 59 ) ||
152
		     ( $this->m_month < 1 ) || ( $this->m_month > 12 ) ) {
153 146
			throw new DataItemException( "Part of the date is out of bounds." );
154 146
		}
155
156
		if ( $this->m_day > self::getDayNumberForMonth( $this->m_month, $this->m_year, $this->m_model ) ) {
157 20
			throw new DataItemException( "Month {$this->m_month} in year {$this->m_year} did not have {$this->m_day} days in this calendar model." );
158 20
		}
159
160
		if ( $month === false ) {
161 43
			$this->m_precision = self::PREC_Y;
162 43
		} elseif ( $day === false ) {
163
			$this->m_precision = self::PREC_YM;
164
		} elseif ( $hour === false ) {
165 43
			$this->m_precision = self::PREC_YMD;
166 43
		} else {
167
			$this->m_precision = self::PREC_YMDT;
168
		}
169 43
	}
170 43
171
	/**
172
	 * @since 1.6
173 43
	 *
174 43
	 * @return integer
175
	 */
176
	public function getDIType() {
177 41
		return SMWDataItem::TYPE_TIME;
178 41
	}
179
180
	/**
181 41
	 * @since 1.6
182 41
	 *
183
	 * @return integer
184
	 */
185 41
	public function getCalendarModel() {
186 41
		return $this->m_model;
187
	}
188
189
	/**
190
	 * @since 1.6
191
	 *
192
	 * @return integer
193
	 */
194 1
	public function getPrecision() {
195
		return $this->m_precision;
196
	}
197 1
198 1
	/**
199 1
	 * Indicates whether a user explicitly used an era marker even for a positive
200
	 * year.
201 1
	 *
202
	 * - [-1] indicates BC(E)
203
	 * - [0]/null indicates no era marker
204
	 * - [1] indicates AD/CE was used
205
	 *
206
	 * @since 2.4
207
	 *
208
	 * @return integer
209
	 */
210
	public function getEra() {
211
		return $this->era;
212
	}
213
214
	/**
215
	 * @since 1.6
216
	 *
217
	 * @return integer
218
	 */
219
	public function getYear() {
220
		return $this->m_year;
221
	}
222
223
	/**
224
	 * @since 1.6
225
	 *
226
	 * @return integer
227
	 */
228
	public function getMonth() {
229
		return $this->m_month;
230
	}
231
232
	/**
233 1
	 * @since 1.6
234
	 *
235 1
	 * @return integer
236
	 */
237
	public function getDay() {
238
		return $this->m_day;
239 1
	}
240
241
	/**
242
	 * @since 1.6
243
	 *
244
	 * @return integer
245 1
	 */
246
	public function getHour() {
247 1
		return $this->m_hours;
248 1
	}
249 1
250 1
	/**
251 1
	 * @since 1.6
252 1
	 *
253
	 * @return integer
254 1
	 */
255
	public function getMinute() {
256
		return $this->m_minutes;
257
	}
258
259
	/**
260
	 * @since 1.6
261
	 *
262
	 * @return integer
263
	 */
264
	public function getSecond() {
265
		return $this->m_seconds;
266 136
	}
267 136
268
	/**
269 136
	 * @since 2.4
270
	 *
271
	 * @return string
272
	 */
273 136
	public function getCalendarModelLiteral() {
274 136
275 136
		$literal = array(
276 136
			self::CM_GREGORIAN => '',
277 136
			self::CM_JULIAN    => 'JL'
278 136
		);
279 136
280 136
		return $literal[$this->m_model];
281 136
	}
282
283
	/**
284
	 * @since 2.4
285
	 *
286
	 * @param DateTime $dateTime
287
	 *
288
	 * @return SMWDITime|false
289
	 */
290
	public static function newFromDateTime( DateTime $dateTime ) {
291
292
		$calendarModel = self::CM_JULIAN;
293 135
294 135
		$year = $dateTime->format( 'Y' );
295 135
		$month = $dateTime->format( 'm' );
296 135
		$day = $dateTime->format( 'd' );
297 135
298 135
		if ( ( $year > 1582 ) ||
299 135
			( ( $year == 1582 ) && ( $month > 10 ) ) ||
300 135
			( ( $year == 1582 ) && ( $month == 10 ) && ( $day > 4 ) ) ) {
301 135
			$calendarModel = self::CM_GREGORIAN;
302 135
		}
303 135
304 135
		return self::doUnserialize( $calendarModel . '/' . $dateTime->format( 'Y/m/d/H/i/s.u' ) );
305
	}
306
307
	/**
308
	 * @since 2.4
309
	 *
310
	 * @return DateTime
311
	 */
312
	public function asDateTime() {
313
314
		$year = str_pad( $this->m_year , 4, '0', STR_PAD_LEFT );
315
316
		// Avoid "Failed to parse time string (-900-02-02 00:00:00) at
317 41
		// position 7 (-): Double timezone specification"
318 41
		if ( $this->m_year < 0 ) {
319 41
			$year = '-' . str_pad( $this->m_year * -1 , 4, '0', STR_PAD_LEFT );
320
		}
321 3
322
		// Avoid "Failed to parse time string (1300-11-02 12:03:25.888499949) at
323
		// at position 11 (1): The timezone could not ..."
324
		$seconds = number_format( str_pad( $this->m_seconds, 2, '0', STR_PAD_LEFT ), 7, '.', '' );
325
326
		$time = $year . '-' .
327
			str_pad( $this->m_month, 2, '0', STR_PAD_LEFT )     . '-' .
328
			str_pad( $this->m_day, 2, '0', STR_PAD_LEFT )       . ' ' .
329
			str_pad( $this->m_hours, 2, '0', STR_PAD_LEFT )     . ':' .
330
			str_pad( $this->m_minutes, 2, '0', STR_PAD_LEFT )   . ':' .
331
			$seconds;
332
333
		return new DateTime( $time );
334 142
	}
335 142
336 142
	/**
337 142
	 * Creates and returns a new instance of SMWDITime from a MW timestamp.
338
	 *
339 3
	 * @since 1.8
340
	 *
341
	 * @param string $timestamp must be in format
342
	 *
343 145
	 * @return SMWDITime|false
344 145
	 */
345 145
	public static function newFromTimestamp( $timestamp ) {
346
		$timestamp = wfTimestamp( TS_MW, (string)$timestamp );
347
348 144
		if ( $timestamp === false ) {
349 144
			return false;
350
		}
351 144
352 139
		return new self(
353 139
			self::CM_GREGORIAN,
354
			substr( $timestamp, 0, 4 ),
355 144
			substr( $timestamp, 4, 2 ),
0 ignored issues
show
Documentation introduced by
substr($timestamp, 4, 2) is of type string, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
356 139
			substr( $timestamp, 6, 2 ),
0 ignored issues
show
Documentation introduced by
substr($timestamp, 6, 2) is of type string, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
357 139
			substr( $timestamp, 8, 2 ),
0 ignored issues
show
Documentation introduced by
substr($timestamp, 8, 2) is of type string, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
358
			substr( $timestamp, 10, 2 ),
0 ignored issues
show
Documentation introduced by
substr($timestamp, 10, 2) is of type string, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
359 144
			substr( $timestamp, 12, 2 )
0 ignored issues
show
Documentation introduced by
substr($timestamp, 12, 2) is of type string, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
360 138
		);
361 138
	}
362
363 144
	/**
364
	 * Returns a MW timestamp representation of the value.
365
	 *
366
	 * @since 1.6.2
367
	 *
368
	 * @param $outputtype
369
	 *
370
	 * @return mixed
371 16
	 */
372 16
	public function getMwTimestamp( $outputtype = TS_UNIX ) {
373 16
		return wfTimestamp(
374
			$outputtype,
375 16
			implode( '', array(
376 16
				str_pad( $this->m_year, 4, '0', STR_PAD_LEFT ),
377
				str_pad( $this->m_month, 2, '0', STR_PAD_LEFT ),
378 16
				str_pad( $this->m_day, 2, '0', STR_PAD_LEFT ),
379
				str_pad( $this->m_hours, 2, '0', STR_PAD_LEFT ),
380
				str_pad( $this->m_minutes, 2, '0', STR_PAD_LEFT ),
381
				str_pad( $this->m_seconds, 2, '0', STR_PAD_LEFT ),
382 16
			) )
383 16
		);
384 5
	}
385
386 16
	/**
387
	 * Get the data in the specified calendar model. This might require
388 16
	 * conversion.
389
	 * @note Conversion can be unreliable for very large absolute year
390
	 * numbers when the internal calculations hit floating point accuracy.
391
	 * Callers might want to avoid this (calendar models make little sense
392 16
	 * in such cases anyway).
393
	 * @param $calendarmodel integer one of SMWDITime::CM_GREGORIAN or SMWDITime::CM_JULIAN
394
	 * @return SMWDITime
395
	 */
396
	public function getForCalendarModel( $calendarmodel ) {
397
		if ( $calendarmodel == $this->m_model ) {
398
			return $this;
399
		} else {
400
			return self::newFromJD( $this->getJD(), $calendarmodel, $this->m_precision );
401
		}
402
	}
403 6
404 6
	/**
405 6
	 * Return a number that helps comparing time data items. For
406
	 * dates in the Julian Day era (roughly from 4713 BCE onwards), we use
407
	 * the Julian Day number. For earlier dates, the (negative) year number
408
	 * with a fraction for the date is used (times are ignored). This
409
	 * avoids calculation errors that would occur for very ancient dates
410
	 * if the JD number was used there.
411 6
	 * @return double sortkey
412 6
	 */
413 6
	public function getSortKey() {
414 2
		$jd = ( $this->m_year >= -4713 ) ? $jd = $this->getJD() : -1;
415
		if ( $jd > 0 ) {
416 6
			return $jd;
417
		} else {
418
			return $this->m_year - 1 + ( $this->m_month - 1 ) / 12 + ( $this->m_day - 1 ) / 12 / 31;
419
		}
420
	}
421
422
	/**
423
	 * @since 1.6
424
	 *
425
	 * @return double
426
	 */
427
	public function getJD() {
428
429 145
		if ( $this->julianDay === null ) {
430 145
			$this->julianDay = JulianDay::get( $this );
0 ignored issues
show
Documentation Bug introduced by
The property $julianDay was declared of type integer, but \SMW\JulianDay::get($this) is of type double. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
431 145
		}
432 145
433 145
		return $this->julianDay;
434 145
	}
435 145
436
	/**
437 6
	 * @since 1.6
438 6
	 *
439 6
	 * @return string
440
	 */
441
	public function getSerialization() {
442
		$result = strval( $this->m_model ) . '/' . ( $this->era > 0 ? '+' : '' ) . strval( $this->m_year );
443
444
		if ( $this->m_precision >= self::PREC_YM ) {
445
			$result .= '/' . strval( $this->m_month );
446
		}
447
448
		if ( $this->m_precision >= self::PREC_YMD ) {
449
			$result .= '/' . strval( $this->m_day );
450
		}
451 145
452 145
		if ( $this->m_precision >= self::PREC_YMDT ) {
453
			$result .= '/' . strval( $this->m_hours ) . '/' . strval( $this->m_minutes ) . '/' . strval( $this->m_seconds ) . '/' . strval( $this->timezone );
454
		}
455
456
		return $result;
457
	}
458
459
	/**
460
	 * Create a data item from the provided serialization string.
461
	 *
462
	 * @return SMWDITime
463
	 */
464
	public static function doUnserialize( $serialization ) {
465 6
		$parts = explode( '/', $serialization, 8 );
466 6
		$values = array();
467 6
468 6
		for ( $i = 0; $i < 8; $i += 1 ) {
469 6
			if ( $i < count( $parts ) ) {
470 6
471 6
				if ( !is_numeric( $parts[$i] ) ) {
472 6
					throw new DataItemException( "Unserialization failed: the string \"$serialization\" is no valid datetime specification." );
473 6
				}
474 6
475 6
				$values[$i] = $i == 6 ? floatval( $parts[$i] ) : intval( $parts[$i] );
476 6
477 6
				// Find out whether the input contained an explicit AD/CE era marker
478 6
				if ( $i == 1 ) {
479 6
					$values[$i] = ( $parts[1]{0} === '+' ? '+' : '' ) . $values[$i];
480
				}
481 6
			} else {
482 6
				$values[$i] = false;
483 6
			}
484 6
		}
485 2
486 2
		if ( count( $parts ) <= 1 ) {
487 2
			throw new DataItemException( "Unserialization failed: the string \"$serialization\" is no valid URI." );
488 2
		}
489
490 2
		return new self( $values[0], $values[1], $values[2], $values[3], $values[4], $values[5], $values[6], $values[7] );
491 2
	}
492 2
493
	/**
494 6
	 * Create a new time data item from the specified Julian Day number,
495 6
	 * calendar model, presicion, and type ID.
496
	 *
497
	 * @param $jdvalue double Julian Day number
498
	 * @param $calendarmodel integer either SMWDITime::CM_GREGORIAN or SMWDITime::CM_JULIAN
499
	 * @param $precision integer one of SMWDITime::PREC_Y, SMWDITime::PREC_YM, SMWDITime::PREC_YMD, SMWDITime::PREC_YMDT
500
	 *
501
	 * @return SMWDITime object
502
	 */
503
	public static function newFromJD( $jdvalue, $calendarmodel, $precision ) {
504 6
		return JulianDay::newDiFromJD( $jdvalue, $calendarmodel, $precision );
505 6
	}
506 6
507 6
	/**
508 6
	 * Find out whether the given year number is a leap year.
509 6
	 * This calculation assumes that neither calendar has a year 0.
510 6
	 * @param $year integer year number
511 6
	 * @param $calendarmodel integer either SMWDITime::CM_GREGORIAN or SMWDITime::CM_JULIAN
512 6
	 * @return boolean
513
	 */
514
	static public function isLeapYear( $year, $calendarmodel ) {
0 ignored issues
show
Coding Style introduced by
As per PSR2, the static declaration should come after the visibility declaration.
Loading history...
515
		$astroyear = ( $year < 1 ) ? ( $year + 1 ) : $year;
516
		if ( $calendarmodel == self::CM_JULIAN ) {
517
			return ( $astroyear % 4 ) == 0;
518
		} else {
519
			return ( ( $astroyear % 400 ) == 0 ) ||
520
			       ( ( ( $astroyear % 4 ) == 0 ) && ( ( $astroyear % 100 ) != 0 ) );
521
		}
522 137
	}
523 137
524 137
	/**
525 3
	 * Find out how many days the given month had in the given year
526
	 * based on the specified calendar model.
527 137
	 * This calculation assumes that neither calendar has a year 0.
528 137
	 * @param $month integer month number
529
	 * @param $year integer year number
530
	 * @param $calendarmodel integer either SMWDITime::CM_GREGORIAN or SMWDITime::CM_JULIAN
531
	 * @return boolean
532
	 */
533
	static public function getDayNumberForMonth( $month, $year, $calendarmodel ) {
0 ignored issues
show
Coding Style introduced by
As per PSR2, the static declaration should come after the visibility declaration.
Loading history...
534
		if ( $month !== 2 ) {
535
			return self::$m_daysofmonths[$month];
536
		} elseif ( self::isLeapYear( $year, $calendarmodel ) ) {
537
			return 29;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return 29; (integer) is incompatible with the return type documented by SMWDITime::getDayNumberForMonth of type boolean.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
538
		} else {
539
			return 28;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return 28; (integer) is incompatible with the return type documented by SMWDITime::getDayNumberForMonth of type boolean.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
540
		}
541 144
	}
542 144
543 34
	public function equals( SMWDataItem $di ) {
544 137
		if ( $di->getDIType() !== SMWDataItem::TYPE_TIME ) {
545 135
			return false;
546
		}
547 3
548
		return $di->getSortKey() === $this->getSortKey();
549
	}
550
}
551