Windows Phone ‘LocalTimestamp’ field

I recently had a question that wasn’t easily found via Google so I figured it deserved a proper write-up. My friends know that I like to geek out on programming with dates and times and they sometimes ping me with questions. The other day a friend of mine was looking at the SMS message data he was exporting from his Windows Phone and couldn’t figure out what the value of the ‘LocalTimestamp’ field was. Here’s an example of what the SMS data looks like when exported:

You can see that the value of the LocalTimestamp field is a large integer. If you’ve worked much with dates and times you’re probably already (correctly) thinking that this value represents some number of small time increments that have elapsed since some known epoch in the past. If you haven’t worked much with dates then you might not have any idea what that value represents and be confused like my friend was. Personally I think that date and time values expressed via a public API like this should be formatted in an ISO 8601 format (e.g. 2015-10-18T09:30Z) because most people will instantly recognize that value as a date and understand how to interpret it.

Anyway, the Windows Phone SMS message format isn’t using a very “friendly” date format (probably because they’re using this value internally and didn’t bother converting it to something else when exporting it) so in order to do anything meaningful with this data we’ll probably want to convert it to a .NET DateTime type. Lucky for us performing this conversion is very easy once you know what that integer value represents. My first thought when seeing it was that it might be the DateTime.Ticks value for the date and time that the message was sent or received. The Ticks property of a DateTime instance represents “the number of 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001”. So this property uses January 1, 0001 at midnight as its epoch. If you have an integer representing the Ticks value of a DateTime you can simply pass that value into one of the available DateTime constructor overloads:

For the above example I got the ‘ticks’ value from DateTime.UtcNow.Ticks, and you might have noticed that the value there is quite a bit larger than the one in the ‘LocalTimestamp’ field of the SMS data export that we’re working with. Not surprisingly, using that LocalTimestamp value as the ‘ticks’ for a DateTime instance doesn’t yield results that make any sense, so that must not be the right approach.

As it turns out, the LocalTimestamp value is a Windows File Timestamp. Much like the DateTime.Ticks property, a Windows File Timestamp is a value representing the number of 100 nanosecond intervals that have elapsed since some epoch, but the epoch it uses is January 1st, 1601 at midnight. That ~1600 years of difference between the epochs is what gives us such a dramatic difference in tick values. You can see this all for yourself with code like this:

As of the time that I’m writing this (2015-10-18 4:25 PM Eastern US time) this code outputs 1601.0766432084 which makes perfect sense given the fact that the SMS data is now a couple of days old and there is 1601 years difference between the ticks used by the DateTime type and Windows File Timestamps.

So, how do you take a Windows File Timestamp and make it into a a DateTime instance? You could take the tick equivalent of 1601 years and add it to the Windows File Timestamp value and then pass that into a DateTime constructor, but thankfully there’s an easier way:

Note that there are two flavors of this method: one assumes that the ticks you’re passing in represent a UTC time (DateTime.FromFileTimeUtc) and the other (from the snippet above) makes no assumptions about timezone. I don’t know what time the message in this example data export was received, and I don’t own a Windows Phone to test this out, but my friend tells me that the LocalTimestamp field appeared to represent the local time from the device (which is unfortunate). As always, YMMV.

4 thoughts on “Windows Phone ‘LocalTimestamp’ field”

Comments are closed.