Using the API to perform time/date arithmetic to find relative times.

By: Christopher Moeller

Abstract: Converting SYSTEMTIME structure to FILETIME and then ULARGE_INTEGER structure to obtain relative times.

- Using the API to perform Time/Date arithmetic -

Background:
The Windows API recommends not performing arithmetic on the values from the SYSTEMTIME structure to obtain relative times. Instead, it recommends the following process:

    · Convert the SYSTEMTIME structure to a FILETIME structure.
    · Copy the resulting FILETIME structure to a ULARGE_INTEGER structure.
    · Use normal 64-bit arithmetic on the ULARGE_INTEGER value.
 

This technical document provides instructions for building a small application which demonstrates the conversion and arithmetic.

Step-by-step:
    1.  File  |  Close All
    2.  File  |  New Application
    3.  Place a three TButtons and a TMemo on the form.
    4.  Using the Object Inspector, change the captions for each button to the following:
        (Button1)    Get first time
        (Button2)    Get second time
        (Button3)    Calculate difference

    5.  Add the following private data to Unit1.h:

        //---------------------------------------------------------------------------
            // Stores second instance of time
            SYSTEMTIME systemTime1;
            FILETIME fileTime1;
            ULARGE_INTEGER uLargeIntegerTime1;

            // Stores second instance of time
            SYSTEMTIME systemTime2;
            FILETIME fileTime2;
            ULARGE_INTEGER uLargeIntegerTime2;

            // Stores results of time arithmetic
            LARGE_INTEGER uLargeIntegerTimeRESULT;
            FILETIME fileTimeRESULT;
            SYSTEMTIME systemTimeRESULT;
        //---------------------------------------------------------------------------

    6.  Now, use the following source code for corresponding TButtons in Unit1.cpp (then run it):

    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
      // Gets the FIRST local time, stores in SYSTEMTIME structure
      GetLocalTime( &systemTime1 );
    }
    //---------------------------------------------------------------------------

    void __fastcall TForm1::Button2Click(TObject *Sender)
    {
      // Gets the SECOND local time, stores in SYSTEMTIME structure
      GetLocalTime( &systemTime2 );
    }
    //---------------------------------------------------------------------------

    void __fastcall TForm1::Button3Click(TObject *Sender)
    {
      // Used for testing the result of conversions
      bool result;

      // Conversion from SYSTEMTIME structure to FILETIME structure
      result = SystemTimeToFileTime(&systemTime1, &fileTime1);
      result = SystemTimeToFileTime(&systemTime2, &fileTime2);

      // Checks if conversion failed
      if (!result) ShowMessage("First Conversion from SYSTEMTIME to FILETIME failed.");
      if (!result) ShowMessage("Second Conversion from SYSTEMTIME to FILETIME failed.");

      // Copies the FILETIME structure into the ULARGER_INTEGER structure;
      // (64-bit value for arithmetic purposes)
      uLargeIntegerTime1.LowPart        =   fileTime1.dwLowDateTime;
      uLargeIntegerTime1.HighPart       =   fileTime1.dwHighDateTime;
      uLargeIntegerTime2.LowPart        =   fileTime2.dwLowDateTime;
      uLargeIntegerTime2.HighPart       =   fileTime2.dwHighDateTime;

      // Subtracts the lower and higher parts of the ULARGE_INTEGER structure
      uLargeIntegerTimeRESULT.HighPart  =   uLargeIntegerTime2.HighPart - uLargeIntegerTime1.HighPart;
      uLargeIntegerTimeRESULT.LowPart   =   uLargeIntegerTime2.LowPart  - uLargeIntegerTime1.LowPart;

      // Converts back to FILETIME structure from ULARGE_INTEGER structure
      // Note:  Now this value has the difference, in milliseconds between the two time intervals
      fileTimeRESULT.dwLowDateTime      =   uLargeIntegerTimeRESULT.LowPart;
      fileTimeRESULT.dwHighDateTime     =   uLargeIntegerTimeRESULT.HighPart;

      // Coverts back to SYSTEMTIME structure from FILETIME structure
      // *IMPORTANT*:  This will add the number of milliseconds to the following base date: 1/1/1601
      result = FileTimeToSystemTime( &fileTimeRESULT, &systemTimeRESULT);

      // Checks if conversion failed
      if (!result) ShowMessage("Conversion from FILETIME to SYSTEMTIME failed.");
 
      // Displays SYSTEMTIME structure
      Memo1->Lines->Add("SYSTEMTIME Base Date = 1/1/1601" );
      Memo1->Lines->Add( "-------------------");
      Memo1->Lines->Add( "Year: " +AnsiString(systemTimeRESULT.wYear) );
      Memo1->Lines->Add( "Month: " +AnsiString(systemTimeRESULT.wMonth) );
      Memo1->Lines->Add( "DayOfWeek: " +AnsiString(systemTimeRESULT.wDayOfWeek) );
      Memo1->Lines->Add( "Day: " +AnsiString(systemTimeRESULT.wDay) );
      Memo1->Lines->Add( "Hour: " +AnsiString(systemTimeRESULT.wHour) );
      Memo1->Lines->Add( "Minute: " +AnsiString(systemTimeRESULT.wMinute) );
      Memo1->Lines->Add( "Second: " +AnsiString(systemTimeRESULT.wSecond) );
      Memo1->Lines->Add( "Milliseconds: " +AnsiString(systemTimeRESULT.wMilliseconds) );
      Memo1->Lines->Add( "-------------------");
    }
    //---------------------------------------------------------------------------
    /*
      Please be aware that although the code demonstrates how to convert back into
      the SYSTEMTIME structure (for display purposes), you will probably want to
      work with the value in the FILETIME structure (after the arithmetic) because this
      value merely holds the difference in milliseconds between the two time intervals.
      Once you take the extra step to convert back into the SYSTEMTIME structure,
      it adds the difference in milliseconds to the base date (1/1/1601).

      Also, if you choose to implement this code, you will probably want to evaluate which
      of the two values is earlier than the other so that you know which value to subtract from.
    */
    //---------------------------------------------------------------------------
    //  Borland Developer Support
    //---------------------------------------------------------------------------
 


Server Response from: ETNASC03