首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# 實作 DateDiff:日期時間間隔計算工具類

     編輯:關於C語言

VB DateDiff 移植到 C#

VB6/VBA 提供 DateDiff(Interval, Start, End),C# 無內建對應方法。本文提供完整實作,支援秒至年等 8 種間隔單位。

介面設計


public enum DateInterval
{
    Second, Minute, Hour, Day, Week, Month, Quarter, Year
}

public static class DateTimeManager
{
    /// 
    /// 計算兩日期時間間隔
    /// 
    /// 間隔單位
    /// 起始時間
    /// 結束時間
    /// 間隔值 (可為負,表示 start > end)
    public static long DateDiff(DateInterval interval, DateTime startDate, DateTime endDate)
    {
        TimeSpan ts = endDate - startDate; // 自動處理正負
        return interval switch
        {
            DateInterval.Second  => (long)ts.TotalSeconds,
            DateInterval.Minute  => (long)ts.TotalMinutes,
            DateInterval.Hour    => (long)ts.TotalHours,
            DateInterval.Day     => ts.Days,
            DateInterval.Week    => ts.Days / 7,
            DateInterval.Month   => (long)Math.Floor(ts.TotalDays / 30.436875), // 平均月長
            DateInterval.Quarter => (long)Math.Floor(ts.TotalDays / (30.436875 * 3)),
            DateInterval.Year    => (long)Math.Floor(ts.TotalDays / 365.2425),   // 平均年長(含閏年)
            _ => throw new ArgumentOutOfRangeException(nameof(interval))
        };
    }
}

改良說明:月/季/年計算

原始碼直接用 30/365 除法不準確。改良版採用平均曆法常數:

  • 平均月長:365.2425 / 12 = 30.436875 天
  • 平均季長:30.436875 × 3 = 91.310625 天
  • 平均年長:365.2425 天 (格里曆 400 年週期)

若需「行事曆月份差」(如 1/31 到 2/1 算 1 月),需改用年月運算:


public static int MonthDiffCalendar(DateTime start, DateTime end)
{
    return (end.Year - start.Year) * 12 + (end.Month - start.Month) + (end.Day >= start.Day ? 0 : -1);
}

使用範例


var d1 = DateTime.Now;
var d2 = d1.AddYears(2).AddMonths(3).AddDays(10);

Console.WriteLine($"Days:     {DateTimeManager.DateDiff(DateInterval.Day, d1, d2)}");
Console.WriteLine($"Hours:    {DateTimeManager.DateDiff(DateInterval.Hour, d1, d2)}");
Console.WriteLine($"Months:   {DateTimeManager.DateDiff(DateInterval.Month, d1, d2)}");
Console.WriteLine($"Years:    {DateTimeManager.DateDiff(DateInterval.Year, d1, d2)}");
Console.WriteLine($"CalMonths:{MonthDiffCalendar(d1, d2)}"); // 行事曆月差

單元測試


[TestFixture]
public class DateDiffTests
{
    [TestCase(DateInterval.Day, "2024-01-01", "2024-01-10", 9)]
    [TestCase(DateInterval.Hour, "2024-01-01 00:00", "2024-01-01 03:30", 3)]
    [TestCase(DateInterval.Month, "2024-01-15", "2024-04-15", 3)] // 近似
    [TestCase(DateInterval.Year, "2020-01-01", "2024-01-01", 4)]
    public void DateDiff_BasicIntervals_ReturnsExpected(DateInterval interval, string s, string e, long expected)
    {
        Assert.AreEqual(expected, DateTimeManager.DateDiff(interval, DateTime.Parse(s), DateTime.Parse(e)));
    }

    [Test]
    public void ReverseOrder_ReturnsNegative()
    {
        var d1 = DateTime.Parse("2024-01-10");
        var d2 = DateTime.Parse("2024-01-01");
        Assert.AreEqual(-9, DateTimeManager.DateDiff(DateInterval.Day, d1, d2));
    }
}

.NET 替代方案

  • TimeSpan 直接提供 TotalDays/TotalHours... 精確到毫秒。
  • DateTime.Subtract 回傳 TimeSpan。
  • NodaTime 庫:Period.Between(start, end, PeriodUnits.Months | PeriodUnits.Days) 提供精確行事曆運算。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved