NTP, UTC, and Working with Time on Linux

Mike Chirico (mchirico@users.sourceforge.net or mchirico@gmail.com)
Date: Fri Jul 8 12:59:46 EDT 2005

What time will it be 4 years from now?

It is a trick question. There is NO way to calculate what time it will be (what time the clocks will read), to the nearest half second, exactly four years into the future.

Are the days getting longer?

Yes. There used to be 86,400 seconds in a day; but, that was back in 1820. Because the earth's rotation is slowed by ocean currents and tidal friction, the number of seconds in a day is slightly greater than 86,400.

How many seconds in a minute?

61, 60 and possibly 59 seconds in a minute. When a leap second is added there are 61 seconds in a minute. There have been 22 leaps seconds. The last one was 01-01-099.

Can we go back in time?

YES. Every time there is a leap second we go back in time. Time-Servers use a 64 bit format called the NTP timestamp. This format is divided into 2 parts. The first 32 bits are the number of seconds since January 1, 1900 (GMT), and the second 32 bits specify the fraction of a second.

``````
0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         Integral Part                         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         Fractional Part                       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
``````

During a leap second, like the one that occurred between December, 31 1998 and January 1, 1999, we went back in time. In order to see this take a close look at the following:

``````
#     Date        Time       TAI  NTP Leap        NTP Seconds

1.  Dec 31 98    23:59:59     31    01           3,124,137,599
2.  Dec 31 98    23:59:60     31    01           3,124,137,600
3.  Jan 01 98    00:00:00     32    00           3,124,137,600
4.  Jan 01 99    00:00:01     33    00           3,124,137,601
``````

Note, starting in row 2, the number of NTP Seconds is 3,124,137,600, the fractional part, not shown, continues counting upward until it is time to rollover to the next second. But, look at row 3 in the NTP Seconds column. The number of seconds does not change. These NTP Seconds are coming from the master clock. The computer, if it is running a current version of the Linux kernel will account for this second by hitting 23:59:60, as shown in the Time column.

Intelligent Alien Life?

Today's cesium master clocks, and hydrogen master clocks will loose less than a second every 1.4 million years. Nothing found in nature produces such a precise signal. Nothing even comes close: certainly not the rotation of the earth. Some form of intelligent modification, at the atomic level, something beyond random chance is needed to continuously produce such precise signal intervals.

Major definitions of time.

Atomic Time - or TAI, International Atomic Time scale. This time scale uses the specific definition of a second: 9,192,631,770 cycles between two hyperfine levels of the ground state of cesium 133.

Universal Time - or UT is counted from 0 hours at midnight, with the unit of duration the mean solar day. There are 2 subdivision of UT.

UT0 - the rotational time of a particular place of observation. Imagine looking up at the sky at a fixed reference, the stars, and calculating time from the apparent motion. However, the earth wobbles, (Chandler wobbles), causing the fixed position of the poles to change, thus affecting the calculated time from this method.

UT1 - this is computed by correcting UT0 for the irregularities in the Earth's rotation from polar motion.

Coordinated Universal Time - or (UTC). This is time we live by. It's the time of your computer, if it is set correctly. UTC is always kept to within 0.9 seconds of UT1 by the introduction of a "leap second", which was occurring roughly every 500 days. However, it's been over a 1000 days since the last leap second. Special note, GMT (Greenwich Mean Time) is often used to mean UTC. The names are interchangeable, but UTC is the correct modern definition. However, GMT is still in heavy use.

The Date Command

You can get the date and time with the following command.

```      \$ date
Tue Aug 31 14:09:02 EDT 2004
```

And, you can modified the data format in a number of ways. This example shows a few of the options:

```      \$ date "+%m%d%y %A,%B %d %Y %X"
083104 Tuesday,August 31 2004 02:10:04 PM
```

If you are creating a lot of log files or backups, where sorting by the filename may be important, then, consider the following format "+%y%m%d", (year, month, day). For example, if you executed the following command below, you would backup everyting in the ./test directory into a filename starting with the current date.

```      \$ tar -czf `date "+%y%m%d_testbackup.tar.gz"` ./test
\$ ls *_testbackup.tar.gz|sort
040829_testbackup.tar.gz
040830_testbackup.tar.gz
040831_testbackup.tar.gz
```

