C++ 如何确定下一次时钟何时调整为夏令时?
我很好奇,是否有任何方法可以确定下一次夏令时调整的UTC日期/时间 类似于Windows报告的内容(请参见圆圈):C++ 如何确定下一次时钟何时调整为夏令时?,c++,c,windows,winapi,dst,C++,C,Windows,Winapi,Dst,我很好奇,是否有任何方法可以确定下一次夏令时调整的UTC日期/时间 类似于Windows报告的内容(请参见圆圈): 我认为没有专门针对这一点的API。我只需要从(C++)或(C)使用localtime(可能还有time和mktime)进行二进制搜索 一种基本方法是一次向前扫描三个月,直到返回的数据结构中的tm_isdst标志被翻转。然后,您可以在最后两个日期之间开始二进制搜索,以准确确定它何时翻转 有关参考资料,请参阅。此信息在Windows中由EnumDynamicTimeZoneInform
我认为没有专门针对这一点的API。我只需要从
(C++)或
(C)使用localtime
(可能还有time
和mktime
)进行二进制搜索
一种基本方法是一次向前扫描三个月,直到返回的数据结构中的tm_isdst
标志被翻转。然后,您可以在最后两个日期之间开始二进制搜索,以准确确定它何时翻转
有关参考资料,请参阅。此信息在Windows中由EnumDynamicTimeZoneInformation函数提供
请参见有一个包含代码和数据的数据库:非常感谢您的回复。而且,是的,事实上,我问的是Windows的WinAPI 我做了更多的研究,并提出了以下方法来满足我的需求。它使用C++和MFC的
动态时区信息的文档。代码如下:
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;
}
int GetNextDaylightSavingAdjustmentTime(系统时间*pOutDtNextDST_本地,int*pnOutAdjustmentMin)
{
//获取下一次DST调整的时间
//“pOutDtNextDST_Local”=如果不为空,则接收下一次DST调整的(本地)时间
//“pnOutAdjustmentMin”=如果不为空,则以分钟为单位接收调整量
//返回:
//=1,如果有时间,或
//如果未使用DST,则=0
//=-1如果出现错误(请检查GetLastError()以获取信息)
int nOSError=无错误;
//动态加载API(对于Windows XP)
BOOL(WINAPI*pfnGetDynamicTimeZoneInformation)(PDYNAMIC\u TIME\u ZONE\u INFORMATION);
(FARPROC&)PFNGETDynamic时区信息=
::GetProcAddress(::GetModuleHandle(L“Kernel32.dll”),“GetDynamicTimeZoneInformation”);
德沃德·齐德;
系统时间标准日期;
SYSTEMTIME DaylightDate;
国际日光;
//如果可能,请使用更新的API
if(PFNGETDynamic时区信息)
{
动态时区信息dtzi={0};
tzID=pfnGetDynamicTimeZoneInformation(&dtzi);
StandardDate=dtzi.StandardDate;
DaylightDate=dtzi.DaylightDate;
nBiasDaylight=dtzi.DaylightBias;
}
其他的
{
//旧API
时区信息tzi={0};
tzID=获取时区信息(&tzi);
StandardDate=tzi.StandardDate;
DaylightDate=tzi.DaylightDate;
nBiasDaylight=tzi.日光偏差;
}
int nRes=-1;
int-nAdjMins=0;
系统时间变化;
memset(&stDstChange,0,sizeof(stDstChange));
系统时间标准测试;
如果(tzID==时区ID标准||
tzID==时区ID日光)
{
stDst=tzID!=时区\u ID\u日光?日光日期:标准日期;
如果(stDst.wMonth>=1&&
stDst.wMonth=1&&
stDst.wDayOfWeek>=0&&
stDst.wDayOfWeek COleDateTime::GetCurrentTime())
打破
}
int nRequiredWeek=stDst.wDay>=1&&stDst.wDay=0&&dow=nRequiredWeek)
{
//停止
打破
}
其他的
{
nCntDOW++;
}
}
//第二天去
dt+=COleDateTimeSpan(1,0,0,0);
}
//转换回系统时间
if(dt.GetAsSystemTime(stDstChange))
{
//成功
nRes=1;
}
其他的
{
//失败
nOSError=错误\无效\函数;
断言(空);
}
}
其他的
{
//绝对日期
stDstChange=stDst;
nRes=1;
}
}
其他的
{
//失败
nOSError=错误\无效\参数;
断言(空);
}
}
其他的
{
//未使用DST
如果(tzID==时区ID未知)
{
nRes=0;
}
其他的
{
//错误
nOSError=错误\无效\数据;
断言(空);
}
}
如果(pOutDtNextDST_本地)
*pOutDtNextDST_Local=标准变化;
如果(pnOutAdjustmentMin)
*pnOutAdjustmentMin=nAdjMins;
::SetLastError(NoError);
返回nRes;
}
另外,请记下我对UTC
时间的请求。据我所知,在这种情况下更容易处理当地时间。可能重复一个迂腐的注释:2014年11月2日1:59:59后的第二个夏令时是2014年11月2日1:00:00标准时间。2014年11月2日凌晨2:00夏令时不存在。看看那些根本不使用DST的国家,我想一个合理的限制应该是在当地时间一年后停止。@SirDarius是的,一年可能就可以了。我不认为C r/t答案适合Winapi问题,是吗?@david.pfx我没有注意到Winapi标签,并且假设需要一个更通用的解决方案(仅以Windows对话框为例)。我也不知道您在回答中引用的API调用。我感谢您的回答。它实际上让我了解了我在下面的代码中使用的GetDynamicTimeZoneInformation
API或GetTimeZoneInformation
。虽然很晚了,但因为这个回答对您有效(Q+A样式)应标记为