DateTime.AddDays或新的DateTime

时间:2009-10-14 14:56:14

标签: c# .net performance datetime stopwatch

我正在创建一个月的日期列表。我想知道什么会更有效率

List<DateTime> GetDates(DateTime StartDay) {
  List<DateTime> dates = new List<DateTime>();
  int TotalDays=StartDay.AddMonths(1).AddDays(-1).Day;
  for (int i=1; i<TotalDays; i++) {
    dates.Add(new DateTime(StartDay.Year, StartDay.Month, i));
  }
  return dates;
}

List<DateTime> GetDates(DateTime StartDay) {
  List<DateTime> dates = new List<DateTime>();
  DateTime NextMonth = StartDay.AddMonths(1);
  for (DateTime curr=StartDay; !curr.Equals(NextMonth); curr=curr.AddDays(1)) {
    dates.Add(curr);
  }
  return dates;
}

基本上,新的DateTime()或DateTime.addDays更有效率。

更新:

static void Main(string[] args) {
  System.Diagnostics.Stopwatch sw=new System.Diagnostics.Stopwatch();
  long t1, t2, total;
  List<DateTime> l;
  DateTime begin = DateTime.Now;
  total = 0L;
  for (int i=0; i<10; i++) {
    sw.Start();
    l = GetDates(begin);
    sw.Stop();


    sw.Stop();
    t1 = sw.ElapsedTicks;
    sw.Reset();
    sw.Start();

    l = GetDates2(begin);
    sw.Stop();
    t2=sw.ElapsedTicks;
    total +=  t1- t2;

    Console.WriteLine("Test {0} : {1} {2} : {3}", i,t1,t2, t1- t2);
  }
  Console.WriteLine("Total: {0}", total);

  Console.WriteLine("\n\nDone");
  Console.ReadLine();
}

static List<DateTime> GetDates(DateTime StartDay) {
  List<DateTime> dates = new List<DateTime>();
  int TotalDays=StartDay.AddMonths(10000).AddDays(-1).Day;
  for (int i=1; i<TotalDays; i++) {
    dates.Add(new DateTime(StartDay.Year, StartDay.Month, i));
  }
  return dates;
}


static List<DateTime> GetDates2(DateTime StartDay) {
  List<DateTime> dates = new List<DateTime>();
  DateTime NextMonth = StartDay.AddMonths(10000);
  for (DateTime curr=StartDay; !curr.Equals(NextMonth); curr=curr.AddDays(1)) {
    dates.Add(curr);
  }
  return dates;
}
Test 0 : 2203229 63086205 : -60882976
Test 1 : 63126483 102969090 : -39842607
Test 2 : 102991588 93487982 : 9503606
Test 3 : 93510942 69439034 : 24071908
Test 4 : 69465137 70660555 : -1195418
Test 5 : 70695702 68224849 : 2470853
Test 6 : 68248593 63555492 : 4693101
Test 7 : 63578536 65086357 : -1507821
Test 8 : 65108190 64035573 : 1072617
Test 9 : 64066128 64933449 : -867321
Total: -62484058

Done

结果一直是负面的...方式为负,所以,看起来像构造函数和整数测试是更有效的方法。

7 个答案:

答案 0 :(得分:5)

测量它 - 编写测试程序,看看哪一个花费的时间更短。

答案 1 :(得分:3)

我相信datetime操作会返回新的日期时间结构,因此您将以任何方式创建新实例。

http://msdn.microsoft.com/en-us/library/system.datetime.aspx

答案 2 :(得分:3)

除非你正在进行一些财务处理,否则我会更担心可读性而不是性能。如果这是一个经过证实的瓶颈,那就开始担心像这里的表现了。

答案 3 :(得分:2)

因为他们最终都做了同样的事情,所以差别不大。

如果您正在寻找效率,请使用滴答声。在完成任何数学运算之前,DateTime中的所有(我已经看到)调用最终会被转换为刻度。

