[LEAPSECS] leapseconds, converting between GPS time (week, second) and UTC

Paul Hirose cfuhb-acdgw at earthlink.net
Mon Jan 21 18:32:27 EST 2019


On 2019-01-16 1:35, Steve Allen wrote:
> So starting 1970-01-01 DCF77 changed to broadcast Stepped Atomic Time
> (SAT) with second markers that were 1 SI second apart except on
> occasions when they were 1.2 SI seconds apart in order that the time
> markers would stay close to UT2.

For fun (?) I wrote a rudimentary C# program to convert an epoch in the 
DCF77 scale to proleptic GPS week and second. It uses the JulianDate, 
Duration, Utc, and UtcTable classes in my SofaJpl fundamental astronomy 
DLL for Windows .NET Framework.

I don't know when DCF77 inserted the step adjustments, so I created a 
small table sufficient for an example. Beginning in January the rate 
offset becomes zero. There's a step adjustment (almost .2 s) at the end 
of the month. To make the example more interesting, I set the epoch 
within that step.

Calculations are performed in the TT scale, which my DLL favors since 
it's written for astronomy. However, the JulianDate class can represent 
TAI or any unstepped time scale. Scales with step adjustments require 
the Utc class and a defining table.

This example begins with a date and time in my fake DCF77 time scale and 
converts it to TT, then GPS week and seconds, then completes a round 
trip via TT to date and time in the original scale as well as UTC in the 
rubber second era.


// Simulated DCF77 time scale. First 2 lines from the real UTC table,
// the rest phony. Step adjustment at end of 1970 Jan 31.
string dcf77TableString =
@"1966 JAN  1 =JD 2439126.5  TAI-UTC=   4.3131700 S + (MJD - 39126.) X 
0.002592 S
1968 FEB  1 =JD 2439887.5  TAI-UTC=   4.2131700 S + (MJD - 39126.) X 
0.002592 S
1970 JAN  1                TAI-UTC=   8.0000820 S + (MJD - 40587.) X 0.0 
      S
1970 FEB  1                TAI-UTC=   8.2000000 S + (MJD - 40587.) X 0.0 
      S
1970 MAR  1                TAI-UTC=   8.2000000 S + (MJD - 40587.) X 0.0 
      S";

// Load the DCF77 table from the string.
UtcTable dcf77Table = new UtcTable(
     new System.IO.StringReader(dcf77TableString));

// Load the default UTC table. This is the USNO table.
Utc.LoadTableFromFile(@"C:\Users\Stan\Documents\astro\IERS\leapSecTable.txt");

// Specify desired time display precision (the unit is 1 / hours).
double timePrecision = 3.6e5;     // .01 s

// base epoch of GPS time scale (TT)
JulianDate gpsBaseEpochTT = new Utc(1980, 1, 6, 0).TerrestrialTime;

// length of one week and the GPS cycle of 1024 weeks
Duration weekLength = new Duration(7);
Duration cycleLength = new Duration(7 * 1024);

// Set DCF77 epoch to 1970-01-31 23:59:60.05
Utc dcf77 = new Utc(1970, 1, 31, Angle.HmsToDays(23, 59, 60.05),
     false, dcf77Table);

// Display DCF77 epoch.
Console.WriteLine("{0} DCF77 epoch",
     dcf77.ToTimeFields(timePrecision));

// Convert to TT, display.
JulianDate tt = dcf77.TerrestrialTime;
Console.WriteLine("{0} TT", tt.ToTimeFields(timePrecision));

// elapsed time (possibly negative) since GPS time scale origin
Duration elapsedTime = tt - gpsBaseEpochTT;

// 1024-week cycle number (negative if before 1980)
int cycleNumber = (int)Math.Floor(elapsedTime / cycleLength);

// TT at beginning of applicable 1024-week cycle
JulianDate weekZeroTT = gpsBaseEpochTT + cycleNumber * cycleLength;

// elapsed time from start of cycle
elapsedTime = tt - weekZeroTT;

// GPS week number
int weekNumber = (int)Math.Floor(elapsedTime / weekLength);

// elapsed time from start of week
elapsedTime -= weekNumber * weekLength;

// convert elapsed time to seconds
double seconds = elapsedTime.ToSeconds();

// Show results.
Console.WriteLine("{0:d} = cycle number", cycleNumber);
Console.WriteLine("{0} = GPS week", weekNumber);
Console.WriteLine("{0:f2} seconds", seconds);

// Convert cycle number, week number, and seconds to DCF77 and UTC.

// elapsed time since start of applicable 1024-week cycle
elapsedTime = Duration.FromSeconds(seconds) + weekNumber * weekLength;

// Add the time in the whole cycles since GPS time origin
elapsedTime += cycleNumber * cycleLength;

// Convert to TT.
tt = elapsedTime + gpsBaseEpochTT;
Console.WriteLine("{0} TT", tt.ToTimeFields(timePrecision));

// Convert to epoch in the DCF77 scale.
dcf77 = new Utc(tt, dcf77Table);
Console.WriteLine("{0} DCF77 epoch", dcf77.ToTimeFields(timePrecision));

// Also convert to UTC.
dcf77 = new Utc(tt);
Console.WriteLine("{0} UTC", dcf77.ToTimeFields(timePrecision));


output:

1970-01-31T23:59:60.05 DCF77 epoch
1970-02-01T00:00:40.23 TT
-1 = cycle number
505 = GPS week
604789.05 seconds
1970-02-01T00:00:40.23 TT
1970-01-31T23:59:60.05 DCF77 epoch
1970-01-31T23:59:59.97 UTC

Hand computation confirms the TT and UTC are correct. I sure any GPS 
week calculator would reject the date as illegal, so that part I tested 
near the present time.


More information about the LEAPSECS mailing list