我已经创建了一些代码来转换双精度日期&时间值到另一个时区。当使用DateTimeKind.Local代替DateTimeKind.Unspecified时,它给出了我不理解的行为。
我的想法是传递给ConvertTime方法的双精度值完全脱离了它的地理上下文。当然,要正确转换的时间,有必要指定该值是当地时间并属于某个时区吗?
我正在尝试确保将本地源时间正确转换为本地目的地时间并观察夏令时,而不考虑主机的时区设置。
根据这个概念,我尝试指定
DateTime sourceDT = DateTime.SpecifyKind(inDT, DateTimeKind.Local);
但这会导致时间不被转换。如果我指定
DateTime sourceDT = DateTime.SpecifyKind(inDT, DateTimeKind.Unspecified);
然后发生转换。
有人可以解释为什么不接受DateTimeKind.Local作为时间转换中的有效规范以及如何实现我正在尝试的内容。
namespace ConvertTime
{
public interface ConvertTimeClass
{
double ConvertTime(double inTime, [MarshalAs(UnmanagedType.LPStr)] string sourceTZ, [MarshalAs(UnmanagedType.LPStr)] string destTZ);
}
public class ManagedClass : ConvertTimeClass
{
public double ConvertTime(double inTime, [MarshalAs(UnmanagedType.LPStr)] string sourceTZ, [MarshalAs(UnmanagedType.LPStr)] string destTZ)
{
DateTime inDT = DateTime.FromOADate(inTime);//convert decimal date and time value to a DateTime object.
DateTime sourceDT = DateTime.SpecifyKind(inDT, DateTimeKind.Unspecified);//specify that the time represents a local time and save into a new object.
TimeZoneInfo sourceTZI = TimeZoneInfo.FindSystemTimeZoneById(sourceTZ);
TimeZoneInfo destTZI = TimeZoneInfo.FindSystemTimeZoneById(destTZ);
DateTime destDT = TimeZoneInfo.ConvertTime(sourceDT, sourceTZI, destTZI);//convert time. FAILS WHEN DateTimeKind.Local is specified
double outTime = destDT.ToOADate();//extract the decimal date & time value
return outTime;
}
}
}
答案 0 :(得分:5)
您所指的"双精度日期和时间值"也被称为" OLE自动化日期"或者" OADate"简而言之。
OADates不传达任何时区信息。它们只是1899年12月30日以来的一个未知日历。此外,还有一些关于它们如何被编码的奇怪怪癖(参见these MSDN docs中的评论)使它们略微不合需要。如果可能的话我会避开它们。
尽管如此,您应该始终将它们视为未指定。事实上,您调用的FromOADate
方法已将其返回为Unspecified
种,因此根本没有理由调用DateTime.SpecifyKind
。简而言之,您的功能应该只是:
public double ConvertTime(double inTime, string sourceTZ, string destTZ)
{
DateTime sourceDT = DateTime.FromOADate(inTime);
TimeZoneInfo sourceTZI = TimeZoneInfo.FindSystemTimeZoneById(sourceTZ);
TimeZoneInfo destTZI = TimeZoneInfo.FindSystemTimeZoneById(destTZ);
DateTime destDT = TimeZoneInfo.ConvertTime(sourceDT, sourceTZI, destTZI);
return destDT.ToOADate();
}
但是,如果您的用例要求假设输入时间是计算机的本地时区,那么您将创建一个不同的方法:
public double ConvertFromLocalTime(double inTime, string destTZ)
{
DateTime sourceDT = DateTime.FromOADate(inTime);
TimeZoneInfo sourceTZI = TimeZoneInfo.Local;
TimeZoneInfo destTZI = TimeZoneInfo.FindSystemTimeZoneById(destTZ);
DateTime destDT = TimeZoneInfo.ConvertTime(sourceDT, sourceTZI, destTZI);
return destDT.ToOADate();
}
您仍然不需要指定本地种类,因为当未指定的DateTime
传递给TimeZoneInfo.ConvertTime
时,它会假定该值是根据源时区 - 这是您的本地时区在这种情况下。虽然本地的工作,但不是必需的。
至于为什么你在尝试本地时遇到错误,我认为这是你的错误:
"转换无法完成,因为提供的DateTime没有正确设置Kind属性。例如,当Kind属性为DateTimeKind.Local时,源时区必须为TimeZoneInfo.Local。"
正如错误所解释的那样,除非专门从DateTime
获取源时区,否则您无法将本地类型TimeZoneInfo.ConvertTime
传递给DateTimeKind.Local
。
源时区ID与本地时区ID匹配是不够的,因为TimeZoneInfo.Local
有一个特殊情况,即考虑"自动调整夏令时的时钟&# 34;选项。见these MSDN docs for details。换句话说:
TimeZoneInfo.Local != TimeZoneInfo.FindSystemTimeZoneById(TimeZoneInfo.Local.Id)
最后,我认为你误解了DateTimeKind
。你说:
当然,要正确转换的时间,有必要指定该值是本地时间并属于某个时区吗?
" local"在DateTimeKind.Local
和TimeZoneInfo.Local
中,具体表示运行代码的计算机的本地 。它不是 本地区域,它是 本地区域。如果DateTime
与UTC或计算机自己的本地时区设置相关联,则使用DateTimeKind.Unspecified
。