在C#中指定另一个时区的日期

6

我有一个asp.net应用程序,必须在美国东部时间(DST感知)的特定时间运行一些代码。因此,我的第一个想法是获取东部时间值并将其转换为本地服务器时间。

所以我需要这样的东西:

var eastern = DateTime.Today.AddHours(17); // run at 5pm eastern
var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
var utc = TimeZoneInfo.ConvertTimeToUtc(eastern, timeZoneInfo);
var local = TimeZoneInfo.ConvertTimeFromUtc(utc, TimeZoneInfo.Local);

但是我该如何指定东部的DateTime对象应该处于EST时区呢?

我这样做是否有问题?


2
这个问题似乎有一个答案:https://dev59.com/InVC5IYBdhLWcg3wlyMo - Glenn
4个回答

8
首先,你需要考虑一些事情。你需要处理夏令时,这似乎在不断变化(过去10年里开始和结束日期已经更改了两次)。所以在北半球的冬季,东部时间是-5格林尼治标准时间(或UTC)。但是,在夏季它是-6 GMT或者是-4 GMT,我总是记不住(也不应该)。
有一些DNF库函数可以处理时区信息,但是你真正需要的是.NET 3.5最有用的东西。在.NET 3.5中有一个TimeZoneInfo类。
TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
DateTime dt = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(DateTime.Now,
     TimeZoneInfo.IsDaylightSavingsTime(tzi) ? 
        tzi.DaylightName : tzi.StandardName);
if (dt.Hour == 17)
    ....

另外,请记住每年两次会增加或减少一小时,所以如果您有一个倒计时计时器,例如显示“下一次处理时间”,您还需要考虑这一点。事实是,时间处理并不像一开始想象的那么容易,并且存在许多边缘情况。


每次我尝试运行将DateTime.Now转换为东部标准时间的代码时(.net 3.5),都会出现以下错误:“由于提供的DateTime没有正确设置Kind属性,因此无法完成转换。” - mikefrey
这通常意味着您以一种绕过Kind类型设置的方式设置了源DateTime。例如,DateTime.Now的Kind被设置为Local。您是如何提供源DateTime的?我怀疑您是使用类似以下方式的构造函数:DateTime dt = new DateTime(2010, 2, 1); 这将Kind设置为"Unspecified"。以下方式设置了Kind:DateTime dt = new DateTime(2010, 2, 1, 0, 0, 0, DateTimeKind.Utc); - Erik Funkenbusch

5

看起来我已经能够回答自己的问题了。这是我使用的代码,用于获取下一个运行的DateTime对象。

    private DateTime GetNextRun()
    {

        var today = DateTime.Today;
        var runTime = new DateTime(today.Year, today.Month, today.Day, 17, 0, 0);
        var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
        var offset = timeZoneInfo.GetUtcOffset(runTime);
        var dto = new DateTimeOffset(runTime, offset);

        if (DateTime.Now > dto.LocalDateTime) 
            dto = dto.AddDays(1);

        return dto.LocalDateTime;
    }

使用DateTimeOffset而不是DateTime进行所有转换,证明非常有效。它甚至似乎正确处理夏令时。


4
一个DateTime并不知道时区。即使是DateTimeOffset也不真正了解时区——它只知道一个UTC瞬间和相对于该瞬间的偏移量。
你可以编写自己的结构体,其中包含TimeZoneInfoDateTime,但我不确定在这种情况下是否需要它。你只是想在东部时间安排下午5点吗?还是实际上更为普遍?之后你要用DateTime(或其他什么)来做什么?使用DateTimeOffsetTimeZoneInfo,你肯定可以得到所感兴趣的时间的UTC瞬间;如果你只需要知道“现在”和那时之间的时间,那就很容易。
我觉得有责任指出,当Noda Time准备好投入生产时,它几乎肯定是正确的答案 :)

@Aaronaught:抱歉,我们在Noda Time中使用的是DateTimeZone :) 我会进行编辑。 - Jon Skeet
是的,我只是想安排一些东西在东部时间下午5点运行(考虑夏令时)。 - mikefrey

1
你可以使用 DateTime.UtcNow 来获取 UTC 中央时间(我相信是 GMT 0),然后只需计算出你想要的时区与 UTC 的差距,并为每个时区添加/减去一个小时即可。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接