Tuesday, June 19, 2012

Conversion between NTP time and UNIX struct timeval

First, let's understand the formats:
  • A NTP timestamp consists of a 32-bit part for second and a 32-bit part for fraction second. And the unit of the fraction part is 2-32 second.
  • A UNIX Struct timeval consists of a 32-bit part for second and a 32-bit part for micro-second.
Second, let's see the meaning of NTP timestamp and UNIX struct timeval
  • A NTP timestamp is defined as the number of seconds have elapsed since Jan 1, 1900.
  • A UNIX struct timeval is defined as the number of seconds have elapsed since Jan 1, 1970.
Assume the structure of NTP is
struct ntp_time_t {
    uint32_t   second;
    uint32_t    fraction;
};

And the knowned timeval structure of UNIX is
struct timeval {
    uint32_t   tv_sec;
    uint32_t    tv_usec;
};

To convert from NTP timestamp to UNIX timeval, we need to offset the second field and
transform the  fraction part:
void convert_ntp_time_into_unix_time(struct ntp_time_t *ntp, struct timeval *unix)
{
    unix->tv_sec = ntp->second - 0x83AA7E80; // the seconds from Jan 1, 1900 to Jan 1, 1970
    unix->tv_usec = (uint32_t)( (double)ntp->fraction * 1.0e6 / (double)(1LL<<32) );
}

void convert_unix_time_into_ntp_time(struct timeval *unix, struct ntp_time_t *ntp)
{
    ntp->second = unix->tv_sec + 0x83AA7E80;
    ntp->fraction = (uint32_t)( (double)(unix->tv_usec+1) * (double)(1LL<<32) * 1.0e-6 );
}

Example:
#include <sys/time.h>
#include <stdio.h>
#include <stdint.h>

struct ntp_time_t {
    uint32_t   second;
    uint32_t    fraction;
};

void convert_ntp_time_into_unix_time(struct ntp_time_t *ntp, struct timeval *unix)
{
    unix->tv_sec = ntp->second - 0x83AA7E80; // the seconds from Jan 1, 1900 to Jan 1, 1970
    unix->tv_usec = (uint32_t)( (double)ntp->fraction * 1.0e6 / (double)(1LL<<32) );
}

void convert_unix_time_into_ntp_time(struct timeval *unix, struct ntp_time_t *ntp)
{
    ntp->second = unix->tv_sec + 0x83AA7E80;
    ntp->fraction = (uint32_t)( (double)(unix->tv_usec+1) * (double)(1LL<<32) * 1.0e-6 );
}

int main()
{
    struct ntp_time_t ntp;
    struct timeval unix;

    // get time unix time via gettimeofday
    gettimeofday(&unix, NULL);
    printf("UNIX Time: %ld %ld\n", unix.tv_sec, unix.tv_usec);

    // convert unix time to ntp time
    convert_unix_time_into_ntp_time(&unix, &ntp);
    printf("NTP Time: %ld %ld\n", ntp.second, ntp.fraction);

    // convert ntp time back to unix time to see whether they are same
    convert_ntp_time_into_unix_time(&ntp, &unix);
    printf("UNIX Time: %ld %ld\n", unix.tv_sec, unix.tv_usec);
}

Output:
UNIX Time: 1340097242 933680
NTP Time: 3549086042 4010129359
UNIX Time: 1340097242 933680

4 comments:

  1. Superb Example Thanks a Lot for Info

    ReplyDelete
  2. Thanks. I used your code to make a NTP to RFC3306 for my logging project.

    https://github.com/cameronkerrnz/libipfix/blob/master/lib/json_out.c

    ReplyDelete
  3. I'm not a developer, i always use the free online timestamp generator to create the unix timestamp.

    ReplyDelete
  4. please check ntp->fraction = (uint32_t)( (double)(unix->tv_usec+1) * (double)(1LL<<32) * 1.0e-6 ); how about this ntp->fraction = (uint32_t)( (double)(unix->tv_usec) * (double)(1LL<<32 - 1) * 1.0e-6 );

    ReplyDelete