使用TimeZoneInfo调整时区的夏令时偏移量

时间:2014-03-27 14:25:32

标签: c# datetime timezone offset dst

以下是我使用的方法,它接收三个输入:

dateTimeInput这是一个表示日期的字符串。

inputFormat是我的format字符串,格式如下:yyyy-MM-dd'T'HH:mm:sszzz

timeZoneStandardName是从var TimeZoneList = TimeZoneInfo.GetSystemTimeZones();检索到的唯一时区标识符,其中ID是通过timeZoneList.Id检索的。

我主要使用TimeZoneInfo来获取我的小时和分钟偏移量,因为它非常明确地表示它是什么城市/时区,例如UTC是输入字符串。

public int dateTimeToUnixTime(string dateTimeInput, string inputFormat, string timeZoneStandardName)
{
    DateTime result;
    CultureInfo provider = CultureInfo.InvariantCulture;
    TimeZoneInfo objTimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(timeZoneStandardName);
    int timeZoneHours = objTimeZoneInfo.BaseUtcOffset.Hours;
    int timeZoneMinutes = objTimeZoneInfo.BaseUtcOffset.Minutes;

    // if input format is "yyyy-MM-dd'T'HH:mm:sszzz"
    if (inputFormat == "yyyy-MM-dd'T'HH:mm:sszzz")
    {
        result = DateTime.ParseExact(dateTimeInput, inputFormat, provider, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);
        int unixTime = (Int32)(result.Subtract(Epoch)).TotalSeconds;
        return unixTime;
    }
    else
    {
        // if other input formats
        result = DateTime.ParseExact(dateTimeInput, inputFormat, provider, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);
        int unixTime = (Int32)(result.AddHours(-timeZoneHours).AddMinutes(-timeZoneMinutes).Subtract(Epoch)).TotalSeconds;
        return unixTime;
    }
}

我的第二种方法接受Unix时间戳和时区说明符,并作为位置相关的时间输出:

public string unixTimeToDateTime(int unixInput, string outputFormat, string timeZoneStandardName)
{
    // output format is "yyyy-MM-dd'T'HH:mm:sszzz"
    TimeZoneInfo objTimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(timeZoneStandardName);
    int timeZoneHours = objTimeZoneInfo.BaseUtcOffset.Hours;
    int timeZoneMinutes = objTimeZoneInfo.BaseUtcOffset.Minutes;
    if (outputFormat == "yyyy-MM-dd'T'HH:mm:sszzz")
    {
        System.DateTime dateTime = Epoch.AddSeconds(unixInput);
        return dateTime.AddHours(timeZoneHours).AddMinutes(timeZoneMinutes).ToString("yyyy-MM-dd'T'HH:mm:ss") + toTimeSpan(timeZoneHours, timeZoneMinutes);
    }
    // output format is not
    else
    {
        System.DateTime dateTime = Epoch.AddSeconds(unixInput).AddHours(timeZoneHours).AddMinutes(timeZoneMinutes);
        return dateTime.ToString(outputFormat);
    }
}

例如,这是Grasshopper组件中的这个方法,让我向您展示我的意思。 dateTimeToUnixTime()是我的第一个"时钟",而unixTimeToDateTime()是我的第二个"时钟"

enter image description here

考虑到这些时间列表的输入和EST的时区标记,并给出这些日期(请注意,2014年11月2日上午1-2点是我们再次进行DST调整的时候),理论上这个方法应该将其时区调整为抵消了一个小时。

我知道TimeZoneInfo支持DST,因为我可以使用以下方法显示相应时区的DST状态bool

    var TimeZoneList = TimeZoneInfo.GetSystemTimeZones();

    for (int i = 0; i < TimeZoneList.Count; i++)
    {
        Console.WriteLine(TimeZoneList[i].Id + ": " + TimeZoneList[i].SupportsDaylightSavingTime);
    }

我的问题是,我的dateTimeToUnixTime()方法中缺少哪些内容可以根据DST条件进行自动调整和偏移?

1 个答案:

答案 0 :(得分:2)

假设您的纪元始于1970年1月1日,那么我们可以使用DateTimeOffset _1970作为您的纪元,将所需的秒数添加到_1970,然后使用{{3使用夏令时调整(如果适用)获取指定时区的日期时间。使用DateTimeOffset而非DateTime非常重要,这样在获取字符串时将保留正确的偏移量。

private static readonly DateTimeOffset _1970 = new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero);
public string UnixTimeToDateTime(int unixInput, string outputFormat, string timeZoneStandardName)
{
    var objTimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(timeZoneStandardName);
    var utcDate = _1970.AddSeconds(unixInput);
    DateTimeOffset localDate = TimeZoneInfo.ConvertTime(utcDate, objTimeZoneInfo);
    return localDate.ToString(outputFormat);
}

//1970-01-01T13:00:00+13:00
Console.WriteLine( UnixTimeToDateTime(0, "yyyy-MM-dd'T'HH:mm:sszzz", "New Zealand Standard Time"));

//1970-01-01T08:00:00+08:00
Console.WriteLine(UnixTimeToDateTime(0, "yyyy-MM-dd'T'HH:mm:sszzz", "Singapore Standard Time"));

//1969-12-31T19:00:00-05:00
Console.WriteLine(UnixTimeToDateTime(0, "yyyy-MM-dd'T'HH:mm:sszzz", "Eastern Standard Time"));

请务必注意,使用TimeZoneInfo可能没有关于历史日期调整的TimeZoneInfo.ConvertTime,因此如果这对您很重要,那么您最好使用accurate information等库。