.NET 中的 NodaTime 与 System.DateTime:比较

了解 .NET 中 NodaTime 和 System.DateTime 之间的差异,以及如何为日期和时间操作选择最佳选项。

野田时间

  1. 不可变性: NodaTime 类型是不可变的,可确保多线程环境中的安全。不变性意味着实例一旦创建,其值就无法更改。
  2. 领域驱动设计 (DDD): NodaTime 的设计遵循领域驱动设计原则,使其适合对复杂的日期和时间场景进行建模。
  3. 时区: NodaTime 包含一个全面的时区数据库 (TZDB),可提供准确且最新的时区信息。提供对 IANA 时区数据库的支持。
  4. 精度: NodaTime 为时间间隔、持续时间和周期提供更精确的表示。支持纳秒精度。
  5. 清晰度和安全性: NodaTime 类型在即时、本地日期、本地时间等不同概念之间有明确的区别,从而减少了歧义。
  6. 算术运算: 支持各种算术运算,计算更准确。
  7. Entity Framework Core 集成: 支持 Entity Framework Core 与值转换器集成。
  8. 可扩展性: NodaTime 是可扩展的,允许用户创建自己的日期和时间类型。

系统日期时间

  1. 可变性: System.DateTime 是可变的,如果处理不当,可能会导致多线程场景中出现问题。
  2. 有限的时区支持: 对时区的有限支持以及处理与时区相关的操作可能不太简单。
  3. 精度:与 NodaTime 相比,精度有限(低至毫秒)。
  4. 清晰度:System.DateTime 在某些情况下可能不明确,尤其是在处理时区和夏令时更改时。
  5. 算术运算:支持基本算术运算,但涉及月和年的计算可能不太精确。
  6. 实体框架集成:实体框架具有对 System.DateTime 的内置支持,但转换可能需要对时区进行额外处理。

注意事项

  • 用例: 选择 NodaTime 来应对复杂的日期和时间场景、准确的时区处理并提高精度。对于不需要大量日期和时间操作的简单场景,System.DateTime 可能就足够了。
  • 安全性和线程安全性: NodaTime 的不变性提高了安全性,尤其是在并发编程中。
  • 社区和支持: NodaTime 拥有活跃的社区并得到积极维护。
  • 迁移: 如果您有使用 System.DateTime 的现有代码,则迁移到 NodaTime 可能需要仔细考虑和测试。

作为开发人员,参与围绕日期和时间相关挑战的大量团队讨论是一种常见的经历。在这篇博文中,我的目标是分享有关确保全球分布式系统中准确的时区管理的见解。由于云中服务器位置的不可预测性以及这些服务器的本地时间设置的不确定性,这项任务特别具有挑战性。此外,考虑到客户端接入点可能在全球范围内有所不同,以用户本地时区显示日期和时间信息变得至关重要。虽然 C# DateTime 构造可能足以满足基本场景,但它缺乏用户友好的界面来处理复杂的时区操作和根据用户首选项定制的演示。

DateTime 的主要问题是什么?

.NET 中存在 Noda Time 的原因与 Java 中存在 Joda Time 的原因相同:用于处理日期和时间的内置库不够充分。这两个平台提供的表示日期和时间值的类型都太少,这鼓励开发人员真正考虑他们正在处理的数据类型,这反过来又使得难以一致地处理数据。

为什么我们应该考虑改用NodaTime?

在我参与的一个项目中,日期和时间属性分散在整个代码库中,特别是未来的日期和时间。正如 Jon Skeet 的博客文章中强调的那样,这种方法可能会带来重大挑战。虽然最佳实践是以 UTC 存储日期,但并非所有开发人员都遵循此准则。正如 Skeet 提到的,“存储 UTC 并不是灵丹妙药。”将 DateTime 与 EF Core 结合使用时会出现另一个复杂情况,它默认创建 datetime2 列类型。

尽管您可以配置此行为,但它很容易被忽视,从而导致潜在的问题。此外,从 EF Core 检索的 DateTime 对象可能不会将类型指定为 UTC,即使它是这样存储的,这可能会导致各种问题。在此项目中,一些开发人员使用了 ToUniversalTime 或 ToLocalTime 等扩展方法,如果处理不当,可能会在应用程序中引入错误。

NodaTime 和 System.DateTime 是在 .NET 应用程序中处理日期和时间的两种不同方法。下面是 NodaTime 和 System.DateTime 提供的类型之间的比较。

即时与日期时间

  • NodaTime Instant:这表示时间线上的瞬时点,通常以自参考点以来的刻度数表示。
  • System.DateTime:表示特定的时间点,精度可达毫秒。

LocalDate 与 DateTime 与 DateOnly

  • NodaTime LocalDate:表示不带时间部分的日期,确保日期和时间之间的分离更清晰。
  • System.DateTime:同时包含日期和时间,这在某些情况下可能会导致歧义。
  • System.DateOnly:DateOnly 从 .NET 6.0 开始可用;它表示没有时间部分的日期

LocalTime 与 DateTime 与 TimeOnly

  • NodaTime LocalTime:这表示一天中没有日期的时间,当时间是主要关注点时提供更清晰的表示。
  • System.DateTime:始终包含日期信息,这对于某些用例来说可能是不必要的。
  • System.TimeOnly:TimeOnly从.NET 6.0开始可用;它代表没有日期部分的时间

ZonedDateTime 与 DateTime with DateTimeKind

  • NodaTime ZonedDateTime:表示特定时区的日期和时间,避免了与 DateTime 中的 DateTimeKind 相关的陷阱。
  • System.DateTime 和 DateTimeKind:使用 DateTimeKind 来指示 DateTime 是否以 UTC、本地时间或未指定的形式表示,但它有局限性并且容易出错。

OffsetDateTime 与 DateTimeOffset

  • NodaTime OffsetDateTime:表示与 UTC 存在偏移的日期和时间,确保涉及不同偏移的场景中的清晰度。
  • System.DateTimeOffset:与OffsetDateTime类似,但方法和注意事项不同。

LocalDateTime 与 DateTime

  • NodaTime LocalDateTime:表示没有明确时区或偏移量的日期和时间,在时区信息不重要时提供清晰的说明。
  • System.DateTime:包含日期和时间,但可能缺少有关预期时区的信息。

持续时间和周期与时间跨度

  • NodaTime 持续时间/周期:提供单独的类型来表示时间跨度和基于日历的周期,防止两者之间发生混淆。
  • System.TimeSpan:这表示持续时间,但没有针对基于日历的时间段的专用类型。

DateTimeZone 与 TimeZoneInfo

  • NodaTime DateTimeZone:这代表时区,与 TimeZoneInfo 相比,提供更好的功能和清晰度。
  • System.TimeZoneInfo:提供时区信息,但有一些限制。

类型之间的转换

下图显示了类型之间转换的各种不同方式。

#dotnet  #aspdotnet 

.NET 中的 NodaTime 与 System.DateTime:比较
1.45 GEEK