Convert boost::posix_time::ptime to Windows FILETIME

When writing platform independent libraries at work, I use boost posix_time as the primary mechanism to generate timestamps. But when integrating the platform independent libraries to Windows world, the interface requires everything to be converted Windows FILETIME.

Recall, Windows FILETIME is a 64 bit structure that represents the number of 100-nanosecond intervals since January 1, 1601 (UTC).

Boost posix_time library has an API called from_ftime<ptime>(FILETIME ft), where it can create a ptime object from a Windows FILETIME.

Strangely, it’s counterpart does not exist. In other word, there is no to_ftime.

Code

I really dislike writing this type of basic time conversion routine. It has probably been done before, and I am probably reinventing the wheel (a common disease in my profession).

Believe it or not, I could not find a solution online. At least, I found out I am not the first person to want to do this.

Anyway, here’s one way to do it.

#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/gregorian/gregorian.hpp>
#include <windows.h>
#include <boost/cstdint.hpp>

FILETIME PtimeToFileTime(boost::posix_time::ptime const &pt)
{
	// extract the date from boost::posix_time to SYSTEMTIME
	SYSTEMTIME st;
	boost::gregorian::date::ymd_type ymd = pt.date().year_month_day();

	st.wYear = ymd.year;
	st.wMonth = ymd.month;
	st.wDay = ymd.day;
	st.wDayOfWeek = pt.date().day_of_week();

	// Now extract the hour/min/second field from time_duration
	boost::posix_time::time_duration td = pt.time_of_day();
	st.wHour = static_cast<WORD>(td.hours());
	st.wMinute = static_cast<WORD>(td.minutes());
	st.wSecond = static_cast<WORD>(td.seconds());

	// Although ptime has a fractional second field, SYSTEMTIME millisecond
	// field is 16 bit, and will not store microsecond. We will treat this
	// field separately later.
	st.wMilliseconds = 0;

	// Convert SYSTEMTIME to FILETIME structure
	FILETIME ft;
	SystemTimeToFileTime(&st, &ft);

	// Now we are almost done. The FILETIME has date, and time. It is
	// only missing fractional second.

	// Extract the raw FILETIME into a 64 bit integer.
	boost::uint64_t _100nsSince1601 = ft.dwHighDateTime;
	_100nsSince1601 <<=32;
	_100nsSince1601 |= ft.dwLowDateTime;

	// Add in the fractional second, which is in microsecond * 10 to get
	// 100s of nanosecond
	_100nsSince1601 += td.fractional_seconds()*10;

	// Now put the time back inside filetime.
	ft.dwHighDateTime = _100nsSince1601 >> 32;
	ft.dwLowDateTime = _100nsSince1601 & 0x00000000FFFFFFFF;

	return ft;
}

And here’s how I verified it.

  1. Create a ptime object, and convert it to FILETIME with the routine above.
  2. Then use from_ftime<ptime>(FILETIME ft) to convert the generated FILETIME into another ptime object.
  3. Verify that the two ptime object is identical.
boost::posix_time::ptime now =
	boost::posix_time::microsec_clock::universal_time();

FILETIME ft = PtimeToFileTime(now);

std::cout << boost::posix_time::to_iso_extended_string(now) << std::endl;

boost::posix_time::ptime clone =
	boost::posix_time::from_ftime<boost::posix_time::ptime>(ft);

std::cout << boost::posix_time::to_iso_extended_string(clone) << std::endl;

Output:
2011-02-04T06:09:30.723805
2011-02-04T06:09:30.723805

On a side note

The routine PtimeToFileTime does not validate its input.

The year_month_day() routine could contain invalid/uninitialized fields.

SystemTimeToFileTime could fail.

I will leave that as an exercise.

3 thoughts on “Convert boost::posix_time::ptime to Windows FILETIME

  1. Alex says:

    Thanks!
    Exactly what I was looking for.
    Btw, all lines after “SystemTimeToFileTime(&st, &ft);” can be shortened to
    (boost::uint64_t&)ft += td.fractional_seconds()*10;

Leave a comment