Welcome to MSDN Blogs Sign in | Join | Help

How to recognize different types of timestamps from quite a long way away

The great thing about timestamps is that there are so many to choose from. Sometimes, while debugging (or reading incomplete documentation) you'll find a timestamp and wonder how to convert it into something readable. Here are some tips.

We will use November 26, 2002 at 7:25p PST as our sample time.

Number one: The UNIX timestamp

UNIX timestamps are in seconds since January 1, 1970 UTC. It is a 32-bit number, the only 32-bit number in common use as a timestamp.

November 26, 2002 at 7:25p PST = 0x3DE43B0C.

If it's a 32-bit value starting with "3", its probably a UNIX time. (The "3" era began in 1995 and ends in 2004.)

To convert these values to something readable, you have several choices.

The C runtime time_t value is the same as a UNIX timestamp, so you can use the ctime() function, for example.

This is the time format used by the C runtime and by the Windows NT event log.

Number two: The Win32 FILETIME

Win32 FILETIME values count 100-nanosecond intervals since January 1, 1600 UTC. It is a 64-bit number.

November 26, 2002 at 7:25p PST = 0x01C295C4:91150E00.

If it's a 64-bit value starting with "01" and a letter, it's probably a Win32 FILETIME. The "01A" era began in 1972 and the "01F" era ends in 2057.

To convert these values to something readable, you can use the FileTimeToSystemTime() function followed by GetDateFormat() and GetTimeFormat().

Number three: The CLR System.DateTime

Warning: Actual .NET content (I'm sorry). CLR System.DateTime values count 100-nanosecond intervals since January 1, 1 UTC. It is a 64-bit number. These aren't used much yet.

November 26, 2002 at 7:25p PST = 0x08C462CB:FCED3800. (? somebody check my math)

If it's a 64-bit value starting with "08" and a letter, it's probably a CLR System.DateTime. The "08A" began in 1970 and the "08F" era ends in 2056.

To convert these values to something readable, construct a System.DateTime object passing the 64-bit time value as the constructor parameter.

Number four: The DOS date/time format

The DOS date/time format is a bitmask:

               24                16                 8                 0
+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
|Y|Y|Y|Y|Y|Y|Y|M| |M|M|M|D|D|D|D|D| |h|h|h|h|h|m|m|m| |m|m|m|s|s|s|s|s|
+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
 \___________/\________/\_________/ \________/\____________/\_________/
    year        month       day      hour       minute        second
The year is stored as an offset from 1980. Seconds are stored in two-second increments. (So if the "second" value is 15, it actually represents 30 seconds.)

These values are recorded in local time.

November 26, 2002 at 7:25p PST = 0x2D7A9B20.

To convert these values to something readable, convert it to a FILETIME via DosDateTimeToFileTime, then convert the FILETIME to something readable.

Number five: OLE Automation date format

The OLE automation date format is a floating point value, counting days since midnight 30 December 1899. Hours and minutes are represented as fractional days.

Converting among these formats

Often there is no direct conversion between two formats; you will have to go through some intermediary formats.

UNIX timestamp to/from Win32 FILETIME
Converting a UNIX timestamp to a WIn32 FILETIME is described in KB article Q167297 and a scaled-down version of the article is also available in the Platform SDK. Some high school algebra will get you the reverse conversion.
FILETIME to/from SYSTEMTIME
Use FileTimeToSystemTime() and SystemTimeToFileTime().
FILETIME to/from System.DateTime
Use System.DateTime.FromFileTime() and System.DateTime.ToFileTime().
OLE date to/from System.DateTime
Use System.DateTime.FromOADate() and System.DateTime.ToOADate().
DOS date/time to/from FILETIME
Use DosDateTimeToFileTime() and FileTimeToDosDateTime().
DOS date/time to/from SYSTEMTIME
Parse it yourself.
SYSTEMTIME to/from OLE date.
Use SystemTimeToVariantTime() and VariantTimeToSystemTime(), or use VarDateFromUdate() and VarUdateFromDate().
DOS date/time to/from OLE date.
Use DosDateTimeToVariantTime() and VariantTimeToDosDateTime().

Let's see if I can draw a little chart. (Warning: Requires a VML-enabled browser, and assumes that blogx didn't eat my <html> tag, which it likes to do.)

