Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DateTime ToFileTime and ToFileTimeUtc have same output

Tags:

c#

datetime

I opened a file and used ToUniversalTime() and ToLocalTime() and output different times. However, when I use ToFileTime() and ToFileTimeUtc(), I get the same number. Why is this?

DateTime creationTime = File.GetCreationTime(@"c:\windows\setupact.log");
Console.WriteLine("utc time: " + creationTime.ToUniversalTime());
Console.WriteLine("file time: " + creationTime.ToLocalTime());
Console.WriteLine("file: " + creationTime.ToFileTime());
Console.WriteLine("utc: " + creationTime.ToFileTimeUtc());

output

utc time: 8/22/2013 2:46:17 PM

file time: 8/22/2013 7:46:17 AM

file: 130216563774628355

utc: 130216563774628355

Shouldn't file and utc be different?

like image 979
Aaron Avatar asked Mar 26 '15 17:03

Aaron


2 Answers

There's good information in the existing answers, but let me attempt a pragmatic summary:

The only time the distinction between System.DateTime.ToFileTime() and System.DateTime.ToFileTimeUtc() matters is when the instance's .Kind property equals Unspecified, i.e., if it's unclear whether the time value represents a local or UTC time.
This information was actually in an answer by Hans Passant that he himself deleted.

In other word: for System.DateTime instances whose .Kind property equals either Local or Utc (the only other possible values), System.DateTime.ToFileTime() and System.DateTime.ToFileTimeUtc() behave identically - this is what the OP experienced, because his input value was of .Kind Local (the kind returned by File.GetCreationTime()).

Note that the related System.DateTimeOffset type by design always carries explicit UTC offset information, so there's never ambiguity, which is probably why that type has only a .ToFileTime() method (and not also .ToFileTimeUtc()).

As others have noted, the return value always represents a UTC time:

  • File time values by definition, invariably represent a point in time in UTC.

  • Thus, both .ToFileTime() and .ToFileTimeUtc() create a point in time expressed as the count of 100ns intervals since midnight January 1, 1601 UTC.

To complement the OP's own example with one where .ToFileTime() and .ToFileTimeUtc() do differ in outcome:

// Create a DateTime instance with .Kind equal to Unspecified;
// use the earliest date that can be represented as a file time.
DateTime dtUnspecified = DateTime.Parse("1601-01-01");

Console.WriteLine(
    dtUnspecified.ToFileTime() + "\n" +
    dtUnspecified.ToFileTimeUtc()
);

Sample output in the US Eastern time zone:

180000000000  // 1601-01-01T05:00:00Z - 5 AM UTC
0             // 1601-01-01T00:00:00Z - midnight UTC
like image 107
mklement0 Avatar answered Oct 09 '22 12:10

mklement0


From the docs:

A Windows file time is a 64-bit value that represents the number of 100-nanosecond intervals that have elapsed since 12:00 midnight, January 1, 1601 A.D. (C.E.) Coordinated Universal Time (UTC). Windows uses a file time to record when an application creates, accesses, or writes to a file.

The number of nanoseconds since 1-1-1601 UTC, don't change no matter in which timezone you are.

From the source of the .net framwork:

public long ToFileTime() {
    // Treats the input as local if it is not specified
    return ToUniversalTime().ToFileTimeUtc();
}

public long ToFileTimeUtc() {
    // Treats the input as universal if it is not specified
    long ticks = ((InternalKind & LocalMask) != 0) ? ToUniversalTime().InternalTicks : this.InternalTicks;
    ticks -= FileTimeOffset;
    if (ticks < 0) {
        throw new ArgumentOutOfRangeException(null, Environment.GetResourceString("ArgumentOutOfRange_FileTimeInvalid"));
    }
    return ticks;
}

So when you use ToFileTimeUtc and you have an unspecified DateTime it gives you the nanosecs since 1-1-1601, no matter what timezone it's originally from. Which could for an hour each year if the timezone has DST give you an invalid time.

like image 20
albertjan Avatar answered Oct 09 '22 12:10

albertjan