[comp.sources.d] Obtaining time info from Naval Observatory

dag@esleng.uucp (David A. Gilmour) (01/09/91)

I have seen references to a program which can automatically obtain
the time from the Naval Observatory and update the system clock.

If anyone knows where I can get the source for this program I'd
appreciate a note via mail.

Thanks in advance.


-- 
__________________________________________________________________________
David A. Gilmour            |   
Excalibur Systems Limited   |   uunet!mitel!cunews!micor!esleng!dag
Kanata, Ontario, Canada     |

jpr@jpradley.jpr.com (Jean-Pierre Radley) (01/10/91)

In article <1991Jan09.003434.5379@esleng.uucp> dag@esleng.uucp (David A. Gilmour) writes:
>I have seen references to a program which can automatically obtain
>the time from the Naval Observatory and update the system clock.
>
>If anyone knows where I can get the source for this program I'd
>appreciate a note via mail.

It isn't all that long, so here goes:


|From: mike@whutt.UUCP (BALDWIN)
|Newsgroups: sci.astro,comp.dcom.modems,rec.ham-radio
|Subject: Re: N.B.S. Time Service
|Summary: I've got (a small) one
|Keywords: naval observatory
|Message-ID: <3507@whutt.UUCP>
|Date: 12 Jul 88 14:54:40 GMT
|References: <455@trane.UUCP> <303@macomw.ARPA> <56@stanton.TCC.COM> <12277@mimsy.UUCP>
|Distribution: na
|Organization: AT&T Bell Laboratories
|Lines: 108
 	In article <56@stanton.TCC.COM> donegan@stanton.TCC.COM
> 				(Steven P. Donegan) writes:
>
> 	I came across a dos based time service program that used a
> 	Hayes modem to autodial the Naval Observatory in the Wash. DC
> 	area (I think) and retrieved the REAL time (plus/minus a second
> 	or so). If anyone knows of source for a similar program that I
> 	could port to my UNIX system I'd appreciate having it.

I've been running such a program, which I wrote, at home for over six
months now.  It's written in C, and runs under System V (or any UNIX
system with an stime(2) system call).  It consists of a single program
called "utc" (universal time coordinated).  When invoked with options,
it reads the Naval clock and does one or both of these things:

	-s	sets the time via stime(2)
	-p	prints the time via ctime(3C)

If it can't read the time from the standard input, it exits non-zero.
When invoked without options, it prints the time in Naval clock format
for about a minute.  Thus, it can be installed as a login shell to provide
time service for your other systems without having them all call DC.
As a test, "utc | utc -p" should print the current time.  You can pipe
cu right into it, so set up a crontab entry to execute

	cu 1-202-653-0351 | utc -s

You may have to fix your cu to die properly when it receives a SIGPIPE.
I have my crontab entry run once a day, but it only calls DC if the
time hasn't been set in over a week.  A simple shell file accomplishes
this:

	LAST=/etc/.lastutc
	[ -z "`find $LAST -mtime -7 -print`" ] &&
	cu 1-202-653-0351 | utc -s && >$LAST

---8<--------8<---------- cut here for utc.c ------------8<--------------8<---
/*
 * The Naval Observatory clock (+1 202 653 0351) prints this every second:
 *
 *	*
 *	jjjjj ddd hhmmss UTC
 *
 * jjjjj	Julian date modulo 2400000
 * ddd		days since beginning of year
 * hhmmss	time of day in Universal Time Coordinated
 */

#include <stdio.h>
#include <time.h>
#include <sys/types.h>

#define	EPOCH		40587			/* UNIX starts JD 2440587, */
#define	leap(y, m)	((y+m-1 - 70%m) / m)	/* also known as 1/1/70 */
#define	TONE		'*'
#define	TIME		"\n%05ld %03d %02d%02d%02d UTC"

