TimeZoneInfo.ConvertTimeFromUtc 未在已部署的 Azure Web 作业上正确应用夏令时
TimeZoneInfo.ConvertTimeFromUtc is not correctly applying DST on a deployed Azure Webjob
我们有一个在 .Net Framework 4.7.1 上运行的网络作业,它执行从 DateTimeOffset.UtcNow
到智利大陆时间的日期时间转换(如果我没记错的话 "Pacific SA Standard Time" ).
当 运行 此 webjob 在本地(在 Windows 10 机器中)时,它可以正常工作并应用 DST 执行转换,但是当部署到 Azure 应用服务时,它不再工作, 最后的 DateTime 总是比当前官方时间晚一小时。
我最初从 TimeZoneInfo.ConvertTimeBySystemTimeZoneId
切换到 TimeZoneInfo.ConvertTimeFromUtc
,假设第一个不考虑夏令时,但那没有用;
然后我尝试切换 "wrong" 我自己的电脑,将我的时区更改为 'UTC_dstoff' 并在 'Adjust date/time' 菜单中禁用选项 'Adjust for daylight saving time automatically' 和 'Set time automatically' 但它在本地仍按预期工作;
我尝试的最后一件事是使用环境变量 WEBSITE_TIME_ZONE
将时区更改为 App Service 到 'Pacific SA Standard Time',但这不是决定性的。我会说它最初似乎有效,但在对时区进行更多更改后,它又开始增加一小时。
这可以用以下几行复制:
var timeZoneId = "Pacific SA Standard Time";
var timeZone = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);
var dateTimeOffset = DateTimeOffset.UtcNow;
var localTime = TimeZoneInfo.ConvertTimeFromUtc(dateTimeOffset.DateTime, timeZone);
我希望函数 TimeZoneInfo.ConvertTimeFromUtc
在本地和 Azure 应用服务中选择带有 DST 的时区时能够正确应用 DST。相反,它似乎在 Windows 10 中正常工作,但在 Azure App Service 中随机工作。
在 Azure 上,将 WEBSITE_TIME_ZONE
添加到 Pacific SA Standard Time
并使用 TimeZoneInfo 结构的方法,如下所示:
DateTime timeUtc = DateTime.UtcNow;
TimeZoneInfo timeZone = TimeZoneInfo.FindSystemTimeZoneById("Pacific SA Standard Time");
DateTime kstTime = TimeZoneInfo.ConvertTimeFromUtc(timeUtc, timeZone );
更新
看来 KB4486459 that covered changes for Chile's DST schedule in 2019 中的时区更新尚未应用于 Azure 应用服务。从而解释了为什么您在某些日期在本地获得的结果与部署到 Azure 时的结果不同。
4486459 包含在 Azure March 2019 Guest OS patches 中,它们仍在部署到 Azure 应用服务。因此,随着个别实例收到更新,此问题将自行解决。
原答案
几件事:
WEBSITE_TIME_ZONE
仅当您拥有无法更改且适用于当地时间的代码时才应使用。例如,如果您多次调用 DateTime.Now
,这将反映当地时区。更改 WEBSITE_TIME_ZONE
将更改用于确定的时区。如果您可以控制自己的代码,那么永远不要写 DateTime.Now
,或使用任何其他依赖于本地时区的函数。那么您将永远不需要使用此设置。将其视为最后的手段 - 不是推荐的做事方式。
一般来说,您应该尽量不要编写会根据系统时区设置更改其行为的服务器端代码,无论是在您本地计算机的控制面板中,还是WEBSITE_TIME_ZONE
设置如上
这并不重要,但 "Adjust for daylight saving time automatically" 设置应该几乎始终保持打开状态。禁用它(或将 _dstoff
传递给 TZUtil.exe
)主要是遗留设置。 (有一种罕见的边缘情况,但不值得在这里讨论。)
是的,"Pacific SA Standard Time"
是智利大陆(圣地亚哥)的正确 Windows 时区 ID。其他适用于智利的是蓬塔阿雷纳斯 ("Magallanes Standard Time"
) 和复活节岛 ("Easter Island Standard Time"
)。
请注意,智利 2019 年的夏令时时间表发生了变化。Read about it here. This was released in an update by Microsoft in February 2019, described here。此更新应该已经安装在您的 Azure 网站上,但您可能想要验证您自己的本地计算机。
你说你原来用的是TimeZoneInfo.ConvertTimeBySystemTimeZoneId
。如果您使用了接受 DateTime
的重载,请注意如果 .Kind
是 DateTimeKind.Unspecified
那么它将被视为本地时间。如果您没有更改 WEBSITE_TIME_ZONE
,则默认本地时间 是 UTC。但如果你这样做了,那会影响行为。
另请注意,当您请求 DateTimeOffset
的 .DateTime
属性 时,种类总是 DateTimeKind.Unspecified
。虽然这不会影响您当前的代码,因为 TimeZoneInfo.ConvertTimeFromUtc
将未指定的种类视为 UTC(因此名称中的 "FromUTC")。
如果您正在使用 DateTimeOffset
类型,您最好使用 TimeZoneInfo.ConvertTimeBySystemTimeZoneId
或仅 TimeZoneInfo.ConvertTime
,以及接受和 [=99 的重载=]一个DateTimeOffset
。那么DateTimeKind
就不会妨碍你了。
最后,我要指出的是,您的问题并不清楚具体是什么不正常。您展示的代码最终会做正确的事情,即使它并不理想。无论您是否更改系统设置或 WEBSITE_TIME_ZONE
,它都不会产生间歇性结果。有没有可能你只是在不同的日期和时间喂食,然后发现有些有夏令时而有些没有?如果是这样,那可能是完全正常的。我会对照 Chile DST schedule 检查它们是否对齐。请记住,这与 DST 是否适用于您执行代码时无关,而是它是否适用于 给定的值。
如果您仍然遇到问题,请评论输入和输出示例以及您的预期。谢谢。
我们有一个在 .Net Framework 4.7.1 上运行的网络作业,它执行从 DateTimeOffset.UtcNow
到智利大陆时间的日期时间转换(如果我没记错的话 "Pacific SA Standard Time" ).
当 运行 此 webjob 在本地(在 Windows 10 机器中)时,它可以正常工作并应用 DST 执行转换,但是当部署到 Azure 应用服务时,它不再工作, 最后的 DateTime 总是比当前官方时间晚一小时。
我最初从 TimeZoneInfo.ConvertTimeBySystemTimeZoneId
切换到 TimeZoneInfo.ConvertTimeFromUtc
,假设第一个不考虑夏令时,但那没有用;
然后我尝试切换 "wrong" 我自己的电脑,将我的时区更改为 'UTC_dstoff' 并在 'Adjust date/time' 菜单中禁用选项 'Adjust for daylight saving time automatically' 和 'Set time automatically' 但它在本地仍按预期工作;
我尝试的最后一件事是使用环境变量 WEBSITE_TIME_ZONE
将时区更改为 App Service 到 'Pacific SA Standard Time',但这不是决定性的。我会说它最初似乎有效,但在对时区进行更多更改后,它又开始增加一小时。
这可以用以下几行复制:
var timeZoneId = "Pacific SA Standard Time";
var timeZone = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);
var dateTimeOffset = DateTimeOffset.UtcNow;
var localTime = TimeZoneInfo.ConvertTimeFromUtc(dateTimeOffset.DateTime, timeZone);
我希望函数 TimeZoneInfo.ConvertTimeFromUtc
在本地和 Azure 应用服务中选择带有 DST 的时区时能够正确应用 DST。相反,它似乎在 Windows 10 中正常工作,但在 Azure App Service 中随机工作。
在 Azure 上,将 WEBSITE_TIME_ZONE
添加到 Pacific SA Standard Time
并使用 TimeZoneInfo 结构的方法,如下所示:
DateTime timeUtc = DateTime.UtcNow;
TimeZoneInfo timeZone = TimeZoneInfo.FindSystemTimeZoneById("Pacific SA Standard Time");
DateTime kstTime = TimeZoneInfo.ConvertTimeFromUtc(timeUtc, timeZone );
更新
看来 KB4486459 that covered changes for Chile's DST schedule in 2019 中的时区更新尚未应用于 Azure 应用服务。从而解释了为什么您在某些日期在本地获得的结果与部署到 Azure 时的结果不同。
4486459 包含在 Azure March 2019 Guest OS patches 中,它们仍在部署到 Azure 应用服务。因此,随着个别实例收到更新,此问题将自行解决。
原答案
几件事:
WEBSITE_TIME_ZONE
仅当您拥有无法更改且适用于当地时间的代码时才应使用。例如,如果您多次调用DateTime.Now
,这将反映当地时区。更改WEBSITE_TIME_ZONE
将更改用于确定的时区。如果您可以控制自己的代码,那么永远不要写DateTime.Now
,或使用任何其他依赖于本地时区的函数。那么您将永远不需要使用此设置。将其视为最后的手段 - 不是推荐的做事方式。一般来说,您应该尽量不要编写会根据系统时区设置更改其行为的服务器端代码,无论是在您本地计算机的控制面板中,还是
WEBSITE_TIME_ZONE
设置如上这并不重要,但 "Adjust for daylight saving time automatically" 设置应该几乎始终保持打开状态。禁用它(或将
_dstoff
传递给TZUtil.exe
)主要是遗留设置。 (有一种罕见的边缘情况,但不值得在这里讨论。)是的,
"Pacific SA Standard Time"
是智利大陆(圣地亚哥)的正确 Windows 时区 ID。其他适用于智利的是蓬塔阿雷纳斯 ("Magallanes Standard Time"
) 和复活节岛 ("Easter Island Standard Time"
)。请注意,智利 2019 年的夏令时时间表发生了变化。Read about it here. This was released in an update by Microsoft in February 2019, described here。此更新应该已经安装在您的 Azure 网站上,但您可能想要验证您自己的本地计算机。
你说你原来用的是
TimeZoneInfo.ConvertTimeBySystemTimeZoneId
。如果您使用了接受DateTime
的重载,请注意如果.Kind
是DateTimeKind.Unspecified
那么它将被视为本地时间。如果您没有更改WEBSITE_TIME_ZONE
,则默认本地时间 是 UTC。但如果你这样做了,那会影响行为。另请注意,当您请求
DateTimeOffset
的.DateTime
属性 时,种类总是DateTimeKind.Unspecified
。虽然这不会影响您当前的代码,因为TimeZoneInfo.ConvertTimeFromUtc
将未指定的种类视为 UTC(因此名称中的 "FromUTC")。如果您正在使用
DateTimeOffset
类型,您最好使用TimeZoneInfo.ConvertTimeBySystemTimeZoneId
或仅TimeZoneInfo.ConvertTime
,以及接受和 [=99 的重载=]一个DateTimeOffset
。那么DateTimeKind
就不会妨碍你了。
最后,我要指出的是,您的问题并不清楚具体是什么不正常。您展示的代码最终会做正确的事情,即使它并不理想。无论您是否更改系统设置或 WEBSITE_TIME_ZONE
,它都不会产生间歇性结果。有没有可能你只是在不同的日期和时间喂食,然后发现有些有夏令时而有些没有?如果是这样,那可能是完全正常的。我会对照 Chile DST schedule 检查它们是否对齐。请记住,这与 DST 是否适用于您执行代码时无关,而是它是否适用于 给定的值。
如果您仍然遇到问题,请评论输入和输出示例以及您的预期。谢谢。