C# 日期与时间高级处理:从基本操作到高性能解决方案
\n日期与时间处理是开发中最常见也最棘手的任务之一。时区错误或格式不当可能导致生产环境中的严重缺陷。本文将超越基本的 DateTime 构造函数,深入探讨高级技术:DateTimeOffset、时区处理、通过 Stopwatch 进行高精度测量,以及性能和线程安全问题。本文面向熟练掌握 C# 并希望编写可靠 .NET 代码的开发人员。
1. DateTime、DateTimeOffset 和 TimeSpan:选择正确的类型
\n许多开发人员默认使用 DateTime,但在当今分布式系统时代,这往往不是最佳选择。让我们看看关键区别。
DateTime 与 DateTimeOffset
\nDateTime 存储时间点,但未明确关联时区。您可以指定 Kind(Local、Utc、Unspecified),但这只是一个标记,而非完整的偏移信息。而 DateTimeOffset 始终存储相对于 UTC 的偏移量,使其明确无误,更适合存储在数据库和 API 中。
// DateTime — 可能引起误解\nDateTime localNow = DateTime.Now; // Kind = Local\nDateTime utcNow = DateTime.UtcNow; // Kind = Utc\n\n// DateTimeOffset — 始终有明确偏移\nDateTimeOffset preciseNow = DateTimeOffset.Now; // +03:00(示例)\nDateTimeOffset utcOffset = DateTimeOffset.UtcNow; // +00:00\n\n// 两者之间的转换\nDateTimeOffset fromDateTime = new DateTimeOffset(2024, 12, 25, 10, 0, 0, TimeSpan.FromHours(3));\nConsole.WriteLine(fromDateTime.Offset); // 03:00:00\n\n建议: 存储时间点(例如记录创建日期)时,请使用 DateTimeOffset。向用户显示本地时间时,在表示层进行转换。
TimeSpan 用于时间间隔
\nTimeSpan 不存储日期,仅存储时间间隔。它是日期运算和操作持续时间测量的必备工具。
DateTimeOffset start = DateTimeOffset.UtcNow;\n// ... 某个耗时过程 ...\nDateTimeOffset end = DateTimeOffset.UtcNow;\n\nTimeSpan duration = end - start;\nConsole.WriteLine($"操作耗时 {duration.TotalMilliseconds} 毫秒");\n// 创建时间间隔\nTimeSpan workDay = new TimeSpan(8, 0, 0); // 8 小时\nDateTimeOffset deadline = DateTimeOffset.UtcNow.Add(workDay);\n\n\n2. 解析与格式化:区域性、ISO 8601 和性能
\n不正确的解析是处理不同区域设置的应用中缺陷的根源。让我们探讨高级方法。
\n\nParseExact 和 TryParseExact
\n对于已知严格格式的字符串,请使用 ParseExact。这提高了代码的可靠性和可读性。
string dateString = "2024-12-25T10:30:00+03:00";\n// ISO 8601 — 通用格式\nDateTimeOffset parsed = DateTimeOffset.ParseExact(\n dateString,\n "yyyy-MM-dd'T'HH:mm:sszzz",\n CultureInfo.InvariantCulture\n);\nConsole.WriteLine(parsed); // 25.12.2024 10:30:00 +03:00\n\n// 使用 TryParseExact 进行安全解析\nif (DateTimeOffset.TryParseExact(\n "2024/12/25",\n new[] { "yyyy/MM/dd", "dd.MM.yyyy" },\n CultureInfo.InvariantCulture,\n DateTimeStyles.None,\n out DateTimeOffset result))\n{\n Console.WriteLine($"成功解析:{result}");\n}\n\n提示: 在日志和 API 中存储日期时,始终使用 ISO 8601 格式("o" 说明符)。这确保了任何系统都能明确读取。
考虑区域性的格式化
\n向用户输出时,请考虑其区域设置,但内部交换应使用不变区域性。