DateTime是值类型且不可变,AddDays()不修改原变量而返回新实例;应写dt = dt.AddDays(1)而非dt.AddDays(1);生产环境优先用TryParse()防崩溃;需关注Kind属性区分本地/UTC/未指定;高频场景应缓存Now、复用格式字符串、避免滥用Parse()。

DateTime.AddDays() 为什么没变?
因为 DateTime 是值类型且不可变,AddDays() 从不修改原变量,只返回新实例。你看到“没变”,大概率是写了 dt.AddDays(1); 却没接住返回值。
- 错误写法:
dt.AddDays(1);—— 返回值被丢弃,dt完全不变 - 正确写法:
dt = dt.AddDays(1); - 链式调用安全:
var result = dt.AddDays(1).AddHours(2).AddSeconds(30); - 循环中尤其容易踩坑:反复对原始
dt调用AddDays(1),结果每天都是从同一起点加,不是累加
DateTime.Parse() 和 DateTime.TryParse() 怎么选?
生产环境几乎必须用 TryParse()。输入来自用户、日志、API 或配置文件时,字符串格式不可控,Parse() 一遇到非法内容就抛 FormatException,直接崩。
-
DateTime.Parse("2026-05-14T")→ 可能成功,也可能崩溃 -
DateTime.TryParse("2026-05-14T", out var d)→ 返回false,d保持默认值,程序继续跑 - 需要精确格式(如固定长度日期):用
TryParseExact("20260514", "yyyyMMdd", null, DateTimeStyles.None, out d) -
null作为IFormatProvider参数会依赖当前线程文化;服务端建议显式传CultureInfo.InvariantCulture
本地时间、UTC、时区转换总出错?先看 Kind
绝大多数时区 bug 的根源是忽略 Kind 属性。一个 DateTime 值本身不带时区语义,它的 Kind 才说明它是本地时间、UTC 还是未指定。
-
DateTime.Now.Kind == DateTimeKind.Local,DateTime.UtcNow.Kind == DateTimeKind.Utc - 别直接比较
Local和Utc实例:即使数值相同,new DateTime(2026,5,14,12,0,0, DateTimeKind.Local) == new DateTime(2026,5,14,12,0,0, DateTimeKind.Utc)返回false - 跨时区计算前,显式标注或转换:
dt.SpecifyKind(DateTimeKind.Utc)或dt.ToUniversalTime() - 真要处理带偏移的时间点(比如用户提交的“2026-05-14 14:00 +08:00”),别硬套
DateTime,改用DateTimeOffset
高频或性能敏感场景要注意什么?
多数 DateTime 操作很快,但以下几处有隐性开销,容易在日志、循环、高并发服务里放大问题。
-
DateTime.Now每次调用都触发系统调用,高频循环中应缓存一次:var now = DateTime.Now;然后复用 -
ToString()格式化(尤其带文化信息时)分配字符串且较慢;常用格式如"yyyy-MM-dd HH:mm:ss"可提前定义为常量并复用 -
DateTime.Parse()内部做大量文化感知解析,比TryParseExact()慢数倍,且行为不稳定 - 最常被忽略的是:把
DateTime当“带时区的时间点”用,却没管Kind;或者当成可变对象,反复调用AddXxx()却不赋值


