答案 4 :(得分:1)

很难想象这会产生显着差异的情况,但Reflector表明AddDays技术应该更有效率。

比较AddDays(来自Add(Double, Int32)

的核心逻辑
long num = (long) ((value * scale) + ((value >= 0.0) ? 0.5 : -0.5));
if ((num <= -315537897600000L) || (num >= 0x11efae44cb400L)) {
    // Throw omitted
}
return this.AddTicks(num * 0x2710L);

DateTime(int, int, int)构造函数的核心逻辑(来自DateToTicks):

if (((year >= 1) && (year <= 0x270f)) && ((month >= 1) && (month <= 12)))
{
    int[] numArray = IsLeapYear(year) ? DaysToMonth366 : DaysToMonth365;
    if ((day >= 1) && (day <= (numArray[month] - numArray[month - 1])))
    {
        int num = year - 1;
        int num2 = ((((((num * 0x16d) + (num / 4)) - (num / 100)) + (num / 400)) + numArray[month - 1]) + day) - 1;
        return (num2 * 0xc92a69c000L);
    }
}
// Throw omitted

AddDays只需将指定的天数转换为等效的刻度数(一个长整数),然后将其添加到现有刻度中。

使用年/月/日构造函数创建新的DateTime需要更多计算。该构造函数必须检查指定年份是否为闰年,每月分配一个天数,执行一系列额外操作,最后得到这三个数字代表的滴答数。


编辑:DateTime.AddDays(int)new DateTime(int, int, int)快,但您的第一个算法比第二个算法快。这可能是因为第二算法中的迭代成本要高得多。正如您在编辑中观察到的那样,这可能是因为DateTime.Equals比比较整数更昂贵。

答案 5 :(得分:1)

这是一个有效的测试程序,实施的算法可以实际比较它们(但它们仍然需要工作):

 class Program
    {
        static void Main(string[] args)
        {
            IList<DateTime> l1, l2;
            DateTime begin = new DateTime(2000, 1, 1);

            Stopwatch timer1 = Stopwatch.StartNew();
            for (int i = 0; i < 10000; i++)
                l1 = GetDates(begin);
            timer1.Stop();

            Stopwatch timer2 = Stopwatch.StartNew();
            for (int i = 0; i < 10000; i++)
                l2 = GetDates2(begin);
            timer2.Stop();

            Console.WriteLine("new DateTime: {0}\n.AddDays: {1}",
                timer1.ElapsedTicks, timer2.ElapsedTicks);
            Console.ReadLine();
        }

        static IList<DateTime> GetDates(DateTime StartDay)
        {
            IList<DateTime> dates = new List<DateTime>();

            int TotalDays = DateTime.DaysInMonth(StartDay.Year, StartDay.Month);

            for (int i = 0; i < TotalDays; i++)
                dates.Add(new DateTime(StartDay.Year, StartDay.Month, i + 1));

            return dates;
        }


        static IList<DateTime> GetDates2(DateTime StartDay)
        {
            IList<DateTime> dates = new List<DateTime>();

            DateTime NextMonth = StartDay.AddMonths(1);

            for (DateTime curr = StartDay; !curr.Equals(NextMonth); curr = curr.AddDays(1))
                dates.Add(curr);

            return dates;
        }
    } // class

输出(我添加了逗号):

new DateTime: 545,307,375
.AddDays: 180,071,512

这些结果对我来说非常清楚,但老实说,我认为他们会更接近。

答案 6 :(得分:0)

我同意马克。自己测试两种方法,看看哪一种方法更快。使用秒表类可以准确计算每个方法运行的时间。我的第一个猜测是,既然最终都会创建新的结构,那么任何速度差异都可以忽略不计。此外,只生成一个月的日期(最多31天),我认为任何一种方法都不会比另一种方法慢得多。也许你是在产生数千或数百万个日期,它会有所作为,但是对于31个日期,它可能是过早的优化。