617 字
3 分钟
C# 计算 DateTime 时间差:从基础到进阶实战

在开发考勤系统、倒计时功能或任务调度时,计算两个时间点之间的差值是高频需求。C# 通过 DateTimeTimeSpan 提供了一套极简且强大的 API。


1. 核心机制:DateTime 相减#

在 C# 中,计算时间差不需要复杂的计算,直接使用减法运算符 - 即可获得一个 TimeSpan 对象。

DateTime startTime = new DateTime(2025, 1, 1, 8, 0, 0);
DateTime endTime = DateTime.Now;
// 核心操作:直接相减
TimeSpan ts = endTime - startTime;

2. 区分 Total 属性与普通属性#

这是初学者最容易踩的坑。TimeSpan 提供了两组属性,其含义完全不同:

  • TotalDays, TotalHours: 返回的是总跨度。例如,1.5 天会返回 TotalHours = 36
  • Days, Hours: 返回的是时间分量。例如,1.5 天会返回 Days = 1, Hours = 12

常用计算方法封装:#

// 获取总天数(向上取整,常用于计算有效期)
public int GetTotalDays(DateTime start, DateTime end) => (int)Math.Ceiling((end - start).TotalDays);
// 获取总秒数(常用于缓存过期或 Token 校验)
public double GetTotalSeconds(DateTime start, DateTime end) => (end - start).TotalSeconds;

3. 高级扩展:处理精度与舍入#

在实际业务中,我们往往需要”忽略秒”或者”不满一小时按一小时计”。

public int DiffFullMinutes(DateTime start, DateTime end)
{
TimeSpan ts = end - start;
// 使用 (int) 会直接截断小数,实现"向下取整"
return (int)ts.TotalMinutes;
}

4. 跨时区的”深水区”#

当你的服务器在 A 国,用户在 B 国时,直接使用 DateTime.Now 计算差值会产生灾难性的 Bug。

黄金法则: 在计算时间差时,永远优先将时间转换为 UTC (协调世界时)

public double SafeDiffMinutes(DateTime start, DateTime end)
{
// 统一转换为 UTC 再计算,消除夏令时和偏移量干扰
return (end.ToUniversalTime() - start.ToUniversalTime()).TotalMinutes;
}

此外,如果你需要处理带偏移量的时间,推荐使用 DateTimeOffset 类型代替 DateTime


5. 性能与精度小贴士#

  1. 精度问题TimeSpan 的最小单位是 Tick(100 纳秒)。对于绝大多数 Web 应用,秒级精度绰绰有余。
  2. 只读性TimeSpan 是不可变的。每次 AddSubtract 都会返回一个新的对象。
  3. .NET 6+ 新选择:如果你只需要计算”一天之内”的时间差(不涉及日期),可以使用 TimeOnly 类型,内存占用更小。

总结#

计算时间差的精髓在于理解 TimeSpan 这个”时间容器”。

  • 如果要算长度,用 TotalXXX
  • 如果要按格式显示(如 01:30:00),用普通的 Hours/Minutes
C# 计算 DateTime 时间差:从基础到进阶实战
https://sw.rscclub.website/posts/csharpdatetimecha/
作者
杨月昌
发布于
2016-03-18
许可协议
CC BY-NC-SA 4.0