UNIX FILETIME System.DateTime SYSTEMTIME OLE date DOS date
I'm not sure that chart actually cleared up anything.

If you allow yourself to use MFC, then there are some more conversions available.

UNIX time, FILETIME, SYSTEMTIME, or DOS date/time to OLE date format.
Use the MFC COleDateTime helper object.

I won't bother trying to add these (unidirectional) arrows to the chart above.

Brad Abrams' blog followed some of these arrows and produced a cute little formula to convert UNIX time_t directly to System.DateTime.

Other time formats

JScript's Date object constructor can construct from an integer representing milliseconds since 1970. This is the same as UNIX time, just multiplied by 1000.
Published Friday, September 05, 2003 2:23 PM by oldnewthing
Filed under:

Comments

# RE: How to recognize different types of timestamps from quite a long way away

Friday, September 05, 2003 9:37 PM by Ken
I get a different result for the 64-bit CLR System.DateTime. I suppose one reason the Win32 FILETIME starts in 1600 is to avoid the ugly switchover from the Julian to Gregorian calendars in 1582, when ten days were dropped in October. One way to calculate it without resorting to fancy formulas would be to calculate the number of days to 1-Jan-2003: 2000 years * 365.25 days/year in Julian calendar - 10 days dropped in 1582 - 3 days for leap years in Julian calendar that aren't in Gregorian since (1700, 1800, 1900) + 365 days for 2001 + 365 days for 2002 then work backwards to 26-Nov-2002: - 31 days in December - (last) 5 days in November = 731,181 days from 1-Jan-0001 The rest is pretty straightforward. PST is 8 hours behind UTC, so 19:25PST is actually "27:25": 731,181 days * 86,400 sec/day + 27 hours * 3600 sec/hour + 25 mins * 60 sec/min * 10,000,000 hundred-nanosecs/sec = 0x8c4656e:085f8e00 I cross-checked that with both a calendar object and some Julian Day formulas and they matched; but frankly I'm still not 100% sure. At least that obscure calendar knowledge: http://www.tondering.dk/claus/cal/node3.html finally came in handy.

# RE: How to recognize different types of timestamps from quite a long way away

Saturday, September 06, 2003 7:52 PM by Brad Abrams
Ah, I knew it! When I asked Raymond to start a blog a few months ago I know he'd eventually be forced into writting about managed code. ;-) Do Raymonds readers want to hear more about managed code from him?

# RE: How to recognize different types of timestamps from quite a long way away

Saturday, September 06, 2003 9:26 PM by Damit
Managed ways of interacting with Win32 UI/shell elements would be cool. :-) Or a series on "rolling your own compliant scrollbar in .NET" ?

# RE: How to recognize different types of timestamps from quite a long way away

Friday, September 12, 2003 3:31 PM by runtime
I thought I might share the following time functions that I just implemented. I had to implement these because Windows CE does not implement such rudimentary standard library functions as time(). NB: There might be a precision bug in my code because my UnixTimeFromFileTime() and UnixTimeToFileTime() functions do not produce identical roundtrip results. The low FILETIME bits are slightly different. Use at your own risk! :-) -runtime #ifdef UNDER_CE typedef unsigned long time_t; #endif // UNDER_CE void UnixTimeToSystemTime(time_t unixtime, SYSTEMTIME* systemtime) { FILETIME filetime; UnixTimeToFileTime(unixtime, &filetime); FileTimeToSystemTime(&filetime, systemtime); } void UnixTimeToFileTime(time_t unixtime, FILETIME* filetime) { LONGLONG longlong = Int32x32To64(unixtime, 10000000) + 116444736000000000; filetime->dwLowDateTime = (DWORD) longlong; filetime->dwHighDateTime = longlong >> 32; } time_t UnixTimeFromFileTime(const FILETIME* filetime) { LONGLONG longlong = filetime->dwHighDateTime; longlong <<= 32; longlong |= filetime->dwLowDateTime; longlong -= 116444736000000000; return longlong / 10000000; } time_t UnixTimeFromSystemTime(const SYSTEMTIME* systemtime) { // convert systemtime to filetime FILETIME filetime; SystemTimeToFileTime(systemtime, &filetime); // convert filetime to unixtime time_t unixtime = UnixTimeFromFileTime(&filetime); #ifdef _DEBUG { FILETIME roundtrip; UnixTimeToFileTime(unixtime, &roundtrip); assert(UnixTimeFromFileTime(&roundtrip) == unixtime); } #endif // _DEBUG return unixtime; } #ifdef UNDER_CE time_t time(time_t* out) { SYSTEMTIME systemtime; GetLocalTime(&systemtime); time_t unixtime = UnixTimeFromSystemTime(&systemtime); if (out) *out = unixtime; return unixtime; } #endif // UNDER_CE

