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

llycmphe  于 2023-02-06  发布在  .NET
关注(0)|答案(4)|浏览(127)

我需要定期将数十亿的日期时间从UTC转换为EDT。
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 ;

        }
    }
}
vktxenjb

vktxenjb1#

在考虑性能之前,先考虑正确性。
你的两个例子给予了不同的结果。
夏令时东部时间比UTC晚4小时;5小时。您的简单减法没有考虑到这一点(事实上,您指定的采样日期给出了错误的结果-差值为2013年1月1日的5小时)。
此外,您需要警惕自制的基准测试,这可能会给予不切实际的结果,特别是如果您的应用不是以发布模式构建的。
如果要获得不考虑夏令时的结果,可以用途:

edtZone.BaseUtcOffset

而不是硬连线的:

new TimeSpan(4,0,0)

以使代码更具可读性。

nvbavucw

nvbavucw2#

根据你要处理的日期范围,你可以用字典来做。这样,第二次你做的时候,它会更快。当然,这只在你重复做有限的几天的时候有效。如果你有一个更大的范围,你每天都做一次(很难想象有几十亿个这样的人--地球只有这么老:),那么这就不会工作得那么好。另外,你必须记住记忆。
如果您实际上是每小时(或分钟和更细)做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;

    }
}
w3nuxt5m

w3nuxt5m3#

总的来说,我认为你是在尝试微优化。你真的会在几毫秒的时间里看到明显的性能差异吗?不太可能。
此外,TimeZoneInfo转换可能不如直接TimeSpan减法快,但正如其他人所指出的-它们做的事情不一样。另请阅读the timezone tag wiki中的“Time Zone!= Offset”。
如果你正在寻找TimeZoneInfo的替代品,我建议你在Noda Time中评估DateTimeZone类。Jon Skeet是它的主要作者,他当然专注于性能调优。我不能100%确定它是否比TimeZoneInfo“更快”,但我知道它肯定功能更强大,更准确。
此外,您可能已经意识到这一点,但值得指出的是。"GMT Standard Time"不是GMT的时区。它是“都柏林,Edinburgh,里斯本,伦敦”的Windows时区ID。它在夏季的GMT(UTC+00:00)和冬季的BST(UTC+01:00)之间交替。类似地,Windows时区标识符"Eastern Standard Time"同时表示EST(UTC-05:00)和EDT(UTC-04:00)。这就是为什么时区转换比简单的减法更复杂的原因。

zed5wv10

zed5wv104#

即使在最新版本的.NET 6中,将时间转换为UTC/从UTC转换时间也很慢的原因是“DST”-夏令时。
不能像这样添加偏移:

//superfast but won't work with DST
var result = utcDate + myTimeZone.BaseUtcOffset;

你需要弄清楚,如果日期福尔斯在DST范围内,为此你需要调用IsDaylightSavingTime(),这是所有缓慢的起源。
微软的Github for .NET运行时存在一个未解决的问题,但它没有得到太多关注https://github.com/dotnet/runtime/issues/25075
唯一的解决方案是放弃DST(如果可以的话),或者为DST提供自己的缓存/计算机制。

相关问题