July 13th, 2015

Generating different types of timestamps from quite a long way away

Today’s Little Program does the reverse of what we had last time. It takes a point in time and then generates timestamps in various formats.

using System;

class Program
{
 static void TryFormat(string format, Func<long> func)
 {
  try {
   long l = func();
   if ((ulong)l > 0x00000000FFFFFFFF) {
       Console.WriteLine("{0} 0x{1:X16}", format, l);
   } else {
       Console.WriteLine("{0} 0x{1:X08}", format, l);
   }
  } catch (ArgumentException) {
   Console.WriteLine("{0} - invalid", format);
  }
 }

Like last time, the Try­Format method executes the passed-in function inside a try/catch block. If the function executes successfully, then we print the result. There is a tiny bit of cleverness where we choose the output format depending on the number of bits in the result.

 static long DosDateTimeFromDateTime(DateTime value)
 {
  int result = ((value.Year - 1980) << 25) |
               (value.Month << 21) |
               (value.Day << 16) |
               (value.Hour << 11) |
               (value.Minute << 5) |
               (value.Second >> 1);
  return (uint)result;
 }

The Dos­Date­Time­From­Date­Time converts the Date­Time into a 32-bit date/time stamp in MS-DOS format. This is not quite correct because MS-DOS format date/time stamps are in local time, but we are not converting the incoming Date­Time to local time. It’s up to you to understand what’s going on.

 public static void Main(string[] args)
 {
  int[] parts = new int[7];
  for (int i = 0; i < 7; i++) {
   parts[i] = args.Length > i ? int.Parse(args[i]) : 0;
  }

  DateTime value = new DateTime(parts[0], parts[1], parts[2],
                                parts[3], parts[4], parts[5],
                                parts[6], DateTimeKind.Utc);

  Console.WriteLine("Timestamp {0} UTC", value);

  TryFormat("Unix time",
    () => value.ToFileTimeUtc() / 10000000 - 11644473600);
  TryFormat("UTC FILETIME",
    () => value.ToFileTimeUtc());
  TryFormat("Binary DateTime",
    () => value.ToBinary());
  TryFormat("MS-DOS Date/Time",
    () => DosDateTimeFromDateTime(value));
  TryFormat("OLE Date/Time",
    () => BitConverter.DoubleToInt64Bits(value.ToOADate()));
 }
}

The parameters on the command line are the year, month, day, hour, minute, second, and millisecond; any omitted parameters are taken as zero. We create a UTC Date­Time from it, and then try to convert that Date­Time into the other formats.

Topics
Code

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

0 comments

Discussion are closed.