You can also dispaly the time, say, two years from now. Or use multiple combinations of plus or minus with year, month, week, day, hour, minute and second. Of course, if during that interval a leap second is introduced, or possibly subtracted, then the predicted time will be off by the number of leap seconds. There is no precise way to calculate when UTC will differ from UT1 by +-0.9 seconds.

```      \$ date -d '+2 year +1 month -1 week +3 day -8 hour +2 min -5 seconds'
Wed Sep 27 06:28:12 EDT 2006
```

So how far can you use date to display times into the future? Currently, you can use the date command to calculate values 30 years into the future and a bit further. However, going forward 34 years fails, unless you are running on a 64-bit system. In fact, the last possible time that can be displayed is January 18, 2038, sometime after 22:14:07 EST, or 01-19-2038 GMT. You can calculate this number exactly by adding 2^31-1 seconds to unix epoch which is (January 1, 1970 UTC). The largest positive value that can be represented by a 32 bit number is 2^31-1, and on the Intel platform time is stored in a 32 bit field. So, you can calculate the earliest internal date by subtracting 2^31-1 seconds from epoch which would give you (12-13-1901 20:45:53 UTC).

You can also use the date command to calculate dates and times for any timezone by modifying the TZ environment variable. For instance, to find the current time in New Zealand, you would execute the following:

```      \$ export TZ=NST
\$ date
```

Like the NTP format, dates are always stored internally as the number of seconds in UTC time, then, converted to the timezone specified in the TZ environment variable. If you unset the TZ variable, then, the timezone is obtained from the binary file /etc/localtime, which contains the timezone, offset from UTC, whether daylight saving time (dst) is in effect, and when dst begins and ends.

Or, you can always get the date command to give UTC, using the -u option

```      \$ date -u
Sun Aug 22 02:06:26 UTC 2004
```

The TZ environment variable can be assigned any of the standard three-letter abbreviations below. However, if you make a mistake and initialize it to something that is not on the charts, you will get GMT, and no error will be returned.

```     Hours From Greenwich Mean Time (GMT) Value

0 GMT Greenwich Mean Time
+1   ECT   European Central Time
+2   EET   European Eastern Time
+2   ART
+3   EAT   Saudi Arabia
+3.5 MET   Iran
+4   NET
+5   PLT   West Asia
+5.5 IST   India
+6   BST   Central Asia
+7   VST   Bangkok
+8   CTT   China
+9   JST   Japan
+9.5 ACT   Central Australia
+10  AET   Eastern Australia
+11  SST   Central Pacific
+12  NST   New Zealand
-11  MIT   Samoa
-10  HST   Hawaii
-8   PST   Pacific Standard Time
-7   PNT   Arizona
-7   MST   Mountain Standard Time
-6   CST   Central Standard Time
-5   EST   Eastern Standard Time
-5   IET   Indiana East
-4   PRT   Atlantic Standard Time
-3.5 CNT   Newfoundland
-3   AGT   Eastern South America
-3   BET   Eastern South America
-1   CAT   Azores
```

Interesting note: take a look at the following. I am currently in in EST, Eastern Standard Time adjusted to EDT, or Eastern Daylight Time.

```
\$ date
Tue Aug 31 14:59:54 EDT 2004

\$ export TZ=HST
\$ date
Tue Aug 31 09:00:16 HST 2004

\$ export TZ=EST
\$ date
Tue Aug 31 14:00:38 EST 2004
```

Note the last time is off by an hour. It should have been 15:00:38. Daylight savings time was not taken into account. This can be corrected by setting TZ as follows:

```
TZ=<timezone><hour offset from UTC><dst timezone>.

\$ export TZ=EST05EDT
\$ date
Tue Aug 31 15:01:50 EDT 2004
```

EST was taken from the chart below. Five hours has to be added to get UTC, hence the 05. And currently EDT, Eastern Daylight, is in effect.

