How to recognize DNS zone scavenging availability timestamps from quite a long way away


A customer couldn't figure out how to decipher the scavenge available value that is produced by the dnscmd /zoneinfo command:

C:\> dnscmd /zoneinfo contoso.com
Zone query result:
Zone info:
    ptr                     = 0000000000327C90
    zone name               = contoso.com
    zone type               = 1
    update                  = 2
    DS integrated           = 1
    data file               = (null)
    using WINS              = 0
    using Nbstat            = 0
    aging                   = 1
        refresh interval    = 168
        no refresh          = 168
        scavenge available  = 3606130
    ...

(If you want to see what it looks like in French, here ya go.)

The customer liaison found an old article of mine on decoding timestamps but none of the tricks on that page worked.

So what is the format for the scavenge available time?

This is one of those weird custom time formats. Specifically, it is "Hours since January 1, 1601 UTC".

The FILETIME format has the same epoch, so the easiest conversion is to convert it through a FILETIME.

using System;

class Program
{
    public static void Main()
    {
        var x = 3606130;
        var y = DateTimeOffset.FromFileTime(x * 36000000000);
        System.Console.WriteLine("{0:u}", y);
    }
}

This program prints 2012-05-21 10:00:00Z, which is the scavenge time.

Bonus reading: Don't be afraid of DNS scavenging. Just be patient.

Earlier versions of this article said that the starting point was January 1, 1600 UTC. This has been corrected.

Comments (12)
  1. Kelly Corcoran says:

    Obligatory Monty Python response...

    Number one: the larch!

  2. Karellen says:

    According to MSDN[0], the FILETIME epoch is Jan 1, 1601. But according to the comments in the bonus reading, so is the scavenge available epoch.

    [0] https://msdn.microsoft.com/en-us/library/windows/desktop/ms724284(v=vs.85).aspx

  3. Glassware says:

    I love random Monty Python references in the morning.

    So - 1582 was the first year of the Gregorian calendar, and 1601 is the first date recognized by Active Directory. I can't find anything in particular that was significant about 1600, except that it was a leap year, which is unusual. Any idea why they chose Jan 1 1600? Maybe they had internally been programming against 1601 but felt that picking a zero was a better starting point?

    https://en.wikipedia.org/wiki/1601

    1. Mark (The Other Mark) says:

      The Gregorian calendar operates on a 400-year cycle, and 1601 is the first year of the cycle that was active at the time Windows NT was being designed. In other words, it was chosen to make the math come out nicely.

      I actually know (of) a guy who has the email from Dave Cutler confirming this- https://blogs.msdn.microsoft.com/b/oldnewthing/archive/2009/03/06/9461176.aspx

      :-)

    2. Myria says:

      The period of the Gregorian calendar is 400 years. Thus, in computing things like leap years and days of the week, you only have to determine the answer modulo 400 years.

      Also, every 400 years is a leap year whose year is 0 mod 100; the other 3 century ends are not leap years. By aligning to--or immediately after--the special year, it makes these calculations simpler. 1601 is the first year after a special year, 1600. 1601 also begins the 400-year period in which Windows NT's creation resides.

      Consider the UNIX way of handling time, seconds since 1970-01-01: your code has to handle the fact that 30 years into your period (2000) is an exception to the rule. With 1601 as the epoch, the exception at 2000 is the last year of the period, making checking for it a simple "greater than" check.

      1. Myria says:

        An additional comment: The optimal choice for epoch is March 1, not January 1, making the special part of the epoch a single day right at the end. This would be really confusing, so human elements probably resulted in January 1.

      2. Karellen says:

        "By aligning to–or immediately after–the special year, it makes these calculations simpler."

        How? I don't get it.

        1600 isn't particularly special - it follows the same rules as all the other 0-mod-400 years, like 2000, 2400, 2800, etc... 2000 isn't an exception to "the rule", it follows the part of the rules that *all* 0-mod-400 years are leap years.

        You are aware that FILETIME and Windows system time is valid up to around AD 30,000, and that Unix time (using a 64-bit time_t, which most of them are these days) doesn't wrap until AD 292,277,026,596, right?

        1. Kevin says:

          There is no particular requirement that the 400 year Gregorian cycle begin or end with a century leap year. It does contain exactly one century leap year, so there is a certain elegance to this approach. However, it makes just as much sense to say a 400 year cycle began in 1582 because that's the first year in which it was observed, in any number of later years depending on your locale settings (yuck!), or *on October 15* of 1582 because that's the first *day* on which the Gregorian calendar was historically observed (and nobody said the cycle begins on January 1). You could also say a cycle began last Thursday, just because.

          Having said all that, you *want* the cycle to begin right after a century leap year, so that you don't have to convert your timestamp into a human-readable year just to calculate when the next century leap year falls.

          As for Unix time, by the year 30,000 AD, it is likely significant amounts of what we currently consider modern hardware and software will no longer exist or no longer be used.

          1. Karellen says:

            Note that Windows doesn't follow the actual Gregorian calendar into the past, but instead uses the Proleptic Gregorian Calendar[0] instead, where 1582 is just another date. Also, the year also always begins on Jan 1st, rather than sometime in March or even April as it sometimes did (depending on where you lived), and the day always begins at midnight, rather than at noon as it sometimes did.

            > you *want* the cycle to begin right after a century leap year, so that you don’t have to convert your timestamp into a human-readable year just to calculate when the next century leap year falls.

            Huh?

            [0] https://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar

        2. Evan says:

          > You are aware that FILETIME and Windows system time is valid up to around AD 30,000, and that Unix time doesn’t wrap until AD 292,277,026,596, right?

          Apparently Unix thinks things can't happen on a sub-second granularity. :-)

          (I did check and at least ext3 stores sub-seconds in its timestamps, so apparently it's not using just a time_t. Not sure what it's using -- but note that either it'll be more than 64 bits or will have basically the same range as FILETIME.)

          1. Karellen says:

            Unix also has "struct timespec" as used by clock_gettime(2)[0] and others, which has nanosecond granularity and uses a time_t for the non-subsecond part of the time.

            [0] http://man7.org/linux/man-pages/man2/clock_gettime.2.html

  4. Roger says:

    The Jan 1, 1601 thing comes from DCE. That begat MSRPC and hence this also being in Active Directory. Heck one of the companies contributing to DCE was Apollo Computer. A principle at Apollo moved to Microsoft and was instrumental in all that. When asked why he forsook the Unix world for the "enemy" Microsoft, he said that things he did at Microsoft would end up on a 100 million systems - something the Unix world didn't offer. (Also remember the days when Microsoft was only on a 100 million systems?)

Comments are closed.

Skip to main content