[Phil Ehrens] with a little neatening up by [Donal Fellows] ---- * GMT or UTC to GPS '''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. [ftp://tycho.usno.navy.mil/pub/series/ser14.txt] The GPS epoch started at 0 at 02/06/80 00:00:00 GMT. 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 22 ;# 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" } { 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 } ---- * GPS to UTC '''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!!" } ---- [Category Date and Time]