```      DST timezones

0      BST for British Summer.
+500   EDT for Eastern Daylight.
+600   CDT for Central Daylight.
+700   MDT for Mountain Daylight.
+800   PDT for Pacific Daylight.
+900   YDT for Yukon Daylight.
+1000  HDT for Hawaii Daylight.
-100   MEST for Middle European Summer,
MESZ for Middle European Summer,
SST for Swedish Summer and FST for French Summer.
-700   WADT for West Australian Daylight.
-1000  EADT for Eastern Australian Daylight.
-1200  NZDT for New Zealand Daylight.
```

Was there an easier way to get back to my correct time? Yes, just unset the TZ environment variable.

```
\$ unset TZ
\$ date
Sun Aug 22 10:17:35 EDT 2004
```

Note, even though TZ was adjusted for daylight saving time, will you get the correct time 5 months from now? When does daylight saving time go into effect? The TZ value shown below adjust for dst, only during the correct dates. For instance, this entry goes into effect April, the first week, at 2am, and ends October the 5th week, at 2am. Note 10.5.0 stands for the 5th week in October, and not the 5th day.

```
\$ export TZ=EST+5EDT,M4.1.0/2,M10.5.0/2
```

However, there is an easier way for you to make timezone changes, that will correctly account for dst, including when dst begins and ends. Here are a few examples.

```
\$ export TZ=:/usr/share/zoneinfo/posix/America/Aruba
\$ export TZ=:/usr/share/zoneinfo/Egypt
```

Need more? Take a look at filenames under /usr/share/zoneinfo

```
\$ ls /usr/share/zoneinfo

Africa      Chile    Factory    Iceland      Mexico    posix       UCT
America     CST6CDT  GB         Indian       Mideast   posixrules  Universal
Antarctica  Cuba     GB-Eire    Iran         MST       PRC         US
Arctic      EET      GMT        iso3166.tab  MST7MDT   PST8PDT     UTC
Asia        Egypt    GMT0       Israel       Navajo    right       WET
Atlantic    Eire     GMT-0      Jamaica      NZ        ROC         W-SU
Australia   EST      GMT+0      Japan        NZ-CHAT   ROK         zone.tab
Brazil      EST5EDT  Greenwich  Kwajalein    Pacific   Singapore   Zulu
Canada      Etc      Hongkong   Libya        Poland    SystemV
CET         Europe   HST        MET          Portugal  Turkey
```

So how do you get dates and times before 1904 or after 2038?

There is a popular open source package, Date-Calc by Steffen Beyer that will handle this. http://www.engelschall.com/u/sb/download/pkg/Date-Calc-5.3.tar.gz

This package can be installed and used as a Perl module or, since the following 3 source files are included: DateCalc.c, DateCalc.h and ToolBox.h. It is possible to use Beyer's functions directly in a C program.

First, it is helpful to get a closer look at some of the date and time commands using a simple C program. The following example will show the date and time to the microsecond, without Beyer's routines.

``````
/* C routine: sample gettimeofday
with seconds and microseconds since the  Epoch.

Compile:
gcc -o gettimeofday gettimeofday.c

*/
#include <sys/time.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>

int main(void)
{
char buffer[30];
struct timeval tv;

time_t curtime;

gettimeofday(&tv, NULL);
curtime=tv.tv_sec;

strftime(buffer,30,"%m-%d-%Y  %T.",localtime(&curtime));
printf("%s%ld\n",buffer,tv.tv_usec);

return 0;

}
``````

Compiling and running the program above, is demonstrated below.

``````
\$ gcc -o gettimeofday gettimeofday.c
\$ ./gettimeofday
08-22-2004  10:39:45.443512
``````

The output of the time is the timezone for the current system. Or, like the data command, changing the TZ environment variable gives you the option to get the time for Any timezone.

``````
\$ export TZ=GMT
\$ ./gettimeofday
08-22-2004  14:40:19.249904

\$ export TZ=EST05EDT
\$ ./gettimeofday
08-22-2004  10:40:49.483140
``````

It is possible to verify EPOC: 01-01-1970 00:00:00 by making the following changes to the program, and recompiling.

``````
curtime=0;
strftime(buffer,30,"%m-%d-%Y  %T",localtime(&curtime));
printf("%s\n",buffer);
``````

Now, run the changes, first setting TZ to GMT.

