Reputation: 4251
Whats the easiest way to convert an NTP timestamp to utc. I know it's in NTP, I can convert it into any other format.
Thanks. Bob.
Upvotes: 4
Views: 20406
Reputation: 554
This works reliably, for me:
#define NTP_TIMESTAMP_DIFF (2208988800) // 1900 to 1970 in seconds
#define NTP_MAX_INT_AS_DOUBLE (4294967295.0) // Max value of frac
// take care of the endianness
reply_pkt.tx_time_sec = ntohl( reply_pkt.tx_time_sec ) ;
reply_pkt.tx_time_frac = ntohl( reply_pkt.tx_time_frac ) ;
// parse
time_t tx_time = ( time_t ) ( reply_pkt.tx_time_sec - NTP_TIMESTAMP_DIFF );
double frac = ((double)reply_pkt.tx_time_frac) / NTP_MAX_INT_AS_DOUBLE ; // 2^32 -1
struct tm *tm = gmtime(&tx_time) ;
char ts[49];
strftime(ts,48,"[%Y-%m-%d %H:%M:%S]",tm);
printf("NTP query: reply was %s\n",ts);
ntp_time_seconds = ((double)tx_time) + frac ;
Upvotes: 5
Reputation: 211
As rene pointed out the NTP timestamp is made up of an integer and a fractional part. The integer part represents the number of seconds since base time, which is 1st Jan 1900. The fractional part represents the number of fractional units (a unit is 1/((2^32)-1)) in the second.
Also, the time representation is UTC.
Therefore, if you have an NTP Timestamp of say 14236589681638796952. NTP is a 64-bit unsigned fixed-point number. We can say:
UInt64 ntpTimestamp = 14236589681638796952;
The high 32 bits are given by:
UInt32 seconds = (UInt32)((ntpTimestamp >> 32) & 0xFFFFFFFF);
And the low 32 bits are are given by:
UInt32 fraction = (UInt32)(ntpTimestamp & 0xFFFFFFFF);
The number in seconds is equal to the most significant word or in this case: seconds == 3314714339
The number of milliseconds can be calculated from the fraction using this calculation:
Int32 milliseconds = (Int32)(((Double)fraction / UInt32.MaxValue) * 1000);
Which is 12 in this case.
Thus the DateTime value is yielded from:
DateTime BaseDate = new DateTime(1900, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
DateTime dt = BaseDate.AddSeconds(seconds ).AddMilliseconds(milliseconds);
Therefore the NTP Timestamp of 14236589681638796952 is equal to the 14th Jan 2005 at 17:58:59 and 12 milliseconds UTC.
Upvotes: 21
Reputation: 100567
Try something like this? I'm not sure on the format of that 'seconds since Jan 1 1900', but you can modify as you see fit.
long ntp = 3490905600;
DateTime start = new DateTime(1900, 1, 1);
DateTime dt = start.AddSeconds(ntp);
Console.WriteLine(dt.ToString());
Console.WriteLine(dt.ToUniversalTime().ToString());
Upvotes: 1