c#和javascript之间的夏令时问题

时间:2018-04-22 13:39:00

标签: javascript c# datetime serialization timezone

我有一个休息api,它给出了当前日期和当前日期的上个月,它有如下输出:

{
 fromDate:2018-03-22T00:00:00+04:30 
 toDate:2018-04-22T00:00:00+04:30
}

如果我在JavaScript中使用这两个日期,如下所示,我会得到不同的结果:

new Date("2018-03-22T00:00:00+04:30")

console output: Wed Mar 21 2018 23:00:00 GMT+0330 (Iran Standard Time)

new Date("2018-04-22T00:00:00+04:30")

console output: Sun Apr 22 2018 00:00:00 GMT+0430 (Iran Daylight Time)

在c#方面,我使用此代码从服务器获取日期:

 var toDate = DateTime.Now.Date;
 DateTime fromDate = toDate.AddMonths(-1);

如何克服这个没有不同日期的问题?

1 个答案:

答案 0 :(得分:1)

由于2018-03-22上的daylight saving time in Iran开始,当时钟接近00:00:00时,它会提前一小时到01:00:00。如果在这段时间内仔细观察时钟,人们会看到它如下:

...
2018-03-21 23:59:58
2018-03-21 23:59:59
2018-03-22 01:00:00
2018-03-21 01:00:01
...

换句话说,当天在当天时区中的值00:00:0000:59:59不存在

由于您在fromDate中提供了此类不存在的值,并且您的本地计算机的时区设置为伊朗,因此JavaScript会将其转换为有效的时间点,如下所示:

2018-03-22T00:00:00+04:30   source input value
2018-03-21T19:30:00+00:00   converted to UTC
2018-03-21T23:00:00+03:30   converted to a valid local time

如果您希望当天开始正确的开始,那么fromDate必须是2018-03-22T01:00:00+04:30

要在C#中在服务器端正确计算,您需要使用TimeZoneInfo API。请考虑以下帮助方法:

static DateTimeOffset GetStartOfDay(DateTime dt, TimeZoneInfo tz)
{
    // Work in the time zone provided
    if (dt.Kind != DateTimeKind.Unspecified)
    {
        dt = TimeZoneInfo.ConvertTime(dt, tz);
    }

    // Start with assuming midnight
    var d = dt.Date;

    // Check for the time being invalid and handle if so
    if (tz.IsInvalidTime(d))
    {
        // the gap is *usually* 1hr, but not always, so calculate it
        var gap = tz.GetUtcOffset(dt.AddDays(1)) - tz.GetUtcOffset(dt.AddDays(-1));

        // advance forward by the amount of the gap
        d = d.Add(gap);
    }

    // Also check for the time being ambiguous, such as in a fall-back transition.
    // We want the *first* occurrence, which will have a *larger* offset
    var offset = tz.IsAmbiguousTime(d)
        ? tz.GetAmbiguousTimeOffsets(d).OrderByDescending(x => x).First()
        : tz.GetUtcOffset(d);

    // Now we know when the date starts precisely
    return new DateTimeOffset(d, offset);
}

通过声明,现在您可以轻松获得API的准确值:

var tz = TimeZoneInfo.FindSystemTimeZoneById("Iran Standard Time");
var date = new DateTime(2014, 3, 22);  // or DateTime.UtcNow for the current date

DateTimeOffset fromDate = GetStartOfDay(date, tz);
DateTimeOffset toDate = GetStartOfDay(fromDate.AddDays(1).Date, tz);

当然,这假设伊朗是您希望从API发出的正确时区。如果您为更广泛的受众群体提供服务,则可能需要相应地调整时区。