什么是TimeZoneInfo.ConvertTime的更快替代品?

时间:2014-04-03 13:17:46

标签: c# .net datetime timezone

我需要定期将数十亿的DateTimes从UTC转换为EDT。

TimeZoneInfo.ConvertTime非常方便,但非常非常慢。

我比较TimeSpan的简单减法。请参阅下面的SSCCE。

如果您注释掉OPTION 1或OPTION 2(如代码所示),您将看到不同的运行时间。

我想要这个功能,但需要更快的速度才有办法吗?

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Globalization;


namespace BinTest2
{
    public partial class Form1 : Form
    {

        static TimeZoneInfo edtZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
        static TimeZoneInfo gmtZone = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
        static TimeZoneInfo utcZone = TimeZoneInfo.FindSystemTimeZoneById("UTC");
        public static CultureInfo ci = CultureInfo.InvariantCulture;

        private void button5_Click(object sender, EventArgs e)
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();

            DateTime DT = new DateTime(2013,01,01);

            DateTime TDT;
            TimeSpan TS = new TimeSpan(4,0,0);
            for (int i = 0; i < 100000000; i++)
            {
                //TDT = DT - TS;   //OPTION 1
                TDT = TimeZoneInfo.ConvertTime(DT, utcZone, edtZone);  //OPTION 2
            }

            sw.Stop();

            label1.Text = "Time taken: " + sw.ElapsedMilliseconds ;


        }
    }
}

3 个答案:

答案 0 :(得分:2)

在考虑表现之前,请考虑正确性。

您的两个示例会给出不同的结果。

当夏令时投入使用时,东部时间比UTC晚4h; 5h时没有。您的简单减法没有考虑到这一点(事实上,您指定的样本日期给出了错误的结果 - 差异是2013年1月1日的5小时)。

此外,您需要警惕自制的基准测试,这可能会产生不切实际的结果,特别是如果您的应用程序不是以发布模式构建的。

如果您希望结果不考虑夏令时,可以使用:

edtZone.BaseUtcOffset

而不是硬连线:

new TimeSpan(4,0,0)

使您的代码更具可读性。

答案 1 :(得分:0)

根据您要处理的日期范围,您可以使用字典进行操作。这样,第二次你这样做,它会更快。当然,这只有在您反复进行有限的几天时才有效。如果你有一个更大的范围,你每天都做几天(难以想象有数十亿 - 地球只有这么老:)那么这将不会那么好。此外,你必须牢记记忆。

如果你实际上每小时都在做DT(或者用分钟和更精细的话),那么你将需要使用一个涵盖小时和分钟的整数索引,这样你就可以正确地处理夏令时的变化。

public partial class Form1 : Form
{
    Dictionary<DateTime,TimeSpan> lut = new Dictionary<DateTime, TimeSpan>(); 
    public Form1()
    {
        InitializeComponent();
    }
    static TimeZoneInfo edtZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
    static TimeZoneInfo gmtZone = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
    static TimeZoneInfo utcZone = TimeZoneInfo.FindSystemTimeZoneById("UTC");
    public static CultureInfo ci = CultureInfo.InvariantCulture;

    private void button5_Click(object sender, EventArgs e)
    {
        Stopwatch sw = new Stopwatch();
        sw.Start();

        DateTime DT = new DateTime(2013, 01, 01);

        DateTime TDT;
        TimeSpan TS = new TimeSpan(5, 0, 0);
        for (int i = 0; i < 100000000; i++)
        {
            if (!lut.ContainsKey(DT))
            {
                lut[DT] = DT - TimeZoneInfo.ConvertTime(DT, utcZone, edtZone);                    
            }

            TDT = DT - lut[DT];

        }

        sw.Stop();

        label1.Text = "Time taken: " + sw.ElapsedMilliseconds;


    }
}

答案 2 :(得分:0)

总的来说,我认为你正在尝试进行微观优化。您是否

此外,TimeZoneInfo次转化可能没有直接TimeSpan减法那么快,但正如其他人所指出的那样 - 他们没有做同样的事情。另请阅读&#34;时区!=偏移&#34;在the timezone tag wiki

如果您正在寻找TimeZoneInfo的替代方案,建议您评估Noda Time中的DateTimeZone课程。 Jon Skeet是它的主要作者,他当然专注于性能调优。如果 TimeZoneInfo,我不是100%确定,但我知道它确实更具功能性和准确性。

此外,您可能已经意识到这一点,但值得指出。 "GMT Standard Time"不是GMT的时区。它是&#34;都柏林,爱丁堡,里斯本,伦敦&#34;的Windows时区ID。它在夏天的GMT(UTC + 00:00)和冬天的BST(UTC + 01:00)之间交替。类似地,Windows时区标识符"Eastern Standard Time"表示EST(UTC-05:00)和EDT(UTC-04:00)。这就是时区转换比简单减法更复杂的原因。