This is my php class implementation of the terran computational calendar:
		
TCDate.class.php
<?php class TCDate { public $utc_leap_seconds = array("1972-06-30T23:59:60+00:00", "1972-12-31T23:59:60+00:00", "1973-12-31T23:59:60+00:00", "1974-12-31T23:59:60+00:00", "1975-12-31T23:59:60+00:00", "1976-12-31T23:59:60+00:00", "1977-12-31T23:59:60+00:00", "1978-12-31T23:59:60+00:00", "1979-12-31T23:59:60+00:00", "1981-06-30T23:59:60+00:00", "1982-06-30T23:59:60+00:00", "1983-06-30T23:59:60+00:00", "1985-06-30T23:59:60+00:00", "1987-12-31T23:59:60+00:00", "1989-12-31T23:59:60+00:00", "1990-12-31T23:59:60+00:00", "1992-06-30T23:59:60+00:00", "1993-06-30T23:59:60+00:00", "1994-06-30T23:59:60+00:00", "1995-12-31T23:59:60+00:00", "1997-06-30T23:59:60+00:00", "1998-12-31T23:59:60+00:00", "2005-12-31T23:59:60+00:00", "2008-12-31T23:59:60+00:00", "2012-06-30T23:59:60+00:00"); public $tc_leap_second_years = array(2,3,4,5,6,7,8,9,10,11,12,13,15,18,20,21,22,23,24,26,27,29,36,39,42); public $tc_epoch = -864000; public $date = array('date'=>0); private $unix_leap_seconds; private $min_tc_leap_second_year; private $max_tc_leap_second_year; public function __construct($date='now', $is_leap_second=false) { $this->min_tc_leap_second_year = min($this->tc_leap_second_years); $this->max_tc_leap_second_year = max($this->tc_leap_second_years); foreach($this->utc_leap_seconds as $utc_leap_second) { $datetime = new DateTime($utc_leap_second); $this->unix_leap_seconds[] = intval($datetime->format('U')); } $tc_timestamp = $this->toTCTimestamp($date, $is_leap_second); $this->date = $this->tcTimestampToDate($tc_timestamp); } //takes a UTC date string or a UNIX timestamp and converts it into a TC timestamp public function toTCTimestamp($date='now', $is_leap_second=false) { if(preg_match('/^[\-]?[\d]*$/',$date)) { //is timestamp if ($is_leap_second) $date--; $datetime = new DateTime(); $datetime->setTimestamp($date); } else { //is utc date if (strstr($date, ':59:60')) { $is_leap_second = true; $date = str_replace(':59:60',':59:59',$date); } $sign = ""; $test_date = $date; $test_date_timezone = substr($date, -5); if(substr($date, 0, 1) == '-') { $sign = '-'; $test_date = substr($date, 1); } $test_date_timezone = str_replace(array("+",":"), '', substr($date, -5)); $test_date = substr($test_date, 0, -5); $date_arr = preg_split( "/(\-|T|:)/", $test_date); if ($date_arr[0] == intval($date_arr[0]) && $date_arr[0] > 9999){ $datetime = new DateTime(); $datetime->setDate($date_arr[0], $date_arr[1], $date_arr[2]); $datetime->setTime($date_arr[3], $date_arr[4], $date_arr[5]); $test_date_timezone = intval(substr($test_date_timezone, 0, -2))*3600 + intval(substr($test_date_timezone, -2))*60; $datetime->setTimezone($this->getDateTimeZone($test_date_timezone)); } else { try { $datetime = new DateTime($date); } catch(Exception $e){ $datetime = new DateTime('now'); } } } $unix_timestamp = intval($datetime->format('U')); $leap_seconds = 0; foreach ($this->unix_leap_seconds as $unix_leap_second) { if ($unix_timestamp+1 == $unix_leap_second && $is_leap_second) { $unix_timestamp++; break; } if ($unix_timestamp < $unix_leap_second) break; else $leap_seconds++; } return $unix_timestamp - $this->tc_epoch + $leap_seconds; } public function tcTimestampToUTC ($tc_timestamp) { list($unix_timestamp, $is_leap_second) = $this->tcTimestampToUNIX($tc_timestamp); $unix_timestamp -= $is_leap_second; $datetime = new DateTime(); $datetime->setTimestamp($unix_timestamp); $datetime->setTimezone($this->getDateTimeZone()); $date = $datetime->format(DateTime::ATOM); if ($is_leap_second) $date = str_replace('59:59', '59:60', $date); return $date; } public function isLeapSecond($unix_timestamp='', $date='', $is_leap_second=0) { if (in_array($date, $this->utc_leap_seconds) || $is_leap_second) return 1; if (in_array($unix_timestamp, $this->unix_leap_seconds) && $date!='' && strstr($date, ':59:60')) return 1; return 0; } //returns a list of a unix_timestamp and whether or not it's the the first second of a 2 second timestamp second public function tcTimestampToUNIX($tc_timestamp) { $unix_timestamp = $tc_timestamp + $this->tc_epoch; foreach ($this->unix_leap_seconds as $unix_leap_second) { if ($unix_timestamp == $unix_leap_second) return array($unix_timestamp, 1); if ($unix_timestamp > $unix_leap_second) $unix_timestamp--; if ($unix_timestamp < $unix_leap_second) break; } return array($unix_timestamp, 0); } public function tcTimestampToDate($tc_timestamp=0, $year_base='', $offset=0) { $designator = 'TC'.($year_base == ''?'': intval($year_base)); list($unix_timestamp, $is_leap_second) = $this->tcTimestampToUNIX($tc_timestamp); $date = array('year'=>0,'month'=>0,'day'=>0,'hour'=>0,'minute'=>0,'second'=>0,'fraction'=>0,'designator'=>$designator,'year_base'=>($year_base == ''?'': intval($year_base)),'offset'=>$offset, 'tc_timestamp'=>$tc_timestamp, 'unix_timestamp'=>$unix_timestamp, 'is_leap_second'=>$is_leap_second); list($date['year'], $seconds_left) = $this->getYear(intval($tc_timestamp)+intval($offset), $year_base); $date['month'] = floor($seconds_left / (28*$this->s('day'))); $seconds_left -= $date['month'] * (28*$this->s('day')); $date['day'] = floor($seconds_left / $this->s('day')); $seconds_left -= $date['day'] * $this->s('day'); $date['hour'] = floor($seconds_left / $this->s('hour')); $seconds_left -= $date['hour'] * $this->s('hour'); $date['minute'] = floor($seconds_left / $this->s('minute')); $seconds_left -= $date['minute'] * $this->s('minute'); $date['second'] = floor($seconds_left); $seconds_left -= $date['second']; $seconds_left = explode('.', strval($seconds_left)); if (isset($seconds_left[1])) $date['fraction'] = intval($seconds_left[1]); $fraction = ($date['fraction'] != 0 ? '.'.$date['fraction'] : ''); $date['datemod'] = 0; $date['date'] = "{$date['year']}.{$date['month']}.{$date['day']},{$date['hour']}.{$date['minute']}.{$date['second']}$fraction $designator"; $date['padded_date'] = $this->pad($date['year'])."-".$this->pad($date['month'])."-".$this->pad($date['day'])." ".$this->pad($date['hour']).":".$this->pad($date['minute']).":".$this->pad($date['second'])."$fraction $designator"; return $date; } public function pad ($unit, $num=2) { return str_pad($unit, $num, '0', STR_PAD_LEFT); } public function getYear($tc_timestamp=0, $year_base='') { if ($tc_timestamp < 0) { $offsets = ceil(abs($tc_timestamp)/$this->s('128years')); list($year, $seconds_left) = $this->getYear(($offsets*$this->s('128years')) + $tc_timestamp, 0); return array($year-($offsets*128), $seconds_left); } $seconds_left = $tc_timestamp; $upper_limit = ceil($this->max_tc_leap_second_year+1/128)*128; for ($year=0; $seconds_left >= 0 && $year < $upper_limit; $year++) { $seconds_left -= $this->sInYear($year, $year_base); } if ($seconds_left < 0) { $year--; $seconds_left += $this->sInYear($year, $year_base); return array($year, $seconds_left); } $_128_cycles = floor($seconds_left / $this->s('128years')); $year += 128 * $_128_cycles; $seconds_left -= $_128_cycles * $this->s('128years'); $first_4_cycles = floor($seconds_left / (4*$this->s('year'))); if ($first_4_cycles > 0) { $year += 4; $seconds_left -= 4 * $this->s('year'); $_4_cycles = floor($seconds_left / $this->s('4years')); $year += 4 * $_4_cycles; $seconds_left -= $_4_cycles * $this->s('128years'); if(floor($seconds_left / ($this->s('year')+$this->s('day')) ) ) { $year += 1; $seconds_left -= $_4_cycles * $this->s('128years'); } } $_1_cycles = floor($seconds_left / $this->s('year')); $year += $_1_cycles; $seconds_left -= $_1_cycles * $this->s('year'); return array($year, $seconds_left); } //returns the number of second in a specifc unit range or the TC timetamp corresponding to a UTC date or UNIX timestamp public function sInYear($year=0, $year_base='') { $seconds = $this->s('year') + ($year%4==0 && $year%128!=0 ? $this->s('day') : 0); if ($year < $this->min_tc_leap_second_year || ($year_base != '' && intval($year_base) < $year) || $year > $this->max_tc_leap_second_year) {} else { $leap_second_count_by_year = array_count_values($this->tc_leap_second_years); if (isset($leap_second_count_by_year[$year])) $seconds += $leap_second_count_by_year[$year]; } return $seconds; } //returns the number of second in a specifc unit range or the TC timetamp corresponding to a UTC date or UNIX timestamp public function s($str='now') { switch ($str) { case 'default': return $this->toTCTimestamp($str); case 'second': return 1; case 'minute': return 60; case 'hour': return 3600; case 'day': return 86400; case 'year': return 31536000; case '4years': return 126230400; case '128years': return 4039286400; } } private function getDateTimeZone($timezone="UTC") { if (is_numeric($timezone)) $timezone = timezone_name_from_abbr("", intval($timezone), 0); $date_timezone = new DateTimeZone("UTC"); try { $date_timezone = new DateTimeZone($timezone); } catch(Exception $e){} return $date_timezone; } public function tcYearToTCTimestamp($year) { $timestamp = 0; if ($year < 0) { for ($i=$year; $i < 0; $i++) { $timestamp -= $this->sInYear($i); } } else { for ($i=0; $i < $year; $i++) { $timestamp += $this->sInYear($i); } } return $timestamp; } } function tcdate($date='now', $is_leap_second=0) { $date = new TCDate($date, $is_leap_second); return $date->date; } function tcdateToHTML($date=array(), $delimiters=array('.','.',',','.','.',' '), $units='', $pad=0, $class="now") { if (empty($units)) $units=array('year','month','day','hour','minute','second','designator'); $i=0; $html = ''; foreach($units as $unit) { $delimiter = (isset($delimiters[$i])?$delimiters[$i]:''); if (isset($date[$unit])) $html .= "<span".($unit == 'designator' ? " data-tc_timestamp=\"{$date['tc_timestamp']}\"":"")." data-designator=\"{$date['designator']}\" data-class=\"$class\" data-unit=\"$unit\"".($pad ? " data-pad=\"$pad\"":'').">{$date[$unit]}</span>$delimiter"; $i++; } return $html; } ?>