Click here to Skip to main content
16,016,227 members
Articles / Programming Languages / Objective C

SystemTime to VariantTime with Milliseconds

Rate me:
Please Sign up or sign in to vote.
4.06/5 (8 votes)
9 Feb 20073 min read 85.6K   1.8K   18   10
Enhanced system time / variant time conversion with milliseconds

Image 1

Introduction

When you use the Microsoft Automation function VariantTimeToSystemTime to convert variant time to system time and the SystemTimeToVariantTime to convert system time to variant time, the milliseconds value appears as zero or is ignored. This is a known issue documented in MSDN knowledge base, under ID Q297463. However, many times, ignoring milliseconds is not a option. Two simple functions wrapping the original API functions can be used to convert SystemTime to VariantTime and vice versa without losing the millisecond information.

The sample application is just to demonstrate the use of these functions. You can type in the SystemTime entries and click convert to see the equivalent VariantTime or you can type in a VariantTime value and select conversion Type for reverse conversion and convert it back to SystemTime. Clicking on the 'GetCurrentTime' button will populate SystemTime structure from the current time on your system. The application also does some basic validations on the range of input you can specify.

Using the Code

Two functions, SystemTimeToVariantTimeWithMilliseconds and VariantTimeToSystemTimeWithMilliseconds can replace the Microsoft Automation functions and can return the result in a similar to the original functions without losing the millisecond information.

a) SystemTimeToVariantTimeWithMilliseconds takes systemtime as the input and passes the information without millisecond information to the Microsoft Automation function. The result would be the converted variant time without milliseconds. The reason for not passing the millisecond information to the Microsoft Automation function is that the function automatically rounds off the value to the nearest second, which we don't want. We then add the variant portion for the millisecond.

A variant time is stored as an 8-byte real value (double), representing a date between January 1, 1753 and December 31, 2078, inclusive. The value 2.0 represents January 1, 1900; 3.0 represents January 2, 1900, and so on. Adding 1 to the value increments the date by a day. The fractional part of the value represents the time of day. Therefore, 2.5 represents noon on January 1, 1900; 3.25 represents 6:00 A.M. on January 2, 1900, and so on. So, 0.5 represents 12 hours i.e. 12*60*60 seconds, hence 1 second = 0.5/(12*60*60) = .0000115740740740

C++
BOOL CSysTimeConversionDlg::SystemTimeToVariantTimeWithMilliseconds 
                 (/*input*/ SYSTEMTIME st, /*output*/double *dVariantTime)
{
    BOOL retVal = TRUE;

    WORD wMilliSeconds = st.wMilliseconds; // save the milli second 
                                           // information
    st.wMilliseconds = 0; // pass 0 milliseconds to the function and get  
                          // the converted value without milliseconds
    double dWithoutms;
    retVal = SystemTimeToVariantTime(&st, &dWithoutms) ;

    // manually convert the millisecond information into variant 
    // fraction and add it to system converted value
    double OneMilliSecond = ONETHOUSANDMILLISECONDS/1000 ;
    *dVariantTime = dWithoutms + (OneMilliSecond * wMilliSeconds);

    return retVal;
}

b) VariantTimeToSystemTimeWithMilliseconds takes in the variant time and calculates each component of SYSTEMTIME individually down to the milliseconds and thus will have the precious millisecond information. We start with using the Microsoft Automation function VariantTimeToSystemTime to give us the variant time from system time. We delete 0.5 seconds from the original variant time so that we remove the rounding off problem with VariantTimeToSystemTime function. We then calculate each component of the systemtime from the fraction until we obtain the millisecond information. Once we have the millisecond information, we then add 0.5 second to compensate for our earlier adjustment.

C++
BOOL CSysTimeConversionDlg::VariantTimeToSystemTimeWithMilliseconds 
                  (/*input*/ double dVariantTime, /*output*/SYSTEMTIME *st)
{
    BOOL retVal = TRUE;

    double halfsecond = ONETHOUSANDMILLISECONDS / 2.0; 
    // ONETHOUSANDMILLISECONDS is equal to 0.0000115740740740

    retVal = VariantTimeToSystemTime(dVariantTime - halfsecond, st); 
    // this takes care of rounding problem with 
    // VariantTimetoSystemTime function
    if (retVal == FALSE)
    {
        return retVal;
    }

    double fraction = dVariantTime - (int) dVariantTime; 
    // extracts the fraction part

    double hours; 
    hours = fraction = (fraction - (int)fraction) * 24;

    double minutes;
    minutes = (hours - (int)hours) * 60;

    double seconds;
    seconds = (minutes - (int)minutes) * 60;

    double milliseconds;
    milliseconds = (seconds - (int)seconds) * 1000;

    milliseconds = milliseconds + 0.5; // rounding off millisecond to the 
                                       // nearest millisecond 
    if (milliseconds < 1.0 || milliseconds > 999.0) //Fractional 
                          // calculations may yield in results like
        milliseconds = 0; // 0.00001 or 999.9999 which should actually 
                          // be zero (slightly above or below limits 
                          // are actually zero)

    if (milliseconds) 
        st->wMilliseconds = (WORD) milliseconds;
    else  // if there is 0 milliseconds, then we don't have the problem !!
        retVal = VariantTimeToSystemTime(dVariantTime, st); // 

    return retVal;
}

