我刚刚注意到使用coredll(Win-CE)函数[SetSystemTime
][1]来设置日期时间,它会更新时间,然后评估夏令时。
例如:今天是2014年5月9日,时间是当地时间上午11点。所以CE设备的应用程序说我的当前日期是2014年1月1日时间xx:xx,然后问你想要什么日期和时间?我们说是2014年5月9日上午11点
当前日期不是夏令时,新日期是,我们使用.NET[ToUniversalTime
][2]函数将其转换为UTC(2014年5月9日下午4:00)。它认为新的日期时间是夏令时,并在转换中考虑它。因此,我们将[SYSTEMTIME
][3]结构设置为:
Dim utc As DateTime = #5/9/2014 11:00am#.ToUniversalTime()
Dim st As New SYSTEMTIME
st.Year = CUShort(utc.Year)
st.Month = CUShort(utc.Month)
st.Day = CUShort(utc.Day)
st.Hour = CUShort(utc.Hour)
st.Minute = CUShort(utc.Minute)
st.Second = CUShort(utc.Second)
st.Milliseconds = CUShort(utc.Millisecond)
你以为我只是把时间定在2014年5月9日上午11点,但不,现在是上午10点。
以下是我对正在发生的事情的猜测。日期和时间设置好了,然后Windows会说"哦,今天是夏令时,我需要调整时间",现在你比预期的时间少了一个小时。上夏令时还是下夏令时并不重要。第二次运行相同的函数,您就会得到预期的结果,因为现在窗口不必为进入或退出DST而进行调整。
目前,我唯一能想到的解决办法是在更改之前设置一个标志
Dim DSTTranstions As Boolean = _
Not (TimeZone.CurrentTimeZone.IsDaylightSavingTime(Now) = _
TimeZone.CurrentTimeZone.IsDaylightSavingTime(newTime))
如果设置了标志,则称其为第二次
我是不是太难了?
此外,我还没有在kernel32("桌面窗口")上测试过这一点,我猜这也是同样的逻辑。
这是整个代码:
<DllImport("coredll.dll"), CLSCompliant(False)> _
Public Function SetSystemTime(ByRef lpSystemTime As SYSTEMTIME) As UInt32
End Function
<StructLayout(LayoutKind.Sequential), CLSCompliant(False)> _
Public Structure SYSTEMTIME
Dim Year As UInt16
Dim Month As UInt16
Dim DayOfWeek As UInt16
Dim Day As UInt16
Dim Hour As UInt16
Dim Minute As UInt16
Dim Second As UInt16
Dim Milliseconds As UInt16
End Structure
Public Function SetTime(ByVal newTime As Date, _
Optional ByVal DateIsUTC As Boolean = False) As Boolean
Try
Dim utc As Date = Nothing
If DateIsUTC Then
utc = newTime
Else
utc = newTime.ToUniversalTime()
End If
Dim DSTTranstions As Boolean = Not (TimeZone.CurrentTimeZone.IsDaylightSavingTime(Now) = _
TimeZone.CurrentTimeZone.IsDaylightSavingTime(newTime))
If DSTTranstions AndAlso TimeZone.CurrentTimeZone.IsDaylightSavingTime(Now) Then
utc = utc.AddHours(-1)
ElseIf DSTTranstions AndAlso Not TimeZone.CurrentTimeZone.IsDaylightSavingTime(Now) Then
utc = utc.AddHours(1)
End If
Dim st As New SYSTEMTIME
st.Year = CUShort(utc.Year)
st.Month = CUShort(utc.Month)
st.Day = CUShort(utc.Day)
st.Hour = CUShort((utc.Hour))
st.Minute = CUShort((utc.Minute))
st.Second = CUShort((utc.Second))
st.Milliseconds = CUShort(utc.Millisecond)
Return CBool(SetSystemTime(st))
Catch ex As Exception
MyMessages.Show(ex.ToString)
Return False
End Try
End Function
我向所有人道歉,我一定没有很好地解释这个问题。我想因为这个例子,每个人都听到我说这个问题是"SetSystemTime"。我相信"SetSystemTime"one_answers"ToUniversalTime"都能按预期工作。我认为这是操作系统的影响。
我们都知道,如果操作系统设置为更新自动DST,那么当DST根据DST参数出现时,操作系统会相应地调整时钟。我应该放松一下,如果我正在更新时钟的日期,并且更新后旧日期的夏令时与新日期的夏令营相反,操作系统会将时间调整为正确的夏令营时间。因此测试">
Dim DSTTranstions As Boolean = Not (TimeZone.CurrentTimeZone.IsDaylightSavingTime(Now) = _
TimeZone.CurrentTimeZone.IsDaylightSavingTime(newTime))
"如果新旧日期的夏令时相反,则DST转换将为真。然后测试DST转换为ON或OFF的方式,并相应地预先调整时间。因此,当操作系统进行调整时,它是如预期的那样。
我只是花了一段时间把这些点联系起来。我的问题是,处理这种罕见情况的最佳方法是什么。马特指出,"请参阅本答案中关于设备制造商实施的第二段"也可能发挥作用。他是对的,问题不一样,但它告诉我们的是,各个制造商编写自己的驱动程序。作为参考,我的CE设备是摩托罗拉9190。我希望这更有意义。
_________________2014年11月7日仍然不确定发生了什么。本周我将我的新代码投入生产。我将包括我的新代码和日志片段。从夏令时转换为非夏令时时会出现问题。偏移代码负责处理这一点。但我在同一天安排了一个时间,所以这不可能是一个过渡。这里有什么奇怪的。在过去的两周里,我已经在100个地点进行了测试。第一跳之后,有些向前有些向后,我没有注意到它再次发生。手持设备用于清点商店的存货。我使用rapi将一批加载到CE设备中。然后使用rapi在CE设备上执行一个程序CeSyncTime。CeSyncTime将参数作为日期/时间,然后设置设备的日期/时间。查看电脑上的日志,它确实在下午1点35分执行了CeSyncTime。从日志片段中可以看到,最初的时间是2014年7月9日下午2:35。它将时间设置为2014年7月9日下午1点35分。随着CeSyncTime的结束,它最后一次记录时间,新时间是2014年7月9日下午12:35。我不认为这是缓存问题,因为当Brscanner(不同的应用程序)启动时,时间是2014年7月9日下午12:35。当商店第二天盘点时,同样的流程。于2014年7月10日下午1点30分开始。时间从下午12:30到下午1:30,以下午1:30的正确时间结束。我就是不明白我的问题。我要请我的摩托罗拉代表让一位工程师看看这个线程。如果我听到什么,我会让你们知道的。首先是代码,然后是第9段和第11段代码。
Public Function SetTime(ByVal newTime As Date, _
Optional ByVal DateIsUTC As Boolean = False) As Boolean
Try
Dim CurrentTime As Date = Now
Dim utc As Date = Nothing
If DateIsUTC Then
utc = newTime
Else
utc = newTime.ToUniversalTime()
End If
Dim DSTTranstions As Boolean = Not (TimeZone.CurrentTimeZone.IsDaylightSavingTime(CurrentTime) = _
TimeZone.CurrentTimeZone.IsDaylightSavingTime(newTime))
Dim DSTTranstionOffset As Integer = 0
If DSTTranstions AndAlso TimeZone.CurrentTimeZone.IsDaylightSavingTime(CurrentTime) Then
DSTTranstionOffset = -1
ElseIf DSTTranstions AndAlso Not TimeZone.CurrentTimeZone.IsDaylightSavingTime(CurrentTime) Then
DSTTranstionOffset = 1
End If
utc = utc.AddHours(DSTTranstionOffset)
Dim st As New SYSTEMTIME
st.Year = CUShort(utc.Year)
st.Month = CUShort(utc.Month)
st.Day = CUShort(utc.Day)
st.Hour = CUShort((utc.Hour))
st.Minute = CUShort((utc.Minute))
st.Second = CUShort((utc.Second))
st.Milliseconds = CUShort(utc.Millisecond)
'Logger.LogCurrentTimeInfo()
'Logger.Log(" SetTime - (UTC) " & utc.ToString)
Logger.Log(" SetTime - Diagnostic Infomation - Start")
Logger.Log(" SetTime - CurrentTime: " & CurrentTime.ToString)
Logger.Log(" SetTime - NewTime: " & newTime.ToString)
Logger.Log(" SetTime - DSTTranstions: " & DSTTranstions.ToString)
Logger.Log(" SetTime - DSTTranstionOffset: " & DSTTranstionOffset.ToString)
Logger.Log(" SetTime - utc: " & utc.ToString)
Logger.Log(" SetTime - st: " & st.Year & ", " & st.Month & ", " & st.Day & " - " & st.Hour & ":" & st.Minute & ":" & st.Second & "." & st.Milliseconds)
Dim SetSystemTimeRetValue As Boolean = CBool(SetSystemTime(st))
Logger.Log(" SetTime - SetSystemTimeRetValue: " & SetSystemTimeRetValue.ToString)
Logger.Log(" SetTime - Diagnostic Infomation - End")
Return SetSystemTimeRetValue
Catch ex As Exception
Logger.Log(" SetTime - Error - " & ex.ToString)
MyMessages.Show(ex.ToString)
Logger.LogError(ex.ToString)
Return False
End Try
End Function
CeSyncTime 7/9/14 2:35:02 PM启动设置时间(从7/9/14 2:35:02 PM到7/9/14 1:35:03 PM)版本:5.1.0.8CeSyncTime 7/9/14下午2:35:02 SetTime-诊断信息-启动CeSyncTime 2014年7月9日下午2:35:02 SetTime-CurrentTime:2014年7日下午2:34:02CeSyncTime 2014年7月9日下午2:35:02 SetTime-NewTime:2014年7日下午1:35:03CeSyncTime 7/9/14下午2:35:02 SetTime-DSTTransitions:FalseCeSyncTime 7/9/14下午2:35:02 SetTime-DSTTransitionOffset:0CeSyncTime 7/9/14下午2:35:02 SetTime-utc:7/9/14下午6:35:03CeSyncTime 2014年9月7日下午2:35:02 SetTime-st:2014年7月9日-18:35:30CeSyncTime 7/9/14下午1:35:03 SetTime-SetSystemTimeRetValue:TrueCeSyncTime 7/9/14下午1:35:03设置时间-诊断信息-结束CeSyncTime 7/9/14下午12:35:08节目结束!Br Scanner 7/9/14 12:35:31 PM frmMain_Closing-上次电源日志,禁用电源通知,并处理扫描仪。Br扫描仪2014年7月9日下午12:35:31 frmMain_Closing-完成Br扫描仪7/9/14 12:35:31 PM总装载时间:167275021毫秒Br扫描仪2014年7月9日下午12:35:31主表单完成。Br扫描仪7/9/14 12:35:31 PM处理主窗体Br扫描仪7/9/14 12:35:31 PM卸下扫描仪处理器。Br扫描仪7/9/14 12:35:31 PM处置扫描仪。MDIShell 7/9/14 12:35:32 PM启动Br扫描仪(KeepRunning)重新启动计数:1Br扫描仪2014年7月9日下午12:35:33开始Br扫描仪7/9/14 12:35:33 PM版本5.1.0.8
第二天
CeSyncTime 7/10/14 12:30:46 PM启动设置时间(从7/10/14下午12:30:44到7/10/14/14下午1:30:46)版本:5.1.0.8CeSyncTime 7/10/14 12:30:46 PM SetTime-诊断信息-启动CeSyncTime 7/10/14 12:30:46 PM设置时间-当前时间:7/10/14下午12:30:44CeSyncTime 2014年10月7日12:30:46 PM设置时间-新时间:2014年10日7日1:30:46 PMCeSyncTime 7/10/14 12:30:46 PM SetTime-DST转换:FalseCeSyncTime 7/10/14 12:30:46 PM SetTime-DSTTransitionOffset:0CeSyncTime 7/10/14 12:30:46 PM SetTime-utc:7/10/14 6:30:46 PMCeSyncTime 2014年10月7日12:30:46 PM SetTime-st:2014年7月10日18:30:46.0CeSyncTime 7/10/14下午1:30:46 SetTime-SetSystemTimeRetValue:TrueCeSyncTime 7/10/14下午1:30:46 SetTime-诊断信息-结束CeSyncTime 7/10/14下午1:30:51节目结束!CeSyncTime 2014年7月10日下午1:31:37启动设置时间(从2014年7日下午1:31.37到2014年7年10月1日下午1:31-37)版本:5.1.0.8CeSyncTime 7/10/14下午1:31:38设置时间-诊断信息-启动CeSyncTime 7/10/14下午1:31:38 SetTime-CurrentTime:7/10/14CeSyncTime 7/10/14下午1:31:38 SetTime-NewTime:7/10/14CeSyncTime 7/10/14下午1:31:38 SetTime-DSTTransitions:FalseCeSyncTime 7/10/14下午1:31:38 SetTime-DSTTransitionOffset:0CeSyncTime 7/10/14下午1:31:38 SetTime-utc:7/10/14下午6:31:37CeSyncTime 2014年10月7日下午1:31:38 SetTime-st:2014年7月10日-18:31:37.0CeSyncTime 7/10/14下午1:31:37 SetTime-SetSystemTimeRetValue:TrueCeSyncTime 7/10/14下午1:31:37 SetTime-诊断信息-结束CeSyncTime 7/10/14下午1:31:42节目结束!Br扫描仪2014年7月10日下午1:31:52开始Br扫描仪7/10/14下午1:31:52版本5.1.0.8
问题出在这一行:
Dim utc As DateTime = #5/9/2014 11:00am#.ToUniversalTime()
DateTime
文字被评估为Unspecified
类型的DateTime
。当您调用ToUniversalTime
时,函数会假定它是本地时间,并将其转换为UTC上午10点。
你可以这样定义你的时间:
Dim utc as DateTime = DateTime.SpecifyKind(#5/9/2014 11:00am#, DateTimeKind.Utc)