main(argc, argv)
int	argc;
char	*argv[];
{
	int	setflg = 0, prtflg = 0;
	int	y, d, h, m, s;
	long	j;
	time_t	now;
	int	c;

	while ((c = getopt(argc, argv, "sp")) != EOF)
		switch (c) {
		case 's': setflg++; break;
		case 'p': prtflg++; break;
		default:
			fprintf(stderr, "usage: %s [-s] [-p]\n", argv[0]);
			return 1;
		}
	if (setflg || prtflg) {
		while ((c = getchar()) != TONE)
			if (c == EOF)
				return 1;
		if (scanf(TIME, &j, &d, &h, &m, &s) != 5)
			return 1;
		now = (((j - EPOCH) * 24 + h) * 60 + m) * 60 + s;
		if (setflg && stime(&now) == -1)
			perror(argv[0]);
		if (prtflg)
			fputs(ctime(&now), stdout);
	} else {
		for (c = 0; c < 60; c++) {
			time(&now);
			s = (now % 60);
			m = (now /= 60) % 60;
			h = (now /= 60) % 24;
			d = (now /= 24) % 365;
			j = now + EPOCH;
			y = (now /= 365);
			d += 1 - leap(y, 4) + leap(y, 100) - leap(y, 400);
			putchar(TONE);
			printf(TIME, j, d, h, m, s);
			putchar('\n');
			fflush(stdout);
			sleep(1);
		}
	}
	return 0;
}
-- 

 Jean-Pierre Radley	    NYC Public Unix	jpr@jpr.com	CIS: 72160,1341

csu@alembic.acs.com (Dave Mack) (01/11/91)

In article <1991Jan09.003434.5379@esleng.uucp> dag@esleng.uucp (David A. Gilmour) writes:
>I have seen references to a program which can automatically obtain
>the time from the Naval Observatory and update the system clock.
>
>If anyone knows where I can get the source for this program I'd
>appreciate a note via mail.
>
>Thanks in advance.

Warren Tucker's nbstime code is pretty specific to Xenix on a PC
clone. Here's what I hacked together using that as a starting point.
I have a shar file of Warren's original if you need it. This should
run on nearly any BSD system and shouldn't be too hard to port (back)
to System V.

put this in /etc/remote (after modifying for your modem) :

# Naval Observatory Time Standard 1200 baud (202)653-0351
notime:pn=12026530351:tc=unixPEP:

