summaryrefslogtreecommitdiff
path: root/www/wiki/extensions/SemanticMediaWiki/src/DataValues/Time/JulianDay.php
diff options
context:
space:
mode:
Diffstat (limited to 'www/wiki/extensions/SemanticMediaWiki/src/DataValues/Time/JulianDay.php')
-rw-r--r--www/wiki/extensions/SemanticMediaWiki/src/DataValues/Time/JulianDay.php200
1 files changed, 200 insertions, 0 deletions
diff --git a/www/wiki/extensions/SemanticMediaWiki/src/DataValues/Time/JulianDay.php b/www/wiki/extensions/SemanticMediaWiki/src/DataValues/Time/JulianDay.php
new file mode 100644
index 00000000..150b206d
--- /dev/null
+++ b/www/wiki/extensions/SemanticMediaWiki/src/DataValues/Time/JulianDay.php
@@ -0,0 +1,200 @@
+<?php
+
+namespace SMW\DataValues\Time;
+
+use RuntimeException;
+
+/**
+ * Julian dates (abbreviated JD) are a continuous count of days and fractions
+ * since noon Universal Time on January 1, 4713 BCE (on the Julian calendar).
+ *
+ * It is assumed that the changeover from the Julian calendar to the Gregorian
+ * calendar occurred in October of 1582.
+ *
+ * For dates on or before 4 October 1582, the Julian calendar is used; for dates
+ * on or after 15 October 1582, the Gregorian calendar is used.
+ *
+ * @license GNU GPL v2+
+ * @since 2.4
+ *
+ * @author Markus Krötzsch
+ */
+class JulianDay implements CalendarModel {
+
+ /**
+ * Moment of switchover to Gregorian calendar.
+ */
+ const J1582 = 2299160.5;
+
+ /**
+ * Offset of Julian Days for Modified JD inputs.
+ */
+ const MJD = 2400000.5;
+
+ /**
+ * @since 2.4
+ *
+ * @param integer $calendarmodel
+ * @param integer $year
+ * @param integer $month
+ * @param integer $day
+ * @param integer $hour
+ * @param integer $minute
+ * @param integer $second
+ *
+ * @return float
+ */
+ public static function getJD( $calendarModel = self::CM_GREGORIAN, $year, $month, $day, $hour, $minute, $second ) {
+ return self::format( self::date2JD( $calendarModel, $year, $month, $day ) + self::time2JDoffset( $hour, $minute, $second ) );
+ }
+
+ /**
+ * Return a formatted value
+ *
+ * @note April 25, 2017 20:00-4:00 is expected to be 2457869.5 and not
+ * 2457869.4999999665 hence apply the same formatting on all values to avoid
+ * some unexpected behaviour as observed in #2454
+ *
+ * @since 3.0
+ *
+ * @param $value
+ *
+ * @return float
+ */
+ public static function format( $value ) {
+ // Keep microseconds to a certain degree distinguishable
+ return floatval( number_format( $value, 7, '.', '' ) );
+ }
+
+ /**
+ * The MJD has a starting point of midnight on November 17, 1858 and is
+ * computed by MJD = JD - 2400000.5
+ *
+ * @since 2.4
+ *
+ * @param float jdValue
+ *
+ * @return float
+ */
+ public static function getModifiedJulianDate( $jdValue ) {
+ return $jdValue - self::MJD;
+ }
+
+ /**
+ * Compute the Julian Day number from a given date in the specified
+ * calendar model. This calculation assumes that neither calendar
+ * has a year 0.
+ *
+ * @param $year integer representing the year
+ * @param $month integer representing the month
+ * @param $day integer representing the day
+ * @param $calendarmodel integer either CM_GREGORIAN or CM_JULIAN
+ *
+ * @return float Julian Day number
+ * @throws RuntimeException
+ */
+ protected static function date2JD( $calendarmodel, $year, $month, $day ) {
+ $astroyear = ( $year < 1 ) ? ( $year + 1 ) : $year;
+
+ if ( $calendarmodel === self::CM_GREGORIAN ) {
+ $a = intval( ( 14 - $month ) / 12 );
+ $y = $astroyear + 4800 - $a;
+ $m = $month + 12 * $a - 3;
+ return $day + floor( ( 153 * $m + 2 ) / 5 ) + 365 * $y + floor( $y / 4 ) - floor( $y / 100 ) + floor( $y / 400 ) - 32045.5;
+ } elseif ( $calendarmodel === self::CM_JULIAN ) {
+ $y2 = ( $month <= 2 ) ? ( $astroyear - 1 ) : $astroyear;
+ $m2 = ( $month <= 2 ) ? ( $month + 12 ) : $month;
+ return floor( ( 365.25 * ( $y2 + 4716 ) ) ) + floor( ( 30.6001 * ( $m2 + 1 ) ) ) + $day - 1524.5;
+ }
+
+ throw new RuntimeException( "Unsupported calendar model ($calendarmodel)" );
+ }
+
+ /**
+ * Compute the offset for the Julian Day number from a given time.
+ * This computation is the same for all calendar models.
+ *
+ * @param $hours integer representing the hour
+ * @param $minutes integer representing the minutes
+ * @param $seconds integer representing the seconds
+ *
+ * @return float offset for a Julian Day number to get this time
+ */
+ protected static function time2JDoffset( $hours, $minutes, $seconds ) {
+ return ( $hours / 24 ) + ( $minutes / ( 60 * 24 ) ) + ( $seconds / ( 3600 * 24 ) );
+ }
+
+ /**
+ * Convert a Julian Day number to a date in the given calendar model.
+ * This calculation assumes that neither calendar has a year 0.
+ * @note The algorithm may fail for some cases, in particular since the
+ * conversion to Gregorian needs positive JD. If this happens, wrong
+ * values will be returned. Avoid date conversions before 10000 BCE.
+ *
+ * @param $jdValue float number of Julian Days
+ * @param $calendarModel integer either CM_GREGORIAN or CM_JULIAN
+ *
+ * @return array( calendarModel, yearnumber, monthnumber, daynumber )
+ * @throws RuntimeException
+ */
+ public static function JD2Date( $jdValue, $calendarModel = null ) {
+
+ if ( $calendarModel === null ) { // 1582/10/15
+ $calendarModel = $jdValue < self::J1582 ? self::CM_JULIAN : self::CM_GREGORIAN;
+ }
+
+ if ( $calendarModel === self::CM_GREGORIAN ) {
+ $jdValue += 2921940; // add the days of 8000 years (this algorithm only works for positive JD)
+ $j = floor( $jdValue + 0.5 ) + 32044;
+ $g = floor( $j / 146097 );
+ $dg = $j % 146097;
+ $c = floor( ( ( floor( $dg / 36524 ) + 1 ) * 3 ) / 4 );
+ $dc = $dg - $c * 36524;
+ $b = floor( $dc / 1461 );
+ $db = $dc % 1461;
+ $a = floor( ( ( floor( $db / 365 ) + 1 ) * 3 ) / 4 );
+ $da = $db - ( $a * 365 );
+ $y = $g * 400 + $c * 100 + $b * 4 + $a;
+ $m = floor( ( $da * 5 + 308 ) / 153 ) - 2;
+ $d = $da - floor( ( ( $m + 4 ) * 153 ) / 5 ) + 122;
+
+ $year = $y - 4800 + floor( ( $m + 2 ) / 12 ) - 8000;
+ $month = ( ( $m + 2 ) % 12 + 1 );
+ $day = $d + 1;
+ } elseif ( $calendarModel === self::CM_JULIAN ) {
+ $b = floor( $jdValue + 0.5 ) + 1524;
+ $c = floor( ( $b - 122.1 ) / 365.25 );
+ $d = floor( 365.25 * $c );
+ $e = floor( ( $b - $d ) / 30.6001 );
+
+ $month = floor( ( $e < 14 ) ? ( $e - 1 ) : ( $e - 13 ) );
+ $year = floor( ( $month > 2 ) ? ( $c - 4716 ) : ( $c - 4715 ) );
+ $day = ( $b - $d - floor( 30.6001 * $e ) );
+ } else {
+ throw new RuntimeException( "Unsupported calendar model ($calendarModel)" );
+ }
+
+ $year = ( $year < 1 ) ? ( $year - 1 ) : $year; // correct "year 0" to -1 (= 1 BC(E))
+
+ return [ $calendarModel, $year, $month, $day ];
+ }
+
+ /**
+ * Extract the time from a Julian Day number and return it as a string.
+ * This conversion is the same for all calendar models.
+ *
+ * @param $jdvalue float number of Julian Days
+ * @return array( hours, minutes, seconds )
+ */
+ public static function JD2Time( $jdvalue ) {
+ $wjd = $jdvalue + 0.5;
+ $fraction = $wjd - floor( $wjd );
+ $time = round( $fraction * 3600 * 24 );
+ $hours = floor( $time / 3600 );
+ $time = $time - $hours * 3600;
+ $minutes = floor( $time / 60 );
+ $seconds = floor( $time - $minutes * 60 );
+ return [ $hours, $minutes, $seconds ];
+ }
+
+}