SetLocalTime/GetLocalTime Not the Same if Adjusting for Daylight Savings Time (234735)



The information in this article applies to:

  • Microsoft Windows 2000 Server
  • Microsoft Windows NT Server 4.0

This article was previously published under Q234735

SYMPTOMS

Calling SetLocalTime() while the "Automatically adjust clock for daylight saving changes" option is selected in the Date/Time Control Panel Tool does not set the time correctly from the point of view of the GetLocalTime() API. Here are the results from the test program: **** WITHOUT DAYLIGHT SAVINGS AUTO UPDATE ****
D:\cst>obj\i386\test1
SetLocalTime:  1998/08/30 22:59:00
GetLocalTime:  1998/08/30 22:59:00
GetSystemTime: 1998/08/31 06:59:00

GetTimeZoneInformation: 
 Bias 480  Name: Pacific Standard Time  SysDate: 00/10/05 02:00:00  Bias: 0
 User_Shared_Data bias: 00000043 0e234000


SetLocalTime:  1998/12/29 22:59:00
GetLocalTime:  1998/12/29 22:59:00
GetSystemTime: 1998/12/30 06:59:00

GetTimeZoneInformation: 
 Bias 480  Name: Pacific Standard Time  SysDate: 00/10/05 02:00:00  Bias: 0
 User_Shared_Data bias: 00000043 0e234000


D:\cst>time /t 
10:59p
				
**** WITH DAYLIGHT SAVINGS AUTO UPDATE ****
D:\cst>obj\i386\test1
SetLocalTime:  1998/08/30 22:59:00
GetLocalTime:  1998/08/30 23:59:00     <<<<<<<<<<<<<   THIS  IS OFF BY AN HOUR
GetSystemTime: 1998/08/31 06:59:00

GetTimeZoneInformation: 
 Bias 480  Name: Pacific Daylight Time  SysDate: 00/04/01 02:00:00  Bias: -60
 User_Shared_Data bias: 0000003a ac5ed800


SetLocalTime:  1998/12/29 22:59:00
GetLocalTime:  1998/12/29 21:59:00            <<<<<<<<<<<<<   THIS  IS OFF BY AN HOUR
GetSystemTime: 1998/12/30 05:59:00

GetTimeZoneInformation: 
 Bias 480  Name: Pacific Standard Time  SysDate: 00/10/05 02:00:00  Bias: 0
 User_Shared_Data bias: 00000043 0e234000


D:\cst>time /t 
 9:59p
				
Here is the test program: (also see attached files)
// time zone test

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <sys\timeb.h>
#include <windows.h>
#include <process.h>
#include <errno.h>
#include <process.h>


#define BIAS1 ( *((DWORD*)0x7FFe0020) )
#define BIAS2 ( *((DWORD*)0x7FFe0024) )

CHAR buf[200];   // message buffer

VOID FormatSt( SYSTEMTIME st, CHAR* buf)
{
    sprintf(buf,"%02d/%02d/%02d %02d:%02d:%02d",
        st.wYear, st.wMonth, st.wDay,
        st.wHour, st.wMinute, st.wSecond );
}

VOID PrintTZInfo()
{
    TIME_ZONE_INFORMATION tzi;
    DWORD dwSta;

    dwSta= GetTimeZoneInformation( &tzi );
   
    printf("GetTimeZoneInformation: \n ");
    switch( dwSta )
    {
        case TIME_ZONE_ID_UNKNOWN:
            printf("returned TIME_ZONE_ID_UNKNOWN\n");
            break;

        case TIME_ZONE_ID_STANDARD:
            FormatSt( tzi.StandardDate, buf );
            printf("Bias %d  Name: %S  SysDate: %s  Bias: %d\n",
                   tzi.Bias, tzi.StandardName, buf, tzi.StandardBias );
            break;

        case TIME_ZONE_ID_DAYLIGHT:
            FormatSt( tzi.DaylightDate, buf );
            printf("Bias %d  Name: %S  SysDate: %s  Bias: %d\n",
                   tzi.Bias, tzi.DaylightName, buf, tzi.DaylightBias );
            break;

        default:
            printf("returned undoced status: %d",dwSta);
            break;
    }
    printf(" User_Shared_Data bias: %08x %08x\n\n",BIAS2, BIAS1 );
}

VOID TstSetTime( int year, int mon, int day, int hour, int minute, int sec)
{
    SYSTEMTIME st,tst;
    BOOL bSta;

    st.wYear=  year;
    st.wMonth= mon;
    st.wDay=   day;
    st.wHour=  hour;
    st.wMinute= minute;
    st.wSecond= sec;

    st.wDayOfWeek= 0;
    st.wMilliseconds= 0;

    bSta= SetLocalTime( &st );

    if( bSta == FALSE )
    {
        FormatSt( st, buf);
        printf("Failed to set date/time: %s\n",buf);
    }
    else
    {
        FormatSt( st, buf);
        printf("SetLocalTime:  %s\n",buf);

        GetLocalTime( &tst );
        FormatSt( tst, buf);
        printf("GetLocalTime:  %s\n", buf);

        GetSystemTime( &tst );
        FormatSt( tst, buf );
        printf("GetSystemTime: %s\n", buf);
    }
    printf("\n");

}

VOID PrintTime( CHAR* msg )
{
    SYSTEMTIME st;

    GetLocalTime( &st );

    FormatSt( st, (CHAR*) buf );

    printf("%s %s\n", msg, buf);

}

int _cdecl  main(int argc, char** argv)
{

    // pick date in savings time

    TstSetTime( 1998, 8, 30, 22, 59, 0 );
    PrintTZInfo();

    // pick date outside of savings time

    printf("\n");
    TstSetTime( 1998, 12, 29, 22, 59, 0 );
    PrintTZInfo();

    return(0);
}

				

CAUSE

This issue occurs when you call SetLocalTime. Your passed in time is converted to UTC using the timezone bias in effect at the time of the call, and then SetSystemTime is called. This algorithm causes the behavior you are seeing. Windows NT has worked this way since its first release (Windows NT 3.1) and cannot be changed.

This behavior is different from Windows 95/98, but we cannot change it without the risk of breaking some programs. In Windows NT, if the caller does not adjust the time, the API will have to be called twice to get the intended results. If the caller adjusts before calling, then only once will do. On Windows 95/98, only one call needs to be made.

RESOLUTION

To work around this issue, call SetLocalTime() twice in a row. The first call changes you to the correct DST setting, the second call sets the time.

STATUS

This behavior is by design.

Modification Type:MajorLast Reviewed:10/9/2002
Keywords:kbbug kbProgramming KB234735