``````
\$ export TZ=GMT
\$ ./gettimeofday
01-01-1970  00:00:00
``````

Since 2^31-1 = 2147483647, which is the maximum positive value that can be expressed by a 32 bit number. If we set curtime to this value, and then set it to -2147483647, we will get the maximum and minimum values for time on a 32 bit system.

``````
curtime=2147483647;
strftime(buffer,30,"%m-%d-%Y  %T",localtime(&curtime));
printf("%s\n",buffer);

curtime=-2147483647;
strftime(buffer,30,"%m-%d-%Y  %T",localtime(&curtime));
printf("%s\n",buffer);
``````

Here is the output.

``````
\$ export TZ=GMT
\$ ./gettimeofday
01-19-2038  03:14:07
12-13-1901  20:45:53
``````

Now we will take the original program and add in Beyer's routines. There are 2 includes "ToolBox.h" and "DateCalc.h". It is also necessary to define year, month, day, hour etc. as Z_int, as shown below.

``````
/* gettimeofday2.c

C routine: sample gettimeofday with time in milliseconds
mmc mchirico@users.sourceforge.net

Compile:

\$  gcc -o gettimeofday2  -Wall -W -O2 -s -pipe gettimeofday2.c DateCalc.c

Make sure DateCalc.h and ToolBox.h are in the current directory as well.

*/
#include <sys/time.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include "ToolBox.h"
#include "DateCalc.h"

int main(void)
{
char buffer[30];
struct timeval tv;

time_t curtime;
Z_int year;
Z_int month;
Z_int day;
Z_int hour;
Z_int min;
Z_int sec;
Z_int doy;
Z_int dow;
Z_int dst;

gettimeofday(&tv, NULL);
curtime=tv.tv_sec;

strftime(buffer,30,"%m-%d-%Y  %T.",localtime(&curtime));
printf("%s%ld\n",buffer,tv.tv_usec);

/* Assign current values to year, month, day, hour ...etc
from curtime */
DateCalc_localtime(&year,&month,&day,
&hour,&min, &sec, &doy, &dow, &dst, curtime);

/* Now add 500 years */
&month,       /*  I/O  */
&day,         /*  I/O  */
&hour,        /*  I/O  */
&min,         /*  I/O  */
&sec,         /*  I/O  */
500,         /*  year. */
0,           /*  month */
0,           /*  day   */
0,           /*  hour  */
0,           /*  min   */
0);          /*  sec   */

" year=%d\n"
" month=%d\n"
" day=%d\n"
" hour=%d\n"
" min=%d\n"
" sec=%d\n"
" fraction=%ld\n",
year,month,day,hour,min,sec,tv.tv_usec);

return 0;

}
``````

The above program will give the following output, which is 500 years into the future.

``````
\$ unset TZ
\$ ./gettimeofday2
08-22-2004  11:16:43.88386
year=2504
month=8
day=22
hour=11
min=16
sec=43
fraction=88386
``````

DateCalc has many other functions, such as counting the number of days until Easter, calculating the day Easter falls on. Note Easter is always a Sunday. "DateCalc_monday_of_week" will determine when Monday occurs given the week and year. For instance, take a look at the layout of this function.

``````
boolean
DateCalc_monday_of_week       (Z_int   week,       /*   I   */
Z_int  *year,       /*  I/O  */
Z_int  *month,      /*   O   */
Z_int  *day);       /*   O   */
``````

In the comments, Beyer uses an "I" for required input, an "0" for derived output, and I/O for required input that may be modified. For instance, the first week in 2004 starts on a Thursday; therefore, the first Monday is in 2003.

``````
January
Su Mo Tu We Th Fr Sa
1  2  3
4  5  6  7  8  9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
``````

Installing and Configuring NTP

The ntpd program runs as a daemon making continuous adjustments to your computer's System Time by sampling the time from 1 or more (preferably 3) Time-Servers. The correct time is calculated by figuring out the network delay from a series of queries to the Time-Servers. Then factoring in this delay to calculate the correct time. The NTP program will deliver accuracy to within 1-50ms, which is dependent upon the network path to the Time-Server and the Time-Server itself. For a workstation, you should use (stratum 2) Time-Servers.