License

This article has no explicit license attached to it, but may contain usage terms in the article text or the download files themselves. If in doubt, please contact the author via the discussion board below.

A list of licenses authors might use can be found here.


Written By
Web Developer
United States United States
I started programming some 10 years back, working on on a 386 PC writing some embedded systems code, but soon moved on into application programming. I have worked on Microsoft environment since the beginning of MSDOS and Windows 3.1. I have had several years of hands on experience with C++, Win32, MFC, ATL COM, Visual Basic and C#
I work IBM Global Services and currently living in Lake Forest California.

Occupation : Software design and development

Other than my work, my special areas of interest is Computer hardware, photography, music and movies.

Comments and Discussions

 
QuestionLicensing Pin
Member 1286863124-Sep-18 21:25
Member 1286863124-Sep-18 21:25 
GeneralMy vote of 5 Pin
Member 68306924-Oct-14 6:43
Member 68306924-Oct-14 6:43 
GeneralMy vote of 5 Pin
Siriwat.Suananpornpanit15-Jun-11 20:14
Siriwat.Suananpornpanit15-Jun-11 20:14 
GeneralRounding problem when miiliseconds is 999 Pin
sbt@ismobile14-Oct-09 21:59
sbt@ismobile14-Oct-09 21:59 
GeneralRe: Rounding problem when miiliseconds is 999 Pin
skarapanahalli21-Nov-11 2:22
skarapanahalli21-Nov-11 2:22 
GeneralBasically and practically error-prone conversion Pin
ehaerim11-Jan-14 13:34
ehaerim11-Jan-14 13:34 
I tried to make VariantTimeToSystemTimeWithMilliseconds work for any case, but I realized it is not possible. Simply this article tries to accomplish what is impossible.
That must be the reason why Microsoft's VariantTimeToSystemTime ignores milliseconds part.
Otherwise, they would have done it already.

So, my conclusion is that VariantTimeToSystemTimeWithMilliseconds is NOT reliable.

Anyway, no matter how I fix/modify the code, there always happened cases that failed to revert variant time to system time. I tested with the code below.
If anyone can make VariantTimeToSystemTimeWithMilliseconds to pass this test, just let me know.
But I doubt.

C++
//for (WORD wYear            = 1601; wYear   < 2100 ; wYear++)
//  for (WORD wMonth         =    1; wMonth  <=  12 ; wMonth++)
//      for (WORD wDay         =    1; wDay    <=  31 ; wDay++)
for (WORD wYear            = 1899; wYear   < 2100 ; wYear++)
    for (WORD wMonth         =   12; wMonth  <=  12 ; wMonth++)
        for (WORD wDay         =   30; wDay    <=  31 ; wDay++)
            for (WORD wHour      =    0; wHour   <   24 ; wHour++)
                for (WORD wMinute  =    0; wMinute <   60 ; wMinute++)
                    for (WORD wSecond =   0; wSecond <   60 ; wSecond++)
                        for (WORD wMilliseconds = 0; wMilliseconds < 1000 ; wMilliseconds++)
                        {
                            st.wYear = wYear;
                            st.wMonth = wMonth;
                            st.wDay = wDay;
                            st.wHour = wHour;
                            st.wMinute = wMinute;
                            st.wSecond = wSecond;
                            st.wMilliseconds = wMilliseconds;
                            st_orig = st;
                            SystemTimeToVariantTimeWithMilliseconds(st, &vt);
                            VariantTimeToSystemTimeWithMilliseconds(vt, &st);
                            if (st_orig.wMilliseconds != st.wMilliseconds || st_orig.wSecond != st.wSecond || st_orig.wMinute != st.wMinute || st_orig.wHour != st.wHour ||
                                    st_orig.wDay != st.wDay || st_orig.wMonth != st.wMonth || st_orig.wYear != st.wYear)
                            {
                                TRACE(_T("%04d/%02d/%02d-%02d:%02d:%02d.%03d => %04d/%02d/%02d-%02d:%02d:%02d.%03d\n"),
                                    st_orig.wYear, st_orig.wMonth, st_orig.wDay, st_orig.wHour, st_orig.wMinute, st_orig.wSecond, st_orig.wMilliseconds,
                                    st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds
                                    );
                            }
                        }

GeneralRe: Basically and practically error-prone conversion Pin
mgampi6-Jul-14 23:20
mgampi6-Jul-14 23:20 
QuestionRange of Dates? Pin
MichP15-Feb-07 5:26
MichP15-Feb-07 5:26 
AnswerRe: Range of Dates? Pin
skydvr16-Feb-07 10:14
skydvr16-Feb-07 10:14 
GeneralRe: Range of Dates? Pin
skarapanahalli20-Feb-07 15:07
skarapanahalli20-Feb-07 15:07 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.