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

JulianDay::JD2Date()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 37
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 37
rs 8.439
c 1
b 0
f 0
cc 6
eloc 30
nc 5
nop 2
1
<?php
2
3
namespace SMW;
4
5
use SMWDITime as DITime;
6
use RuntimeException;
7
8
/**
9
 * Julian dates (abbreviated JD) are a continuous count of days and fractions
10
 * since noon Universal Time on January 1, 4713 BCE (on the Julian calendar).
11
 *
12
 * It is assumed that the changeover from the Julian calendar to the Gregorian
13
 * calendar occurred in October of 1582.
14
 *
15
 * For dates on or before 4 October 1582, the Julian calendar is used; for dates
16
 * on or after 15 October 1582, the Gregorian calendar is used.
17
 *
18
 * @license GNU GPL v2+
19
 * @since 2.4
20
 *
21
 * @author Markus Krötzsch
22
 */
23
class JulianDay {
24
25
	/**
26
	 * Moment of switchover to Gregorian calendar.
27
	 */
28
	const J1582 = 2299160.5;
29
30
	/**
31
	 * Offset of Julian Days for Modified JD inputs.
32
	 */
33
	const MJD = 2400000.5;
34
35
	/**
36
	 * Create a new time dataItem from a specified Julian Day number,
37
	 * calendar model, presicion.
38
	 *
39
	 * @param double $jdValue
40
	 * @param integer|null $calendarmodel
0 ignored issues
show
Documentation introduced by
There is no parameter named $calendarmodel. Did you maybe mean $calendarModel?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
41
	 * @param integer|null $precision
42
	 *
43
	 * @return DITime object
44
	 */
45
	public static function newDiFromJD( $jdValue, $calendarModel = null, $precision = null ) {
46
47
		if ( $calendarModel === null ) { // 1582/10/15
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...
48
			$calendarModel = $jdValue < self::J1582 ? DITime::CM_JULIAN : DITime::CM_GREGORIAN;
49
		}
50
51
		if ( $precision === null ) {
52
			$precision = strpos( strval( $jdValue ), '.5' ) !== false ? DITime::PREC_YMD : DITime::PREC_YMDT;
53
		}
54
55
		list( $year, $month, $day ) = self::JD2Date( $jdValue, $calendarModel );
56
57
		if ( $precision <= DITime::PREC_YM ) {
58
			$day = false;
59
			if ( $precision === DITime::PREC_Y ) {
60
				$month = false;
61
			}
62
		}
63
64
		if ( $precision === DITime::PREC_YMDT ) {
65
			list( $hour, $minute, $second ) = self::JD2Time( $jdValue );
66
		} else {
67
			$hour = $minute = $second = false;
68
		}
69
70
		return new DITime( $calendarModel, $year, $month, $day, $hour, $minute, $second );
0 ignored issues
show
Bug introduced by
It seems like $month defined by self::JD2Date($jdValue, $calendarModel) on line 55 can also be of type double or integer; however, SMWDITime::__construct() does only seem to accept boolean, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
Bug introduced by
It seems like $day defined by self::JD2Date($jdValue, $calendarModel) on line 55 can also be of type double; however, SMWDITime::__construct() does only seem to accept boolean, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
Bug introduced by
It seems like $hour defined by self::JD2Time($jdValue) on line 65 can also be of type double; however, SMWDITime::__construct() does only seem to accept boolean, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
Bug introduced by
It seems like $minute defined by self::JD2Time($jdValue) on line 65 can also be of type double; however, SMWDITime::__construct() does only seem to accept boolean, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
Bug introduced by
It seems like $second defined by self::JD2Time($jdValue) on line 65 can also be of type double; however, SMWDITime::__construct() does only seem to accept boolean, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
71
	}
72
73
	/**
74
	 * @since 2.4
75
	 *
76
	 * @param DITime $dataItem
77
	 *
78
	 * @return float
79
	 */
80
	public static function get( DITime $dataItem ) {
81
82
		$jdValue = self::date2JD(
83
			$dataItem->getYear(),
84
			$dataItem->getMonth(),
85
			$dataItem->getDay(),
86
			$dataItem->getCalendarModel()
87
		) + self::time2JDoffset(
88
			$dataItem->getHour(),
89
			$dataItem->getMinute(),
90
			$dataItem->getSecond()
91
		);
92
93
		// Keep microseconds to a certain degree distinguishable
94
		return floatval( number_format( $jdValue, 7, '.', '' ) );
95
	}
96
97
	/**
98
	 * The MJD has a starting point of midnight on November 17, 1858 and is
99
	 * computed by MJD = JD - 2400000.5
100
	 *
101
	 * @since 2.4
102
	 *
103
	 * @param DITime $dataItem
104
	 *
105
	 * @return float
106
	 */
107
	public static function getModifiedJulianDate( DITime $dataItem ) {
108
		return self::get( $dataItem ) - self::MJD;
109
	}
110
111
	/**
112
	 * Compute the Julian Day number from a given date in the specified
113
	 * calendar model. This calculation assumes that neither calendar
114
	 * has a year 0.
115
	 *
116
	 * @param $year integer representing the year
117
	 * @param $month integer representing the month
118
	 * @param $day integer representing the day
119
	 * @param $calendarmodel integer either SMWDITime::CM_GREGORIAN or SMWDITime::CM_JULIAN
120
	 *
121
	 * @return float Julian Day number
122
	 * @throws RuntimeException
123
	 */
124
	protected static function date2JD( $year, $month, $day, $calendarmodel ) {
125
		$astroyear = ( $year < 1 ) ? ( $year + 1 ) : $year;
126
127
		if ( $calendarmodel === DITime::CM_GREGORIAN ) {
128
			$a = intval( ( 14 - $month ) / 12 );
129
			$y = $astroyear + 4800 - $a;
130
			$m = $month + 12 * $a - 3;
131
			return $day + floor( ( 153 * $m + 2 ) / 5 ) + 365 * $y + floor( $y / 4 ) - floor( $y / 100 ) + floor( $y / 400 ) - 32045.5;
132
		} elseif ( $calendarmodel === DITime::CM_JULIAN ) {
133
			$y2 = ( $month <= 2 ) ? ( $astroyear - 1 ) : $astroyear;
134
			$m2 = ( $month <= 2 ) ? ( $month + 12 ) : $month;
135
			return floor( ( 365.25 * ( $y2 + 4716 ) ) ) + floor( ( 30.6001 * ( $m2 + 1 ) ) ) + $day - 1524.5;
136
		}
137
138
		throw new RuntimeException( "Unsupported calendar model ($calendarmodel)" );
139
	}
140
141
	/**
142
	 * Compute the offset for the Julian Day number from a given time.
143
	 * This computation is the same for all calendar models.
144
	 *
145
	 * @param $hours integer representing the hour
146
	 * @param $minutes integer representing the minutes
147
	 * @param $seconds integer representing the seconds
148
	 *
149
	 * @return float offset for a Julian Day number to get this time
150
	 */
151
	protected static function time2JDoffset( $hours, $minutes, $seconds ) {
152
		return ( $hours / 24 ) + ( $minutes / ( 60 * 24 ) ) + ( $seconds / ( 3600 * 24 ) );
153
	}
154
155
	/**
156
	 * Convert a Julian Day number to a date in the given calendar model.
157
	 * This calculation assumes that neither calendar has a year 0.
158
	 * @note The algorithm may fail for some cases, in particular since the
159
	 * conversion to Gregorian needs positive JD. If this happens, wrong
160
	 * values will be returned. Avoid date conversions before 10000 BCE.
161
	 *
162
	 * @param $jdvalue float number of Julian Days
163
	 * @param $calendarmodel integer either SMWDITime::CM_GREGORIAN or SMWDITime::CM_JULIAN
164
	 *
165
	 * @return array( yearnumber, monthnumber, daynumber )
0 ignored issues
show
Documentation introduced by
The doc-type array( could not be parsed: Expected "|" or "end of type", but got "(" at position 5. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
166
	 * @throws RuntimeException
167
	 */
168
	protected static function JD2Date( $jdvalue, $calendarmodel ) {
169
170
		if ( $calendarmodel === DITime::CM_GREGORIAN ) {
171
			$jdvalue += 2921940; // add the days of 8000 years (this algorithm only works for positive JD)
172
			$j = floor( $jdvalue + 0.5 ) + 32044;
173
			$g = floor( $j / 146097 );
174
			$dg = $j % 146097;
175
			$c = floor( ( ( floor( $dg / 36524 ) + 1 ) * 3 ) / 4 );
176
			$dc = $dg - $c * 36524;
177
			$b = floor( $dc / 1461 );
178
			$db = $dc % 1461;
179
			$a = floor( ( ( floor( $db / 365 ) + 1 ) * 3 ) / 4 );
180
			$da = $db - ( $a * 365 );
181
			$y = $g * 400 + $c * 100 + $b * 4 + $a;
182
			$m = floor( ( $da * 5 + 308 ) / 153 ) - 2;
183
			$d = $da - floor( ( ( $m + 4 ) * 153 ) / 5 ) + 122;
184
185
			$year  = $y - 4800 + floor( ( $m + 2 ) / 12 ) - 8000;
186
			$month = ( ( $m + 2 ) % 12 + 1 );
187
			$day   = $d + 1;
188
		} elseif ( $calendarmodel === DITime::CM_JULIAN ) {
189
			$b = floor( $jdvalue + 0.5 ) + 1524;
190
			$c = floor( ( $b - 122.1 ) / 365.25 );
191
			$d = floor( 365.25 * $c );
192
			$e = floor( ( $b - $d ) / 30.6001 );
193
194
			$month = floor( ( $e < 14 ) ? ( $e - 1 ) : ( $e - 13 ) );
195
			$year = floor( ( $month > 2 ) ? ( $c - 4716 ) : ( $c - 4715 ) );
196
			$day   = ( $b - $d - floor( 30.6001 * $e ) );
197
		} else {
198
			throw new RuntimeException( "Unsupported calendar model ($calendarmodel)" );
199
		}
200
201
		$year  = ( $year < 1 ) ? ( $year - 1 ) : $year; // correct "year 0" to -1 (= 1 BC(E))
202
203
		return array( $year, $month, $day );
204
	}
205
206
	/**
207
	 * Extract the time from a Julian Day number and return it as a string.
208
	 * This conversion is the same for all calendar models.
209
	 *
210
	 * @param $jdvalue float number of Julian Days
211
	 * @return array( hours, minutes, seconds )
0 ignored issues
show
Documentation introduced by
The doc-type array( could not be parsed: Expected "|" or "end of type", but got "(" at position 5. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
212
	 */
213
	protected static function JD2Time( $jdvalue ) {
214
		$wjd = $jdvalue + 0.5;
215
		$fraction = $wjd - floor( $wjd );
216
		$time = round( $fraction * 3600 * 24 );
217
		$hours = floor( $time / 3600 );
218
		$time = $time - $hours * 3600;
219
		$minutes = floor( $time / 60 );
220
		$seconds = floor( $time - $minutes * 60 );
221
		return array( $hours, $minutes, $seconds );
222
	}
223
224
}
225