# re: How to recognize different types of timestamps from quite a long way away

Thursday, April 22, 2004 5:36 PM by Anuj Agarwal
Here is .NET code to convert between time_t and DateTime -

public sealed class ConvertTime
{
/// <summary>
/// Private constructor to prevent the class from being instantiated.
/// </summary>
private ConvertTime() {}

private static DateTime origin = System.TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1, 0, 0, 0));

/// <summary>
/// time_t is an int representing the number of seconds since Midnight UTC 1 Jan 1970 on the Gregorian Calendar.
/// </summary>
/// <param name="time_t"></param>
/// <returns></returns>
public static DateTime ToDateTime(int time_t)
{
DateTime convertedValue = origin + new TimeSpan(time_t * TimeSpan.TicksPerSecond);
if (System.TimeZone.CurrentTimeZone.IsDaylightSavingTime(convertedValue) == true)
{
System.Globalization.DaylightTime daylightTime = System.TimeZone.CurrentTimeZone.GetDaylightChanges(convertedValue.Year);
convertedValue = convertedValue + daylightTime.Delta;
}
return convertedValue;
}

/// <summary>
/// time_t is an int representing the number of seconds since Midnight UTC 1 Jan 1970 on the Gregorian Calendar.
/// </summary>
/// <param name="time"></param>
/// <returns></returns>
public static int To_time_t(DateTime time)
{
DateTime convertedValue = time;
if (System.TimeZone.CurrentTimeZone.IsDaylightSavingTime(convertedValue) == true)
{
System.Globalization.DaylightTime daylightTime = System.TimeZone.CurrentTimeZone.GetDaylightChanges(convertedValue.Year);
convertedValue = convertedValue - daylightTime.Delta;
}
long diff = convertedValue.Ticks - origin.Ticks;
return (int)(diff / TimeSpan.TicksPerSecond);
}
}

# re: How to recognize different types of timestamps from quite a long way away

Thursday, April 22, 2004 5:45 PM by Raymond Chen
Wow, that was an awful lot of code compared to Brad's three-line function.

# DateTime.ToOADate

Thursday, October 14, 2004 7:20 AM by Daniels Blog

# Eric's Complete Guide To VT_DATE

Thursday, October 12, 2006 1:11 PM by Fabulous Adventures In Coding

I suspect that I may be the world's leading authority on bugs having to do with the OLEAUT date format, a dubious distinction at best.

# Image Header vs. File Timestamps.

Thursday, January 18, 2007 11:00 PM by Mike Stall's .NET Debugging Blog

Folks may use the term "Module Timestamp" to mean both file timestamp and image header timestamp. Although

# ???????????? &raquo; Blog ?????? &raquo; ??????TimeStamp

Sunday, August 05, 2007 7:23 AM by ???????????? » Blog ?????? » ??????TimeStamp

# I jeszcze o czasie (time_t, FILETIME, TIMESTAMP)...

Monday, December 08, 2008 2:23 PM by Wampiryczny blog

Wczoraj napisałem kilka słów o różnych timestampach zwracanych przez LogParser dla różnych formatów wejściowych. Dziś jeszcze kilka słów w tym temacie.time_t (unix time) time_t to typ danych, w którym data jest reprezentowana jako ilość se

New Comments to this post are disabled
 
Page view tracker