GPS/UTC Time Conversion Functions

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. [L1 ] The GPS epoch started at 0 at 01/06/80 00:00:00 GMT/UTC [L2 ]. 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
 }

  • 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 [email protected]
        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!!"
     }