Announcement

Collapse
No announcement yet.

Code to check Windows lower date bound

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Code to check Windows lower date bound

    [PBDLL 60]

    Hi fellows,
    The rumour is widely spread: Windows should track date and time from January 1, 1601 in nanoseconds UTC.

    Well, it is true. I've checked it, using Julian Day Number calculations to find the number of days elapsed. Believe me or not, these days represent exact the same number of (nano)seconds as found in Windows' FILETIME-structure.

    My code is posted in the source code section.

    Egbert Zijlema, journalist and programmer (zijlema at basicguru dot eu)
    http://zijlema.basicguru.eu
    *** Opinions expressed here are not necessarily untrue ***

  • #2
    Egbert --

    Unless I missed something in your code, I think you need to add a factor of 100 somewhere. A FileTime structure is the number of 100-nanosecond ticks since 1601, not the number of nanoseconds.

    Also, you'll probably find this API function very useful:

    Code:
    DECLARE FUNCTION CoFileTimeNow LIB "OLE32.DLL" ALIAS "CoFileTimeNow" (qFileTime AS ANY) AS LONG
    CoFileTimeNow returns a GMT-based current-time FileTime value directly, without using a SystemTime structure. You can use either a QUAD variable or your UNION structure. The function does not actually produce a "return value", it places the current date/time in the qFileTime variable or structure.

    Even though it is located in OLE32.DLL it is not necessary to initialize OLE to use CoFileTimeNow. It works on all versions of Windows.

    HTH.

    -- Eric


    ------------------
    Perfect Sync: Perfect Sync Development Tools
    Email: mailto:[email protected][email protected]</A>

    "Not my circus, not my monkeys."

    Comment


    • #3
      Eric,

      You are right in respect with the way I wrote it down, but in my code (see: source code forum) my computation is correct: I divide by 10,000,000 instead of 1 billion. The correct discription should be (imho): "100-nanoseconds intervals".

      I've checked the API-call, you mentioned. Did not find anything about it in Win32.hlp nor in PBDLL60's API-declarations. However on-line (see: Microsoft's on-line help file) the function is properly explained.

      One final question: what does the ANY type do? Why not use QUAD here, simply because the result will be a quad integer anyhow. The ANY type is not explained in detail in PBDLL60 (help file). It is mentioned as a 'valid' type, but what is its purpose?

      ------------------




      [This message has been edited by Egbert Zijlema (edited May 25, 2000).]

      Egbert Zijlema, journalist and programmer (zijlema at basicguru dot eu)
      http://zijlema.basicguru.eu
      *** Opinions expressed here are not necessarily untrue ***

      Comment


      • #4
        Egbert --

        AS ANY can be used in a DECLARE statement to tell the compiler "accept a pointer to any type of data for this parameter". I used it so that you could pass either a QUAD or a FILETIME structure to CoFileTimeNow without the compiler objecting. ANY is a little "sloppy" but it is useful in much the same way that a UNION is useful... one "object" that does more than one thing. In my own programs I do use AS QUAD in the CoFileTimeNow declaration.

        > Did not find anything about it

        See if you can find a copy of the OLE.HLP file. I don't know where I got my copy because it is in my HELP directory, where I collect help files from different sources.

        OLE.HLP contains other goodies too, like CoCreateGUID, a function that will create a 128-bit Globally Unique ID string. According to the docs, "To a very high degree of certainty, this function returns a unique value - no other invocation, on the same or any other system (networked or not), should return the same value."

        -- Eric


        ------------------
        Perfect Sync: Perfect Sync Development Tools
        Email: mailto:[email protected][email protected]</A>



        [This message has been edited by Eric Pearson (edited May 25, 2000).]
        "Not my circus, not my monkeys."

        Comment


        • #5
          Okay, folks.

          I've posted a renewed routine to the SCF, using Eric's knowledge base. With thanks to Eric.

          Regards,
          Egbert

          ------------------

          Egbert Zijlema, journalist and programmer (zijlema at basicguru dot eu)
          http://zijlema.basicguru.eu
          *** Opinions expressed here are not necessarily untrue ***

          Comment


          • #6
            BTW, FileTimes have some very nice features. Because they are "linear" they make it very easy to calculate a Julian Date. Just divide a FileTime (as a QUAD) by the number of ticks in a day, and voila! Then take that number and perform a MOD 7 operation and you've got the day of the week.

            And they are (at least theoretically) much more accurate than using a SystemTime. My NT machine only returns a different FileTime from CoFileTimeNow every millisecond, so their real-world accuracy is the same as a SystemTime, but as machines get faster and the OS gets more sophisticated, a FileTime is capable of much better accuracy.

            The API supplies functions called SystemTimeToFileTime and FileTimeToSystemTime, so I generally do all of my calculations with a FileTime, and then convert it to a SystemTime to extract the year, month...milliseconds, etc.

            -- Eric


            ------------------
            Perfect Sync: Perfect Sync Development Tools
            Email: mailto:[email protected][email protected]</A>

            "Not my circus, not my monkeys."

            Comment


            • #7
              Eric,

              Your statement is not 100% correct. The "Julian" returned by your method, differs one day from the "original" Julian formula. I mean: 1 day after synchronizing both formulas by taking the Julian Day Number for "12-31-1600" in account.

              Hence, your DayOfWeek calculation is not correct too. Testing it on May 25 (a Thursday, which is day 4) your method returned 3.

              But apart from this minor inaccuracy, your method can safely be used to count days between Gregorian calendar dates after 1600.

              Regards,
              Egbert


              ------------------

              Egbert Zijlema, journalist and programmer (zijlema at basicguru dot eu)
              http://zijlema.basicguru.eu
              *** Opinions expressed here are not necessarily untrue ***

              Comment


              • #8
                Egbert --

                Hmmm... Simple division works perfectly for me, without a 1-day offset, producing results that match the standard Julian date.

                A couple of things come to mind. Was the FileTime you tested offset from GMT to account for your local time zone? If not, you were calculating the Julain date for a GMT time and that might be a day different from your local date.

                More likely... did you perform your test after noon? If you did, and if you used floating-point division, then you'd be off by a day because of rounding. Sorry, I should have specified integer division (\ not /).

                But then again, "standard" Julian dates actually start at noon and include a fractional value indicating the time of day. But let's not go crazy!

                Since very few of my current customers keep business records going back to 1601, my programs use an MJD -- a Modified Julian Date -- that is based on 17 November 1858. It's nice because it produces a 5-digit number for all "reasonable" dates (in a business sense)... from about 1887 to 2132.

                -- Eric


                ------------------
                Perfect Sync: Perfect Sync Development Tools
                Email: mailto:[email protected][email protected]</A>



                [This message has been edited by Eric Pearson (edited May 25, 2000).]
                "Not my circus, not my monkeys."

                Comment


                • #9
                  Eric,

                  Stupid thinking. By both of us, to be frank. Integer division of (Quad)FileTime by the number of 100-nanosecs intervals for a daytime (24 * 60 * 60 * 10,000,000) will return zero for January 1, 1601. But this date is considered to be the first day of, let me call it: the 'Pearson Period'. So your formula should include "+ 1", not only to synchronize with the original Julian Date formula, but also to get the correct results from a MOD 7 operation.

                  --Egbert

                  ------------------

                  Egbert Zijlema, journalist and programmer (zijlema at basicguru dot eu)
                  http://zijlema.basicguru.eu
                  *** Opinions expressed here are not necessarily untrue ***

                  Comment


                  • #10
                    Egbert --

                    > Stupid thinking. By both of us

                    Well, you're half right. Seriously, yes, I should know better than to post things "off the cuff" without writing a test program. Here is (I hope) a definitive answer.

                    According to the "original" Julian date formula, using today's date...

                    Code:
                    DD MON YYYY HH MM SS   JULIAN DATE
                    -- --- ---- -- -- --   ---------------
                    26 May 2000 00:00:00 = 2,451,690.5      (midnight)
                    26 May 2000 12:00:00 = 2,451,691.0      (noon)
                    26 May 2000 23:59:59 = 2,451,691.49999
                    But most people (and programs) do not find a "serial date" that starts at noon to be very useful, so the value is usually rounded. Therefore the "traditional" Julian date for all of 26 May 2000 is 2,451,691.

                    This code:

                    Code:
                    DIM qTime AS LOCAL QUAD
                    CoFileTimeNow qTime
                    PRINT qTime \ 864000000000&&
                    ...yields 145,877. The difference is due to the fact that the "traditional" Julian date is based on a date in 4713 B.C.E. and Microsoft's CoFileTimeNow returns a value based on 1 January 1601.

                    So this code:

                    Code:
                    DIM qTime AS LOCAL QUAD
                    CoFileTimeNow qTime
                    PRINT (qTimeNow\%OneDay)+2305814&
                    ...can be used to obtain the "traditional" Julian date 2,451,691. And this code:

                    Code:
                    DIM qTime AS LOCAL QUAD
                    CoFileTimeNow qTime
                    PRINT (qTimeNow\%OneDay)-94187&
                    ...can be used to obtain a "Modified Julian Date" or "MJD". Using that system -- which is nearly universal in actual applications -- 26 May 2000 is day 51,690.

                    Returning to CoFileTimeNow... I guess I'll call a value derived directly from CoFileTimeNow an "MS Julian" date. I refuse to call everthing since 1601 "the Microsoft Era".

                    Since 1 January 1601 was not a Sunday, simply performing a MOD 7 operation will not produce the correct day of the week as I'd said. Use this code instead:

                    Code:
                    DIM qTime     AS LOCAL QUAD
                    DIM qMSJulian AS LOCAL QUAD
                    CoFileTimeNow qTime
                    qMSJulian = qTime \ 864000000000&&
                    PRINT "Today is day "+FORMAT$((qMSJulian+1) MOD 7)+" of the week."
                    ...to produce a day number from 0-6. Of course you can add one to the result (not by using +2 instead of +1) if you prefer to use days 1-7.

                    -- Eric

                    P.S. Here is a link to the U.S. Naval Observatory's Julian Date Calculator:

                    http://aa.usno.navy.mil/AA/data/docs/JulianDate.html

                    It's interesting to note that even this authoritative reference says "the day of the week can be obtained from the remainder of the division of the Julian date by 7" but this is apparently not correct. Doing that with today's date yields 4, not 5 as it should. Time to write them an email...
                    ------------------
                    Perfect Sync: Perfect Sync Development Tools
                    Email: mailto:[email protected][email protected]</A>



                    [This message has been edited by Eric Pearson (edited May 26, 2000).]
                    "Not my circus, not my monkeys."

                    Comment

                    Working...
                    X