This updates and replaces the gpsdate script. I started it in 2004 and last touched it in 2006. There has been a lot of water under the dam since then.
This script show a simple proof of concept that you can expand to extract any data you want from your gpsd data. It also show a simple example of several facilities in the Perl date::manip module.
Note that this isn't all that accurate. For sub-second accuracy, look into using gpsd with ntpd or chrony. (man gpsd, then search on 'NTP' or 'CHRONY'.)
#! /usr/bin/perl # OK, I'm lazy; it's one of the reasons I work in Perl. I figure if we # have these 24 atomic clocks of reasonably acceptable accuracy # orbiting the planet, I ought to be able to set my system clock from # them occasionally. So this is a simple script to display the system # time from GPS. You can also use it to set the system time. # This version uses Net::GPSD3, which handles all the heavy lifting, # but requires lbgps version 2.90 or higher. # Options: # -h is reserved in case I decide to add a "help" function. # -l specifies printing the time in local time. # -p sets the port on the remote host to try. You can give the service # name (e.g. gpsd) or the port number (e.g. 2947). Or you can give # both by using the syntax 'name(number)', e.g. 'gpsd(2947)'. If Perl # can't find the name wherever it looks these things up (probably # /etc/services), it goes for the number. So use both for maximum # portability. The default value is 'gpsd(2947)'. To avoid bashisms, # use '-p gpsd\(2947\)'. # -s indicates that we should spit out the time and date ready for # date to set the system clock. If the local time option is not set, # we provide the -u switch for date. E.g: # date -s $(gpsdate -s) # date -s $(gpsdate -sl gpsbox) # If -s is not set, we give a more human readable time format. We # ignore portions of a second; the lag time and overhead make the time # delivered by the program close enough. # Requires: gpsd (http://gpsd.berlios.de/) version 2.90 or higher; # date, the gnu time setting and displaying utility. Date twiddling is # courtesy of Date::Manip; Debian and Ubuntu users will want to # install libdate-manip-perl. Oh, and a GPS receiver somewhere would # probably help. # gpsdate will block until the GPS receiver has warmed up, # i.e. acquired enough satellites (or whatever it needs) to have a # valid time signal. # Copyright 2004 through the last date of modification Charles Curley, # http://www.charlescurley.com/. # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # You can also contact the Free Software Foundation at # http://www.fsf.org/ use Getopt::Std; use Net::GPSD3; use Date::Manip::Date; use Date::Manip::TZ; use strict; my %option; getopts ("lp:sv", \%option); # $host is the name or IP address of the host. It may be local or # remote. e.g: localhost. User configurable at the command line. my $host = 'localhost'; if (@ARGV > 1) { die ("Maximum of one host name, please.\n"); } $host = shift (@ARGV); # If set, show the time as local time, not GMT. $option{l} = 0 unless defined $option{l}; my $localTime = $option{l}; # $port is the port on the remote host to try. User configurable at # the command line with -p. $option{p} = 'gpsd(2947)' unless defined $option{p}; my $port = $option{p}; # $settime, if set, indicates that we should spit out the time and # date ready for settime to set the system clock. We even provide the # -u switch for date if appropriate. my $settime=$option{s}; $option{v} = 0 unless defined $option{v}; my $verbose = $option{v}; # Originally from the Net::GPSD3 man page. sub myHandler { my $object = shift; # use Data::Dumper qw{Dumper}; # print Dumper($object); # print ("Class is $object->{'class'}\n"); if ($object->{'class'} eq 'VERSION' && $verbose) { # Show the version of the host. # print ($object->{'string'} . "\n"); print ("gpsd release: $object->{'release'}, rev: $object->{'rev'}"); print (", protocol $object->{'proto_major'}.$object->{'proto_minor'}\n"); } elsif ($object->{'class'} eq 'TPV') { # We have a Time, Position, Velocity report # print ($object->{'string'} . "\n"); if ($object->{'mode'} == 3) { # Mode is 3, i.e. a 3D fix. my $date = new Date::Manip::Date; my $err = $date->parse ($object->{'time'}); if ($err) { die ("Unacceptable date string: $date.\n"); } # my $val = $date->value(); # print ("Value is $val\n"); if ($localTime) { my $tz = new Date::Manip::TZ; my $zone = $tz->curr_zone(); $err = $date->convert($zone); if ($err) { die ("Time zone conversion failed.\n"); } print ("The local time zone is $zone.\n") if ($verbose); } if ($settime && $localTime) { print $date->printf ("%m%d%H%M%Y.%S\n"); # print ("MMDDhhmmCCYY.ss\n"); } elsif ($settime) { print $date->printf (" -u %m%d%H%M%Y.%S\n"); # print (" -u MMDDhhmmCCYY.ss\n"); } else { print $date->printf ("%Y-%m-%dT%H:%M:%S\n"); } exit (0); } } } my $gpsd=Net::GPSD3->new(host=>$host, port=>$port); $gpsd->addHandler(\&myHandler); $gpsd->watch; exit (0);