NOTE: If your computer clock differs by more than 1000s, then, the ntpd daemon will not start, instead, it will enter panic mode and exit. Therefore, on boot-up it is important to query a Time-Server for the time, using the ntpdate command or first run ntpd with the -g option. Red Hat and Fedora will run ntpdate against any Time-Server listed in the "/etc/ntp/step_tickers" file. So Time-server entries must be listed /etc/ntp.config, these are the Time-servers that are queried when ntpd is running; but, on startup at least one Time-Server must be list in /etc/ntp/step_tickers, for time initialization.

All Time Servers give UTC time. In other words, you never have to worry about what timezone the Time Server is in; but, you want to pick the Time-Server that is has the smallest network distance.

NTP on Red Hat and Fedora

If you are running Red Hat or Red Hat's Fedora it is recommended that you use their version of NTP, since its been modified to switch from the root account to the user NTP after startup. In addition, when your startup script runs it will automatically read entries in /etc/ntp/step-tickers to initialize the hardware clock. Again, on startup if your computer's time is off by more than 1000s, which would happen if the computer was powered off and the battery was removed,the ntpd daemon will enter a panic mode and exit.

STEP 1:

Find three or four public (stratum 2) Time-Servers near you. Stratum 2 servers are better suited for workstations, and should have better response compared to a stratum 1 server, which will not give priority to anonymous workstations. You can find a listing of servers at the following link: http://www.eecis.udel.edu/~mills/ntp/clock2b.html

STEP 2:

Specify the Time-Servers and restrict the access of these server. You computer can query the time from these stratum servers and set the time correctly based on the best server. However, since access is restricted, these time servers cannot initiate a time change on your compuer. For a workstation, you would configure your file as follows:

```      \$ cat /etc/ntp.conf

# A very simple client-only NTP configuration.
server ntp-1.cede.psu.edu
restrict 146.186.218.60
server timeserver1.upenn.edu
restrict 128.91.2.13
server clock.psu.edu
restrict 128.118.25.3
driftfile /etc/ntp/drift
authenticate no
```

STEP 3:

Create entries in the /etc/ntp/step-tickers file. Pick a server that is close to you for the initial time set on boot-up. Again, this will keep the ntpd daemon from entering panic mode on startup.

```      \$ cat /etc/ntp/step-tickers

timeserver1.upenn.edu
clock.psu.edu

```

Above, two entries are shown in this file.

STEP 4:

Start or restart the ntpd program. You will need to do this as root.

```      # /etc/init.d/ntpd restart
Shutting down ntpd:                                        [  OK  ]
ntpd: Synchronizing with time server:                      [  OK  ]
Starting ntpd:                                             [  OK  ]
```

Note, NTP uses UDP port 123. The ntpd script that comes with red Hat will open this port, both source port 123 and destination port 123, using the following command.

```iptables -D RH-Lokkit-0-50-INPUT -m udp -p udp -s \$server/32  --sport 123 -d 0/0 --dport 123 -j ACCEPT
```

Special note, the above change is not needed in Fedora Core 3.

STEP 5:

Check that ntpd is operating correctly with the ntpq command as follows

```      \$ ntpq -np

remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
*146.186.218.60  204.123.2.5      2 u  613 1024  377   23.953   -5.935   2.263
+128.91.2.13     128.4.40.12      3 u  180 1024  377   11.191   -4.330   1.377
-128.182.58.100  192.5.41.41      2 u  540 1024  377   20.872   15.298   1.507
+128.118.25.3    128.118.25.12    2 u  137 1024  377   26.207   -5.419   0.561
```

You should be getting values for all fields. If several of the columns are zero, and jitter is very high, say 4000, then, NTP is not working correctly. But give it a few minutes. You need a few minutes on DSL or cable for enough times stamps to be sent and received.

The following shows a problem.

```    \$ ntpq -pn

remote refid st t when poll reach delay offset jitter
===================================================
tock.usno.navy 0.0.0.0 16 u - 64 0 0.000 0.000 4000.00
```
Setting Up and Using NTP From Source.

STEP 1:

