下次如何调整时钟以进行夏令时调整?

时间:2014-03-23 23:37:27

标签: c++ c windows winapi dst

我很好奇,如果有任何方法可以找到下一次夏令时调整的UTC日期/时间吗?

类似于Windows报告的内容(见带圆圈标记):

enter image description here

4 个答案:

答案 0 :(得分:3)

此信息在Windows中由EnumDynamicTimeZoneInformation函数提供。

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

答案 1 :(得分:2)

有一个包含代码和数据的数据库: http://www.iana.org/time-zones

答案 2 :(得分:1)

我认为没有针对此的特定API。我只会使用localtime(C ++)或time(C)中的mktime(可能是<ctime><time.h>)进行二分搜索。

基本方法是一次扫描三个月,直到翻转返回的数据结构中的tm_isdst标志。然后,您可以在最后两个日期之间开始二进制搜索,以确切知道它何时翻转。

有关参考资料,请参阅http://www.cplusplus.com/reference/ctime/tm/

答案 3 :(得分:1)

感谢您的所有回复。而且,是的,我确实在询问有关Windows的WinAPI。

我做了更多的研究,并提出了以下方法来做我想要的。它使用C ++和MFC的COleDateTime来简化日期/时间计算。除此之外,它只是C ++和WinAPIs。请检查我是否正确理解了DYNAMIC_TIME_ZONE_INFORMATION的文档。这是代码:

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。请抓住UTC时间的请求。据我所知,在这种情况下处理当地时间比较容易。