Microsoft KB Archive/821231

= PRB: Time Function May Return Wrong UTC Time and _Ftime Function May Return Wrong DST Flag =

Article ID: 821231

Article Last Modified on 5/12/2007

-

APPLIES TO


 * Microsoft Visual C++ 6.1
 * Microsoft Visual C++ 6.0 Service Pack 5
 * Microsoft Visual C++ .NET 2002 Standard Edition
 * Microsoft Visual C++ .NET 2003 Standard Edition

-



SYMPTOMS
When you use the time function in Visual C++, and the Daylight Saving Time (DST) flag is changed on the computer, the function may return 3600 seconds + Coordinated Universal Time (UTC). This behavior occurs when successive calls are made to the function within one minute.



CAUSE
When the DST flag is changed on the computer, the _ftime function may return an incorrect DST flag when successive calls to the _ftime function occur after one minute. This problem may occur while the time and the _ftime functions cache the DST flag. The GetTimeZoneInformation API uses a great deal of system resources and time. Therefore, the DST status is cached and is only updated when the time or the _ftime function is called again within one minute.



STATUS
This behavior is by design.



Steps to Reproduce the Behavior
  Paste the following code in Notepad:
 * 1) include 
 * 2) include 
 * 3) include 
 * 4) include 
 * 5) include 
 * 6) include 

/* * Three values of dstflag_cache */
 * 1) define MYDAYLIGHT_TIME  1
 * 2) define MYSTANDARD_TIME  0
 * 3) define MYUNKNOWN_TIME   -1

int GetDaylightSavingFlag {   int dstF = 0; TIME_ZONE_INFORMATION tzinfo; DWORD tzstate;

if ( (tzstate = GetTimeZoneInformation( &tzinfo )) != 0xFFFFFFFF ) {       /*        * Must be very careful in determining whether DST is        * really in effect. */       if ( (tzstate == TIME_ZONE_ID_DAYLIGHT) &&                (tzinfo.DaylightDate.wMonth != 0) &&                (tzinfo.DaylightBias != 0) ) dstF= MYDAYLIGHT_TIME; else /*       * If you are not sure, assume standard time */       dstF= MYSTANDARD_TIME; }   else dstF= MYUNKNOWN_TIME; return dstF; }

void main(void) {

struct _timeb timebuffer; long t, tPrev=0; FILE *fp;

if((fp = fopen(&quot;C:\\junk.txt&quot;,&quot;wt&quot;) ) != NULL) for {       _ftime(&timebuffer); time(&t); if (t != tPrev) {                   int dst = GetDaylightSavingFlag; tPrev = t;                   fprintf(fp,&quot;time=%ld, ftime=%ld%s\n&quot;,                t,timebuffer.time, (t != timebuffer.time ? &quot;  diff&quot; : &quot;&quot;)); fprintf(fp, &quot;ftime.dstFlag = %d; my.dstFlag = %d%s\n&quot;,                timebuffer.dstflag, dst, (dst != timebuffer.dstflag ? &quot;   diff&quot; : &quot;&quot;)); fflush(fp); }       Sleep(1); }   fclose(fp); } Save the file as Sample.cpp.   Compile the earlier code at the command prompt by using the following command: cl Sample.cpp Note Perform steps 3-7 only when your computer is running Windows 2000.  In Control Panel, double-click Date/Time.</li> In the Date/Time Properties dialog box, click (GMT-07:00) Mountain Time (US & Canada) on the Time Zone tab.</li> Click to select the Automatically adjust clock for daylight saving changes check box.</li> On the Date & Time tab, set the date to 6 April 2003 under Date. (For the Mountain Time Zone, the change from Standard Time to the Daylight Saving Time occurs on this date for the year 2003) In the Time box, set the time to 1:59:55 AM.</li> At the command prompt, run Sample.exe.</li>  The output of Sample.exe (in the file C:\junk.txt) is as follows:

Visual C++ .NET
time=1049619599, ftime=1049619599 ftime.dstFlag = 0; my.dstFlag = 0 time=1049619600, ftime=1049619600 ftime.dstFlag = 0; my.dstFlag = 0 time=1049619601, ftime=1049619601 ftime.dstFlag = 0; my.dstFlag = 1   diff time=1049619602, ftime=1049619602 ftime.dstFlag = 0; my.dstFlag = 1   diff time=1049619603, ftime=1049619603 ftime.dstFlag = 0; my.dstFlag = 1   diff

