00001 <?php
00030 class SMWDITime extends SMWDataItem {
00031
00032 const CM_GREGORIAN = 1;
00033 const CM_JULIAN = 2;
00034
00035 const PREC_Y = 0;
00036 const PREC_YM = 1;
00037 const PREC_YMD = 2;
00038 const PREC_YMDT = 3;
00039
00044 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 );
00045
00051 protected $m_precision;
00056 protected $m_model;
00061 protected $m_year;
00066 protected $m_month;
00071 protected $m_day;
00076 protected $m_hours;
00081 protected $m_minutes;
00086 protected $m_seconds;
00087
00104 public function __construct( $calendarmodel, $year, $month = false, $day = false,
00105 $hour = false, $minute = false, $second = false ) {
00106 if ( ( $calendarmodel != self::CM_GREGORIAN ) && ( $calendarmodel != self::CM_JULIAN ) ) {
00107 throw new SMWDataItemException( "Unsupported calendar model constant \"$calendarmodel\"." );
00108 }
00109 if ( $year == 0 ) {
00110 throw new SMWDataItemException( "There is no year 0 in Gregorian and Julian calendars." );
00111 }
00112 $this->m_model = $calendarmodel;
00113 $this->m_year = intval( $year );
00114 $this->m_month = $month != false ? intval( $month ) : 1;
00115 $this->m_day = $day != false ? intval( $day ) : 1;
00116 $this->m_hours = $hour !== false ? intval( $hour ) : 0;
00117 $this->m_minutes = $minute !== false ? intval( $minute ) : 0;
00118 $this->m_seconds = $second !== false ? intval( $second ) : 0;
00119 if ( ( $this->m_hours < 0 ) || ( $this->m_hours > 23 ) ||
00120 ( $this->m_minutes < 0 ) || ( $this->m_minutes > 59 ) ||
00121 ( $this->m_seconds < 0 ) || ( $this->m_seconds > 59 ) ||
00122 ( $this->m_month < 1 ) || ( $this->m_month > 12 ) ) {
00123 throw new SMWDataItemException( "Part of the date is out of bounds." );
00124 }
00125 if ( $this->m_day > self::getDayNumberForMonth( $this->m_month, $this->m_year, $this->m_model ) ) {
00126 throw new SMWDataItemException( "Month {$this->m_month} in year {$this->m_year} did not have {$this->m_day} days in this calendar model." );
00127 }
00128 if ( $month === false ) {
00129 $this->m_precision = self::PREC_Y;
00130 } elseif ( $day === false ) {
00131 $this->m_precision = self::PREC_YM;
00132 } elseif ( $hour === false ) {
00133 $this->m_precision = self::PREC_YMD;
00134 } else {
00135 $this->m_precision = self::PREC_YMDT;
00136 }
00137 }
00138
00139 public function getDIType() {
00140 return SMWDataItem::TYPE_TIME;
00141 }
00142
00143 public function getCalendarModel() {
00144 return $this->m_model;
00145 }
00146
00147 public function getPrecision() {
00148 return $this->m_precision;
00149 }
00150
00151 public function getYear() {
00152 return $this->m_year;
00153 }
00154
00155 public function getMonth() {
00156 return $this->m_month;
00157 }
00158
00159 public function getDay() {
00160 return $this->m_day;
00161 }
00162
00163 public function getHour() {
00164 return $this->m_hours;
00165 }
00166
00167 public function getMinute() {
00168 return $this->m_minutes;
00169 }
00170
00171 public function getSecond() {
00172 return $this->m_seconds;
00173 }
00174
00182 public function getMwTimestamp( $outputtype = TS_UNIX ) {
00183 return wfTimestamp(
00184 $outputtype,
00185 implode( '', array(
00186 str_pad( $this->m_year, 4, '0', STR_PAD_LEFT ),
00187 str_pad( $this->m_month, 2, '0', STR_PAD_LEFT ),
00188 str_pad( $this->m_day, 2, '0', STR_PAD_LEFT ),
00189 str_pad( $this->m_hours, 2, '0', STR_PAD_LEFT ),
00190 str_pad( $this->m_minutes, 2, '0', STR_PAD_LEFT ),
00191 str_pad( $this->m_seconds, 2, '0', STR_PAD_LEFT ),
00192 ) )
00193 );
00194 }
00195
00206 public function getForCalendarModel( $calendarmodel ) {
00207 if ( $calendarmodel == $this->m_model ) {
00208 return $this;
00209 } else {
00210 return self::newFromJD( $this->getJD(), $calendarmodel, $this->m_precision );
00211 }
00212 }
00213
00223 public function getSortKey() {
00224 $jd = ( $this->m_year >= -4713 ) ? $jd = $this->getJD() : -1;
00225 if ( $jd > 0 ) {
00226 return $jd;
00227 } else {
00228 return $this->m_year - 1 + ( $this->m_month - 1 ) / 12 + ( $this->m_day - 1 ) / 12 / 31;
00229 }
00230 }
00231
00232 public function getJD() {
00233 return self::date2JD( $this->m_year, $this->m_month, $this->m_day, $this->m_model ) +
00234 self::time2JDoffset( $this->m_hours, $this->m_minutes, $this->m_seconds );
00235 }
00236
00237 public function getSerialization() {
00238 $result = strval( $this->m_model ) . '/' . strval( $this->m_year );
00239 if ( $this->m_precision >= self::PREC_YM ) {
00240 $result .= '/' . strval( $this->m_month );
00241 }
00242 if ( $this->m_precision >= self::PREC_YMD ) {
00243 $result .= '/' . strval( $this->m_day );
00244 }
00245 if ( $this->m_precision >= self::PREC_YMDT ) {
00246 $result .= '/' . strval( $this->m_hours ) . '/' . strval( $this->m_minutes ) . '/' . strval( $this->m_seconds );
00247 }
00248 return $result;
00249 }
00250
00256 public static function doUnserialize( $serialization ) {
00257 $parts = explode( '/', $serialization, 7 );
00258 $values = array();
00259
00260 for ( $i = 0; $i < 7; $i += 1 ) {
00261 if ( $i < count( $parts ) ) {
00262 if ( is_numeric( $parts[$i] ) ) {
00263 $values[$i] = intval( $parts[$i] );
00264 } else {
00265 throw new SMWDataItemException( "Unserialization failed: the string \"$serialization\" is no valid datetime specification." );
00266 }
00267 } else {
00268 $values[$i] = false;
00269 }
00270 }
00271
00272 if ( count( $parts ) <= 1 ) {
00273 throw new SMWDataItemException( "Unserialization failed: the string \"$serialization\" is no valid URI." );
00274 }
00275
00276 return new self( $values[0], $values[1], $values[2], $values[3], $values[4], $values[5], $values[6] );
00277 }
00278
00287 public static function newFromJD( $jdvalue, $calendarmodel, $precision ) {
00288 list( $year, $month, $day ) = self::JD2Date( $jdvalue, $calendarmodel );
00289 if ( $precision <= self::PREC_YM ) {
00290 $day = false;
00291 if ( $precision == self::PREC_Y ) {
00292 $month = false;
00293 }
00294 }
00295 if ( $precision == self::PREC_YMDT ) {
00296 list( $hour, $minute, $second ) = self::JD2Time( $jdvalue );
00297 } else {
00298 $hour = $minute = $second = false;
00299 }
00300 return new SMWDITime( $calendarmodel, $year, $month, $day, $hour, $minute, $second );
00301 }
00302
00313 static public function date2JD( $year, $month, $day, $calendarmodel ) {
00314 $astroyear = ( $year < 1 ) ? ( $year + 1 ) : $year;
00315 if ( $calendarmodel == self::CM_GREGORIAN ) {
00316 $a = intval( ( 14 - $month ) / 12 );
00317 $y = $astroyear + 4800 - $a;
00318 $m = $month + 12 * $a - 3;
00319 return $day + floor( ( 153 * $m + 2 ) / 5 ) + 365 * $y + floor( $y / 4 ) - floor( $y / 100 ) + floor( $y / 400 ) - 32045.5;
00320 } else {
00321 $y2 = ( $month <= 2 ) ? ( $astroyear - 1 ) : $astroyear;
00322 $m2 = ( $month <= 2 ) ? ( $month + 12 ) : $month;
00323 return floor( ( 365.25 * ( $y2 + 4716 ) ) ) + floor( ( 30.6001 * ( $m2 + 1 ) ) ) + $day - 1524.5;
00324 }
00325 }
00326
00335 static public function time2JDoffset( $hours, $minutes, $seconds ) {
00336 return ( $hours / 24 ) + ( $minutes / ( 60 * 24 ) ) + ( $seconds / ( 3600 * 24 ) );
00337 }
00338
00349 static public function JD2Date( $jdvalue, $calendarmodel ) {
00350 if ( $calendarmodel == self::CM_GREGORIAN ) {
00351 $jdvalue += 2921940;
00352 $j = floor( $jdvalue + 0.5 ) + 32044;
00353 $g = floor( $j / 146097 );
00354 $dg = $j % 146097;
00355 $c = floor( ( ( floor( $dg / 36524 ) + 1 ) * 3 ) / 4 );
00356 $dc = $dg - $c * 36524;
00357 $b = floor( $dc / 1461 );
00358 $db = $dc % 1461;
00359 $a = floor( ( ( floor( $db / 365 ) + 1 ) * 3 ) / 4 );
00360 $da = $db - ( $a * 365 );
00361 $y = $g * 400 + $c * 100 + $b * 4 + $a;
00362 $m = floor( ( $da * 5 + 308 ) / 153 ) - 2;
00363 $d = $da - floor( ( ( $m + 4 ) * 153 ) / 5 ) + 122;
00364
00365 $year = $y - 4800 + floor( ( $m + 2 ) / 12 ) - 8000;
00366 $month = ( ( $m + 2 ) % 12 + 1 );
00367 $day = $d + 1;
00368 } else {
00369 $b = floor( $jdvalue + 0.5 ) + 1524;
00370 $c = floor( ( $b - 122.1 ) / 365.25 );
00371 $d = floor( 365.25 * $c );
00372 $e = floor( ( $b - $d ) / 30.6001 );
00373
00374 $month = floor( ( $e < 14 ) ? ( $e - 1 ) : ( $e - 13 ) );
00375 $year = floor( ( $month > 2 ) ? ( $c - 4716 ) : ( $c - 4715 ) );
00376 $day = ( $b - $d - floor( 30.6001 * $e ) );
00377 }
00378 $year = ( $year < 1 ) ? ( $year - 1 ) : $year;
00379 return array( $year, $month, $day );
00380 }
00381
00388 static public function JD2Time( $jdvalue ) {
00389 $wjd = $jdvalue + 0.5;
00390 $fraction = $wjd - floor( $wjd );
00391 $time = round( $fraction * 3600 * 24 );
00392 $hours = floor( $time / 3600 );
00393 $time = $time - $hours * 3600;
00394 $minutes = floor( $time / 60 );
00395 $seconds = floor( $time - $minutes * 60 );
00396 return array( $hours, $minutes, $seconds );
00397 }
00398
00406 static public function isLeapYear( $year, $calendarmodel ) {
00407 $astroyear = ( $year < 1 ) ? ( $year + 1 ) : $year;
00408 if ( $calendarmodel == self::CM_JULIAN ) {
00409 return ( $astroyear % 4 ) == 0;
00410 } else {
00411 return ( ( $astroyear % 400 ) == 0 ) ||
00412 ( ( ( $astroyear % 4 ) == 0 ) && ( ( $astroyear % 100 ) != 0 ) );
00413 }
00414 }
00415
00425 static public function getDayNumberForMonth( $month, $year, $calendarmodel ) {
00426 if ( $month !== 2 ) {
00427 return self::$m_daysofmonths[$month];
00428 } elseif ( self::isLeapYear( $year, $calendarmodel ) ) {
00429 return 29;
00430 } else {
00431 return 28;
00432 }
00433 }
00434
00435 }