How to find out the next time when the clock will be adjusted for Daylight Saving?

六眼飞鱼酱① 提交于 2021-01-27 17:26:21

问题


I'm curious, if there's any way to find out the UTC date/time when the next Daylight Saving adjustment will take place?

Something akin to what Windows reports (see circled):

enter image description here


回答1:


This information is provided in Windows by the EnumDynamicTimeZoneInformation function.

See http://msdn.microsoft.com/en-us/library/windows/desktop/hh706893%28v=vs.85%29.aspx




回答2:


There is a database that has code and data: http://www.iana.org/time-zones




回答3:


I don't think there's a specific API for this. I would just do a binary search, using localtime (and maybe time and mktime) from <ctime> (C++) or <time.h> (C).

A basic approach is to scan ahead three months at a time until the tm_isdst flag in the returned data structure is flipped. Then you can start binary searching between the last two two dates to figure out exactly when it flips.

See http://www.cplusplus.com/reference/ctime/tm/ for reference material.




回答4:


I appreciate all your replies. And, yes, indeed I was asking about a WinAPI for Windows.

I did more research and came up with the following method that does what I wanted. It uses C++ and MFC's COleDateTime for easier date/time calculations. Other than that it's just C++ and WinAPIs. Please check if I understood the documentation for the DYNAMIC_TIME_ZONE_INFORMATION correctly. Here's the code:

int GetNextDaylightSavingAdjustmentTime(SYSTEMTIME* pOutDtNextDST_Local, int* pnOutAdjustmentMin)
{
    //Get next time when DST adjustment will take place
    //'pOutDtNextDST_Local' = if not NULL, receives the (local) time when next DST adjustment will take place
    //'pnOutAdjustmentMin' = if not NULL, receives the amount of adjustment in minutes
    //RETURN:
    //      = 1 if got the time, or
    //      = 0 if DST is not used
    //      = -1 if error (check GetLastError() for info)
    int nOSError = NO_ERROR;

    //Load API dynamically (in case of Windows XP)
    BOOL (WINAPI *pfnGetDynamicTimeZoneInformation)(PDYNAMIC_TIME_ZONE_INFORMATION);
    (FARPROC&)pfnGetDynamicTimeZoneInformation =
        ::GetProcAddress(::GetModuleHandle(L"Kernel32.dll"), "GetDynamicTimeZoneInformation");

    DWORD tzID;
    SYSTEMTIME StandardDate;
    SYSTEMTIME DaylightDate;
    int nBiasDaylight;

    //Use newer API if possible
    if(pfnGetDynamicTimeZoneInformation)
    {
        DYNAMIC_TIME_ZONE_INFORMATION dtzi = {0};
        tzID = pfnGetDynamicTimeZoneInformation(&dtzi);

        StandardDate = dtzi.StandardDate;
        DaylightDate = dtzi.DaylightDate;

        nBiasDaylight = dtzi.DaylightBias;
    }
    else
    {
        //Older API
        TIME_ZONE_INFORMATION tzi = {0};
        tzID = GetTimeZoneInformation(&tzi);

        StandardDate = tzi.StandardDate;
        DaylightDate = tzi.DaylightDate;

        nBiasDaylight = tzi.DaylightBias;
    }

    int nRes = -1;
    int nAdjMins = 0;
    SYSTEMTIME stDstChange;
    memset(&stDstChange, 0, sizeof(stDstChange));

    SYSTEMTIME stDst;
    if(tzID == TIME_ZONE_ID_STANDARD ||
        tzID == TIME_ZONE_ID_DAYLIGHT)
    {
        stDst = tzID != TIME_ZONE_ID_DAYLIGHT ? DaylightDate : StandardDate;

        if(stDst.wMonth >= 1 &&
            stDst.wMonth <= 12 &&
            stDst.wDay >= 1 &&
            stDst.wDayOfWeek >= 0 &&
            stDst.wDayOfWeek <= 6)
        {
            //Get adjustment bias
            nAdjMins = tzID != TIME_ZONE_ID_DAYLIGHT ? -nBiasDaylight : nBiasDaylight;

            if(stDst.wYear == 0)
            {
                //Relative date

                SYSTEMTIME stLocal;
                ::GetLocalTime(&stLocal);

                //Begin from the 1st day of the month &
                //make sure that the date is in the future
                COleDateTime dt;
                for(int nYear = stLocal.wYear;; nYear++)
                {
                    dt.SetDateTime(nYear, stDst.wMonth, 1, stDst.wHour, stDst.wMinute, stDst.wSecond);
                    if(dt > COleDateTime::GetCurrentTime())
                        break;
                }

                int nRequiredWeek = stDst.wDay >= 1 && stDst.wDay <= 5 ? stDst.wDay : 5;

                for(int nCntDOW = 1;;)
                {
                    //0=Sunday, 1=Monday; 2=Tuesday; 3=Wednesday; 4=Thursday; 5=Friday; 6=Saturday
                    int dow = dt.GetDayOfWeek() - 1;
                    ASSERT(dow >= 0 && dow <= 6);

                    if(dow == stDst.wDayOfWeek)
                    {
                        if(nCntDOW >= nRequiredWeek)
                        {
                            //Stop
                            break;
                        }
                        else
                        {
                            nCntDOW++;
                        }
                    }

                    //Go to next day
                    dt += COleDateTimeSpan(1, 0, 0, 0);
                }

                //Convert back to system time
                if(dt.GetAsSystemTime(stDstChange))
                {
                    //Success
                    nRes = 1;
                }
                else
                {
                    //Failed
                    nOSError = ERROR_INVALID_FUNCTION;
                    ASSERT(NULL);
                }
            }
            else
            {
                //Absolute date
                stDstChange = stDst;

                nRes = 1;
            }
        }
        else
        {
            //Failed
            nOSError = ERROR_INVALID_PARAMETER;
            ASSERT(NULL);
        }
    }
    else
    {
        //DST is not used
        if(tzID == TIME_ZONE_ID_UNKNOWN)
        {
            nRes = 0;
        }
        else
        {
            //Error
            nOSError = ERROR_INVALID_DATA;
            ASSERT(NULL);
        }
    }


    if(pOutDtNextDST_Local)
        *pOutDtNextDST_Local = stDstChange;
    if(pnOutAdjustmentMin)
        *pnOutAdjustmentMin = nAdjMins;

    ::SetLastError(nOSError);
    return nRes;
}

PS. And scratch my request for the UTC time. As I learned, it is easier to deal with local time in this situation.



来源:https://stackoverflow.com/questions/22598606/how-to-find-out-the-next-time-when-the-clock-will-be-adjusted-for-daylight-savin

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!