In C/Windows land, there are a handful of different formats for storing date and time values. Unfortunately, you often need to convert between them to get something useful done, this also means it is important to know the properties of each format. Here is a cheat sheet for the standard date/time formats with some basic information about each.
Container
Domain
Format / Notes
Min Date
Resolution
SYSTEMTIME
Win32
Struct (16 bytes)
January 1, 1601
1 millisecond
FILETIME
Offset value (64bit unsigned int)
100 nanoseconds
VT_DATE
Win32 / OLE Automation
Offset value (64bit signed float), 0.0 is December 30, 1899.
January 1, 100 (1)
500 milliseconds (2)
FAT/MS-DOS
Struct (values packed into two 16bit ints)
January 1, 1980
2 seconds
time_t
CRT
Offset value (unsigned int)
January 1, 1970
1 second
tm
Struct (36 bytes (3))
January 1, 1900
Windows Times
SystemTimeToFileTime
SystemTimeToVariantTime
FileTimeToSystemTime
FileTimeToDosDateTime
VariantTimeToSystemTime
VariantTimeToDosDateTime
DosDateTimeToFileTime
DosDateTimeToVariantTime
CRT Times
gmtime
mktime
In bridging between the CRT and Windows API sets, I've occasionally needed to convert a time_t value into something more Windows friendly. The below helper functions do just that (4).
void SystemTimeToTime_t(SYSTEMTIME *systemTime, time_t *dosTime)
{
LARGE_INTEGER jan1970FT = {0};
jan1970FT.QuadPart = 116444736000000000I64; // january 1st 1970
LARGE_INTEGER utcFT = {0};
SystemTimeToFileTime(systemTime, (FILETIME*)&utcFT);
unsigned __int64 utcDosTime = (utcFT.QuadPart - jan1970FT.QuadPart)/10000000;
*dosTime = (time_t)utcDosTime;
}
void Time_tToSystemTime(time_t dosTime, SYSTEMTIME *systemTime)
utcFT.QuadPart = ((unsigned __int64)dosTime)*10000000 + jan1970FT.QuadPart;
FileTimeToSystemTime((FILETIME*)&utcFT, systemTime);
Note: we use a hack by interpreting a FILETIME struct as a LARGE_INTEGER since the layouts match (both are designed to hold 64bits of data). The "nice" way would be to use the initial format as a temp and then convert from one to the other by copying the "low" and "high" DWORDs individually. I will also leave it as a reader exercise to do any necessary parameter validation or error checking from the Win32 API calls.
(1) In reality the year can go way into BC values, but for practical reasons some subsystems capped it at the year 100.
(2) The 500 ms resolution is according to http://msdn2.microsoft.com/en-us/library/aa393691.aspx, but since this is an IEEE floating point value, your resolution will physically be bounded by precision as it relates to your date: the further away from 0.0 you go, the less precision you will have, but for normal dates, having a precision of 1 millisecond is physically possible.
(3) The struct consists of 9 ints, so the size will scale depending on your environment.
(4) RtlTimeToSecondsSince1970() may be what you need instead, but it is currently only available for driver projects.
Edit:
Here are a couple of "net" friendly apis when dealing with various network protocols:
WinHttpTimeToSystemTime, WinHttpTimeFromSystemTime