then compile the following code and put the executable somewhere in
your path (I call it bsdnbs - it's a very hacked up version of
Warren Tucker's code. If there are problems, blame me, not Warren.)

Then try:

tip notime | bsdnbs

It should tell you by how many seconds your system time was changed.

Then a "~." will kill tip and hang you up.

Since it resets the system time, you have to run it as root.

bsdnbs.c:
-------------------------------- cut here --------------------------------
/*
  Warren H. Tucker, 150 West Lake Drive, Mountain Park, GA  30075
  (404)587-5766
*/
/*
 * BSD modifications, hacks to accept the Naval Obs. signal from
 * stdin, etc., due to Dave Mack, csu@alembic.acs.com.
 *
 * Compile with: cc -o bsdnbs -O bsdnbs.c
 *
 * Runs on a Sun-4, SunOS4.1
 */
#include <stdio.h>
#include <signal.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <time.h>
#include <sys/time.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>


#ifndef ushort
#define ushort	unsigned short
#endif
#ifndef uchar
#define uchar	unsigned char
#endif
#ifndef uint
#define uint	unsigned int
#endif
#ifndef ulong
#define ulong	unsigned long
#endif


#define	EPOCH		40587	/* UNIX starts JD 2440587, */
#define	leap(y, m)	((y+m-1 - 70%m) / m)	/* also known as 1/1/70 */
#define	TONE		'*'
/* #define	TIME		"\n%05ld %03d %02d%02d%02d UTC" */
#define	TIME		"%05ld %03d %02d%02d%02d UTC"

/* for better source line utilization, frequent use of 'fprintf' and 'stderr'
   warrants the following */
#define pf	printf
#define	ff	fprintf
#define se	stderr
#define so	stdout

main(argc,argv,envp)
     int		argc;
     char	**argv;
     char	**envp;
{
  char	*cptr;
  int		iargv;
  int		swchar;
  int		itmp;
  char	rd_buf[64];
  long	now;
  long	julian;
  long	time_at_connect;
  int		day_of_year;
  int		year;
  int		month;
  int		day;
  int		hour;
  int		min;
  int		sec;
  int		fdcmos;
  int		have_time = 0;
  int		max_tries;
  struct tm *lt;
  char c;
  struct timeval tp;
  struct timezone tzp;
  long oldsecs;
  for (;;) {
    /* find the designator */
    while ((c = getchar()) != '*') ;
    
    /* skip the whitespace (CRLF) */
    getchar(); getchar();
    
    /* get the time */
    cptr = rd_buf;
    while ((*cptr = getchar()) != 'C')
      cptr++;
    *(++cptr) = '\0';
    if(sscanf(rd_buf,TIME,&julian,&day_of_year,&hour,&min,&sec) != 5) {
      fprintf(stderr,"missed\n");
      continue;
    }
    else {
      have_time = 1;
      break;
    }
  }
  if(have_time) {
      now = (((julian - EPOCH) * 24 + hour) * 60 + min) * 60 + sec;
      printf("Time retrieved from standard: %s\n",ctime(&now));
      gettimeofday(&tp,&tzp);
      oldsecs = tp.tv_sec - now;
      tp.tv_sec = now;
      settimeofday(&tp,&tzp);
      printf("System time reset by %d seconds\n",oldsecs);
      exit(0);
    }
  else
    {
      printf("Did not get time ... sorry\n");
      exit(254);
    }
  
}	/* end of main */

mcdonald@aries.scs.uiuc.edu (Doug McDonald) (01/15/91)

In article <1991Jan11.040746.7981@alembic.acs.com> csu@alembic.acs.com (Dave Mack) writes:
>In article <1991Jan09.003434.5379@esleng.uucp> dag@esleng.uucp (David A. Gilmour) writes:
>>I have seen references to a program which can automatically obtain
>>the time from the Naval Observatory and update the system clock.
>>
>
>Warren Tucker's nbstime code is pretty specific to Xenix on a PC
>clone. Here's what I hacked together using that as a starting point.

I got this to work on my PC.

However, how accurate is the time you get? That is, is there any
way to tell what the propagation delay is, and also, exactly when in the
string of characters I receive is the given time supposed to correspond to?

Doug McDonald

wht@n4hgf.Mt-Park.GA.US (Warren Tucker) (01/23/91)

In article <1991Jan14.205634.2201@ux1.cso.uiuc.edu> mcdonald@aries.scs.uiuc.edu (Doug McDonald) writes:
>In article <1991Jan11.040746.7981@alembic.acs.com> csu@alembic.acs.com (Dave Mack) writes:
>>In article <1991Jan09.003434.5379@esleng.uucp> dag@esleng.uucp (David A. Gilmour) writes:
>>>I have seen references to a program which can automatically obtain
>>>the time from the Naval Observatory and update the system clock.
>>Warren Tucker's nbstime code is pretty specific to Xenix on a PC
>>clone. Here's what I hacked together using that as a starting point.
>However, how accurate is the time you get? That is, is there any
>way to tell what the propagation delay is, and also, exactly when in the

The time is *fairly* close +-10 seconds or so. The clock they keep
is supposed to be jam on (their budget is larger than i would charge
to keep a Casio sync'd to WWV every day or so :-)).  It usually is
quite right, but some reports have shown it to be off by 12 seconds
or so.  I imagine that if you call with a *direct*-attached modem
(no servers, local networking, or whatever) you'll get good time
most very time.

The propagation delay is not > 1 second over the phone network. It is
probably < 100 msec here in Atlanta.  That's good enough for me!
If I needed more accurate time, I would get one of the three-frequency
diversity HF receivers and wheel over my dual-trace oscilloscope
and match the ticks with my local cesium standard, subtracting, of
course the calculated propagation delay from Fort Collins. Total
investment -- I don't want to think about it.

The time hack is on the stop bit of the '*' (or thereabouts :-)).
 
-----------------------------------------------------------------------
Warren Tucker, March Hare   gatech!n4hgf!wht or wht@n4hgf.Mt-Park.GA.US
When bad men combine, the good must associate;  else they will fall one
by one, an unpitied sacrifice in a contemptible struggle. -Edmund Burke