Phil Ehrens with a little neatening up by
Donal Fellows
- Description
- Given a GMT or UNIX epoch time, return GPS time. If no argument is given, return current GPS time.
- Parameters
- time - UNIX epoch seconds, or a date and time: "01/06/80 01:01:01"
Usage set gpstime [ gpsTime "04/20/99 01:20:59" ]
or set gpstime [ gpsTime 91232121 ]
or set gpstime [ gpsTime 01/20/01 ]
or set gpstime [ gpsTime 01/20/2001 ]
(of course, you can't calculate GPS time in the future unless you know when the leap seconds are...)
or set gpstime [ gpsTime now ]
- Comments
- This procedure must be manually updated when a new leap-second is added. [1] The GPS epoch started at 0 at 01/06/80 00:00:00 GMT/UTC [2]. Should put leap seconds in a separate file and check daily for updates.
proc gpsInit {} {
uplevel {
;## the difference between the UNIX epoch and GPS epoch.
set epochdiff 315964819
;## 1972-01-01 00:00:00 UTC was 1972-01-01 00:00:10 TAI.
set offset 10
;## WARNING! KEEP THE NEXT VARIABLE IN SYNC OR ELSE!
set nowOffset 23 ;# must be [llength [gpsLeapSecondTimes]]
}
}
# This is factored out to make for easy upgrading to handle updates.
proc gpsLeapSecondTimes {} {
;## assumes 00:00:00.
foreach date {
"June 30, 1972"
"December 31, 1972"
"December 31, 1973"
"December 31, 1974"
"December 31, 1975"
"December 31, 1976"
"December 31, 1977"
"December 31, 1978"
"December 31, 1979"
"June 30, 1981"
"June 30, 1982"
"June 30, 1983"
"June 30, 1985"
"December 31, 1987"
"December 31, 1989"
"December 31, 1990"
"June 30, 1992"
"June 30, 1993"
"June 30, 1994"
"December 31, 1995"
"June 30, 1997"
"January 1, 1999"
"January 1, 2006"
} {
lappend times [clock scan $date -gmt 1]
}
;## Ensure that we're sorted by number (i.e. by date)
return [lsort -integer $times]
}
proc gpsTime { { time "" } } {
gpsInit
;## quick short-circuit for "now".
if { [ regexp {^$|now} $time ] } {
set time [ clock seconds ]
set fudge [ expr {$offset + $nowOffset} ]
return [ expr {$time - $epochdiff + $fudge} ]
}
;## canonicalise input to UNIX epoch seconds
if { ! [ regexp {^-?[0-9]+$} $time ] } {
if { [ catch {
set time [ clock scan $time -gmt 1 ]
} err ] } then {
return -code error $err
}
}
set index 0
foreach sec [gpsLeapSecondTimes] {
if {$time <= $sec} {break}
incr index
}
set offset [expr {$offset + $index}]
set gpstime [expr {$time - $epochdiff + $offset}]
return $gpstime
}
- Description
- Converts GPS epoch time to UNIX epoch time
- Parameters
- time - GPS time in GPS seconds, leap second corrected
Usage set utctime [ utcTime gpsTime ]
'''Comments''':
proc utcTime { { time "" } } {
Here is a proc for getting leap second info from a standard source.
It contains the useful if { $force_update } { unset ::leapdates }
if { [ info exists ::leapdates ] } { return $::leapdates }
set months { JAN 1 FEB 2 MAR 3 APR 4 MAY 5 JUN 6 \
JUL 7 AUG 8 SEP 9 OCT 10 NOV 11 DEC 12 }
if { [ catch {
FTP::new leap
leap::Open maia.usno.navy.mil anonymous foo@bar.baz
leap::Get ser7/tai-utc.dat leapseconds
leap::Close
} err ] } {
set msg "error encountered while trying to update "
append msg "leap seconds list: $err (falling back to "
append msg "old list)."
return -code errif {![regexp {^-?[0-9]+$} $time]} {
return -code error "utcTime requires integer argument"
}
gpsInit
set index 0
foreach sec [gpsLeapSecondTimes] {
if { $time <= $sec } {break}
incr index
}
set offset [expr {$offset + $index}]
set utctime [expr {$time + $epochdiff - $offset}]
return $utctime
}
----if { [ catch {
set fid [ open leapseconds r ]
set data [ read $fid ]
close $fid
} err ] } {
return -code error $err
}
or $msg
}
foreach { mo ord } $months {
regsub -all $mo $data $ord data
}
foreach line [ split $data "\n" ] {
foreach { y m d 1 ;## there are currently 36
set ::leapdates $leapdates lappend leapdates $utc [ expr { int($leap) } ] }2 3 leap 4 5 6 7 8 9 10 11 } $line {
set utc [ clock scan $m/$d/$y -gmt 1 ]
}
}entries in the leap seconds table
if { [ llength $leapdates ] < 72 } {
return -code error "CANNOT CALCULATE LEAP SECONDS!!"
}