```      \$ wget http://www.eecis.udel.edu/~ntp/ntp_spool/ntp4/ntp-4.2.0.tar.gz
\$ tar -xzvf ntp-4.2.0.tar.gz
\$ cd ntp-4.2.0
\$ ./configure
\$ make
\$ su -
\$ make install
```

STEP 2:

Add entries to /etc/ntp.conf using 3 or 4 of the closest stratum 2 servers near you. These servers can be found in the following file: http://www.eecis.udel.edu/~mills/ntp/clock2b.html

```     \$ cat /etc/ntp.conf

# A very simple client-only NTP configuration.
server ntp-1.cede.psu.edu
restrict 146.186.218.60
server timeserver1.upenn.edu
restrict 128.91.2.13
server fuzz.psc.edu
restrict 128.182.58.100
server clock.psu.edu
restrict 128.118.25.3
driftfile /etc/ntp/drift
authenticate no
```

STEP 3:

Since NTP uses UDP port 123 for both destination and source, firewall adjustments may be necessary. Here is an example of opening the 123 port for source and destination on each server above.

``` \$ iptables -A INPUT -m udp -p udp -s 146.186.218.60/32  --sport 123 -d 0/0 --dport 123 -j ACCEPT
\$ iptables -A INPUT -m udp -p udp -s 128.92.2.13/32  --sport 123 -d 0/0 --dport 123 -j ACCEPT
\$ iptables -A INPUT -m udp -p udp -s 128.182.58.100/32  --sport 123 -d 0/0 --dport 123 -j ACCEPT
\$ iptables -A INPUT -m udp -p udp -s 128.118.25.3/32  --sport 123 -d 0/0 --dport 123 -j ACCEPT
```

STEP 4:

Unlike the red Hat installation, the source install does not use /etc/ntp/step-tickers for the initial time set. So you will need to initialize the time. It has to be within 1000 seconds, about 16 minutes or the ntpd daemon will enter panic mode and exit.

To manually set the time, enter the following command,as root, with your chosen Time Server. Note, timeserver1.upenn.edu is shown here.

```      \$ su -
# ntpdate -s -b -p 8 timeserver1.upenn.edu
```

Next, start the ntp deamon.

```      # /usr/sbin/ntpd

```

Everything OK?

Run the following command. You should be able to run it under any account, and running it as root is not necessary.

```      \$  /usr/sbin/ntpq -crv
status=0654 leap_none, sync_ntp, 5 events, event_peer/strat_chg,
version="ntpd 4.1.1c-rc1@1.836 Thu Feb 13 12:17:19 EST 2003 (1)",
processor="i686", system="Linux2.6.7-ch0", leap=00, stratum=3,
precision=-17, rootdelay=24.973, rootdispersion=62.575, peer=36276,
refid=b50.cede.psu.edu,
reftime=c4df5922.cae1deac  Tue, Aug 31 2004 16:08:02.792, poll=10,
clock=c4df5ca7.738194c0  Tue, Aug 31 2004 16:23:03.451, state=4,
offset=-76.829, frequency=-70.770, jitter=18.474, stability=0.293
```

If you look at the value for stability, which here is equal to 0.293, and frequency which is -70.770 these values tend to vary if the computer gets too hot -- the fan stops working. Or, if you are starting to get hardware problems, you may notice the values increase.

Personally, I like to keep a record of these values throughout the day by putting them in to a sqlite3 www.sqlite.org database, which the values can be compared over time. A sample script ntplog can be found in the example download.

Calculate and Observe Sunrise and Sunset.

If UTC is not adjusted by adding or subtracting leap seconds, then, the times for a sunrise and sunset would be incorrect. If the time is correct on your computer, plus you know the longitude and latitude in degrees, then, sunset will occur at the calculated time.

The following program, sunrise.c, works as follows. Note longitude is 39.95 degrees, and latitude in 75.15 degrees. If you live in the US http://www.census.gov/geo/www/tiger/latlng.txt contains a complete listing of all major cities.

``````
\$./sunrise `date "+%Y %m %d"` 39.95 75.15
Sunrise  09-24-2004  06:21:12   Sunset 09-24-2004  19:43:42
``````

Note the date must be in the format Year month day, then latitude and longitude must be specified in degrees. Convert minutes and seconds of the coordinates to degrees. Below the program is put into a batch job to calculate the next 100 days. For this current location.

