0x26res
0x26res

Reputation: 13902

Converting number of 100 ns since 1601 to boost posix time in C++

I am receiving from a data provider timestamps that follow this specification:

number of 100 nanoseconds since 1601

I am using boost::posix_time::ptime and I would like to convert the timestamps to posix time. Is there a simple way to do that ?

Upvotes: 0

Views: 2059

Answers (2)

9dan
9dan

Reputation: 4282

number of 100 nanoseconds since 1601

It is Windows FILETIME value.

Boost.DateTime actually use Windows FILETIME for Windows platform.

Below is the relevant Boost source code that convert FILETIME to boost::posix_time::ptime:
(from boost/date_time/microsec_time_clock.hpp)

static time_type create_time(time_converter converter)
{
  winapi::file_time ft;
  winapi::get_system_time_as_file_time(ft);
  uint64_t micros = winapi::file_time_to_microseconds(ft); // it will not wrap, since ft is the current time
                                                           // and cannot be before 1970-Jan-01
  std::time_t t = static_cast<std::time_t>(micros / 1000000UL); // seconds since epoch
  // microseconds -- static casts supress warnings
  boost::uint32_t sub_sec = static_cast<boost::uint32_t>(micros % 1000000UL);

  std::tm curr;
  std::tm* curr_ptr = converter(&t, &curr);
  date_type d(curr_ptr->tm_year + 1900,
              curr_ptr->tm_mon + 1,
              curr_ptr->tm_mday);

  //The following line will adjust the fractional second tick in terms
  //of the current time system.  For example, if the time system
  //doesn't support fractional seconds then res_adjust returns 0
  //and all the fractional seconds return 0.
  int adjust = static_cast< int >(resolution_traits_type::res_adjust() / 1000000);

  time_duration_type td(curr_ptr->tm_hour,
                        curr_ptr->tm_min,
                        curr_ptr->tm_sec,
                        sub_sec * adjust);

  return time_type(d,td);
}

You can browse your Boost installation for the detailed implementation.

Upvotes: 1

Jonathan Leffler
Jonathan Leffler

Reputation: 753890

When did the switch from the Julian to Gregorian calendar occur for this system? Some countries switched before 1st January 1601; others didn't switch until much later. This will critically affect your calculation - by 11 days or so.

Since there are 107 units of 100 ns each in one second, you divide the starting number by 107 to produce the number of seconds since the reference time (the remainder is the fraction of a second). You then divide that by 86400 to give the number of days (the remainder is the time of day). Then you can compute the date from the number of days.

Since POSIX time uses 1970-01-01 00:00:00 as the reference, you may simply need to compute the correct number of seconds between 1601-01-01 00:00:00 and the POSIX epoch (as it is known), and subtract that number from the number of seconds you calculated.

Upvotes: 3

Related Questions