Visual C++ 6.0
time=1049619598, ftime=1049619598 ftime.dstFlag = 0; my.dstFlag = 0 time=1049619599, ftime=1049619599 ftime.dstFlag = 0; my.dstFlag = 0 time=1049619600, ftime=1049619600 ftime.dstFlag = 0; my.dstFlag = 0 time=1049623200, ftime=1049619600  diff ftime.dstFlag = 0; my.dstFlag = 1   diff time=1049623201, ftime=1049619601  diff ftime.dstFlag = 0; my.dstFlag = 1   diff time=1049623202, ftime=1049619602  diff ftime.dstFlag = 0; my.dstFlag = 1   diff time=1049623203, ftime=1049619603  diff ftime.dstFlag = 0; my.dstFlag = 1   diff Note The difference in the output of Sample.exe when you compile the code with Visual C++ 6.0 and Visual C++ .NET is the change in the implementation of the time function in Visual C++ .NET. The time function implementation in Visual C++ .NET does not implement the DST flag caching. </li></ol>

To understand why the _ftime function returns an incorrect DST flag in successive calls after the Daylight Saving Time settings have changed on the computer, look at the following code. The following code is an excerpt from the implementation of the _ftime function: _CRTIMP void __cdecl _ftime (       struct _timeb *tp        ) { ...       if ( (t = (time_t)(nt_time.ft_scalar / 600000000i64))             != elapsed_minutes_cache ) {           ...        } ... } This code implements Daylight Saving Time (DST) flag caching. The DST flag is cached because the API that provides the DST status, GetTimeZoneInformation, uses a lot of system resources. When a successive call to _ftime is made within a minute, the cached DST flag is used instead of making the GetTimeZoneInformation API call. When the DST flag is changed on your computer within one minute from successive calls to the _ftime function, the erroneous cached DST flag is returned by _ftime function.

To understand why the time function returns the incorrect UTC time in successive calls after the Daylight Saving Time settings have changed on the system, look at the following code. The following code is an excerpt from the implementation of the time function in Visual C++ 6.0: time_t __cdecl time (       time_t *timeptr        ) {      ...       GetSystemTime( &gmt );

if ( (gmt.wMinute == gmt_cache.wMinute) &&            (gmt.wHour == gmt_cache.wHour) &&             (gmt.wDay == gmt_cache.wDay) &&             (gmt.wMonth == gmt_cache.wMonth) &&             (gmt.wYear == gmt_cache.wYear) ) {           dstflag = dstflag_cache; }       else {           if ( (tzstate = GetTimeZoneInformation( &tzinfo )) != 0xFFFFFFFF ) {               ...            }            ...        }                                tim = __loctotime_t( (int)loct.wYear,                             (int)loct.wMonth,                             (int)loct.wDay,                             (int)loct.wHour,                             (int)loct.wMinute,                             (int)loct.wSecond,                             dstflag ); ... } This is similar to the code for the _ftime function. DST flag caching is implemented to prevent the overhead of calling the GetTimeZoneInformation API. When a successive call is made to the time function within one minute, the DST flag that is stored in the cache is used instead of getting the flag from the GetTimeZoneInformation function. When the DST flag is changed on the computer within the one minute between successive time function calls, the erroneous cached DST flag is passed to the __loctotime_t function. The excerpt of the __loctotime_t function code that returns the incorrect UTC time is as follows: time_t __cdecl __loctotime_t (       int yr,         /* 0 based */        int mo,         /* 1 based */        int dy,         /* 1 based */        int hr,        int mn,        int sc,        int dstflag ) {   ...    if ( (dstflag == 1) || ((dstflag == -1) && _daylight && _isindst(&tb)) ) tmptim += _dstbias; ... } Because the DST flag that is passed in the time function to the __loctotime_t function is incorrect, the line of code (that is shown earlier in this article) in the __loctotime_t function is never run. This line corrects the time that is returned when the DST flag is set on the computer.

The problem with the time function is only found in Visual C++ 6.0 and does not appear in Visual C++ .NET. The time function returns the correct value in Visual C++ .NET because the time function does not cache the DST flag in Visual C++ .NET.

<div class="references_section">