``````
#!/bin/bash
#  program: next100days  Mike Chirico
#
#  This will calculate the sunrise and sunset for
#  latitude     39.95  Note must convert to degrees
#  longitude  75.15  Note must convert to degrees
lat=39.95
long=75.15
for (( i=0; i <= 100; i++))
do
./sunrise    `date -d "+\$i day" "+%Y %m %d"` \$lat \$long
done
``````

Take a look at the following sample output.

``````
\$ export TZ=EST+5EDT,M4.1.0/2,M10.5.0/2
\$ ./next100days

Sunrise  08-24-2004  06:21:12   Sunset 08-24-2004  19:43:42
Sunrise  08-25-2004  06:22:09   Sunset 08-25-2004  19:42:12
Sunrise  08-26-2004  06:23:06   Sunset 08-26-2004  19:40:41
Sunrise  08-27-2004  06:24:03   Sunset 08-27-2004  19:39:09
Sunrise  08-28-2004  06:25:00   Sunset 08-28-2004  19:37:37
Sunrise  08-29-2004  06:25:56   Sunset 08-29-2004  19:36:04
Sunrise  08-30-2004  06:26:53   Sunset 08-30-2004  19:34:31
Sunrise  08-31-2004  06:27:50   Sunset 08-31-2004  19:32:57
Sunrise  09-01-2004  06:28:46   Sunset 09-01-2004  19:31:22
Sunrise  09-02-2004  06:29:43   Sunset 09-02-2004  19:29:47
..[values omitted ]
Sunrise  10-28-2004  07:25:31   Sunset 10-28-2004  18:02:34
Sunrise  10-29-2004  07:26:38   Sunset 10-29-2004  18:01:19
Sunrise  10-30-2004  07:27:46   Sunset 10-30-2004  18:00:06
Sunrise  10-31-2004  06:28:53   Sunset 10-31-2004  16:58:54
Sunrise  11-01-2004  06:30:01   Sunset 11-01-2004  16:57:44
Sunrise  11-02-2004  06:31:10   Sunset 11-02-2004  16:56:35
``````

Compare 10-30-2004 with 10-31-2004. Sunrise is an hour earlier because daylight saving time has ended. The 5 in M10.5.0 is for the 5th week in October, in which a Sunday, 0 exists. If you do a man 3 tzset you will get the exact wording.

``````
Mm.w.d This  specifies  day  d (0 <= d <= 6) of week w (1 <= w <= 5) of
month m (1 <= m <= 12).  Week 1 is the first week in which day d
occurs and week 5 is the last week in which day d occurs.  Day 0
is a Sunday.

The time fields specify when, in the local time  currently  in  effect,
the  change  to  the  other  time  occurs.   If omitted, the default is
02:00:00.
``````

Taking a look at October 2004, the 5th week of a Sunday is the 31st. And the time change occurs in the morning.

``````
October
Su Mo Tu We Th Fr Sa
1  2
3  4  5  6  7  8  9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
``````

Building an NTP Aware Application

If you do not have any control over whether or not a local server can or is running NTP, or if there is a chance that the server does not have the correct time, then, it is still possible to get accurate time by querying an NTP Time-Server directly.

First A Close Look At The NTP TimeStamp Format.

The following link contains a description of the NTP timestamp format http://www.eecis.udel.edu/~mills/database/rfc/rfc2030.txt

Below is a description of the NTP/SNTP Version 4 message format described in the standard.

``````

1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|LI | VN  |Mode |    Stratum    |     Poll      |   Precision   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                          Root Delay                           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       Root Dispersion                         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                     Reference Identifier                      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
|                   Reference Timestamp (64)                    |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
|                   Originate Timestamp (64)                    |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
|                    Transmit Timestamp (64)                    |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                 Key Identifier (optional) (32)                |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
|                                                               |
|                 Message Digest (optional) (128)               |
|                                                               |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Reference Timestamp: This is the time at which the local clock was
last set or corrected, in 64-bit timestamp format.

Originate Timestamp: This is the time at which the request departed
the client for the server, in 64-bit timestamp format.

Receive Timestamp: This is the time at which the request arrived at
the server, in 64-bit timestamp format.

Transmit Timestamp: This is the time at which the reply departed the
server for the client, in 64-bit timestamp format.
``````

The program queryTimeServer.c prints the 4 timestamp values, by doing 3 separate queries a Time-Server. The timstamp formats must be converted from big-endian to little-endian the htonl function call. Plus seconds in the NTP time scale start in 1900. Unix and Linux define zero seconds at Jan 1st, 1970.

REFERENCES:

NTP timestamp format (RFC2030).
http://www.eecis.udel.edu/~mills/database/rfc/rfc2030.txt

US Listings Of Latitude and Longitude
http://www.census.gov/geo/www/tiger/latlng.txt

Author's articles:

How to Compile the 2.6 kernel for RedHat 9 and 8.0 and get Fedora Updates This is a step by step tutorial on how to compile the 2.6 kernel from source.

Virtual Filesystem: Building A Linux Filesystem From An Ordinary File You can take a disk file, format it as ext2, ext3, or reiser filesystem and then mount it, just like a physical drive. Yes, it then possible to read and write files to this newly mounted device. You can also copy the complete filesystem, since it is just a file, to another computer. If security is an issue, read on. This article will show you how to encrypt the filesystem, and mount it with ACL (Access Control Lists), which give you rights beyond the traditional read (r) write (w) and execute (x) for the 3 user groups file, owner and other.

Lemon Parser Generator Tutorial . This article explains how to build grammars and programs using the lemon parser, which is faster than yacc. And, unlike yacc, it is thread safe.

MySQL Tips and Tricks . A collection of essential, explicit, examples that every MySQL user should know.

Getting Email on Home Linux Box. How to configure Sendmail and Fetchmail plus a simple Procmail example.

SPECIAL THANKS:

Erik Sjolund (erik.sjolund@home.se) for pointing out changes in Fedora Core 3.

W. Lewis Harmon for pointing out NTP starts January 1, 1900 (GMT); was listed as January 1, 1990 (GMT),

Gmail on Home Linux Box using Postfix and Fetchmail If you have a Google Gmail account, you can relay mail from your home linux system. It's a good exercise in configuring Postfix with TLS and SASL. Plus, you will learn how to bring down the mail safely, using fetchmail with the "sslcertck" option.

Breaking Firewalls with OpenSSH and PuTTY If the system administrator deliberately filters out all traffic except port 22 (ssh), to a single server, it is very likely that you can still gain access other computers behind the firewall. This article shows how remote Linux and Windows users can gain access to firewalled samba, mail, and http servers. In essence, it shows how openSSH and Putty can be used as a VPN solution for your home or workplace.

Create your own custom Live Linux CD These steps will show you how to create a functioning Linux system, with the latest 2.6 kernel compiled from source, and how to integrate the BusyBox utilities including the installation of DHCP. Plus, how to compile in the OpenSSH package on this CD based system. On system boot-up a filesystem will be created and the contents from the CD will be uncompressed and completely loaded into RAM -- the CD could be removed at this point for boot-up on a second computer. The remaining functioning system will have full ssh capabilities. You can take over any PC assuming, of course, you have configured the kernel with the appropriate drivers and the PC can boot from a CD.

SQLite Tutorial This article explores the power and simplicity of sqlite3, first by starting with common commands and triggers, then the attach statement with the union operation is introduced in a way that allows multiple tables, in separate databases, to be combined as one virtual table, without the overhead of copying or moving data. Next, the simple sign function and the amazingly powerful trick of using this function in SQL select statements to solve complex queries with a single pass through the data is demonstrated, after making a brief mathematical case for how the sign function defines the absolute value and IF conditions.

Mike Chirico, a father of triplets (all girls) lives outside of Philadelphia, PA, USA. He has worked with Linux since 1996, has a Masters in Computer Science and Mathematics from Villanova University, and has worked in computer-related jobs from Wall Street to the University of Pennsylvania. His hero is Paul Erdos, a brilliant number theorist who was known for his open collaboration with others.

Mike's notes page is souptonuts. For open source consulting needs, please send an email to mchirico@comcast.net. All consulting work must include a donation to SourceForge.net.