【问题标题】:What's best practice to represent a Time object in C#?在 C# 中表示 Time 对象的最佳做法是什么?
【发布时间】:2011-04-10 23:34:06
【问题描述】:

我在数据库表中有一个时间列。日期并不重要,我们只想要一天中的某个时间。什么类型最适合用 C# 来表示它?我打算使用 DateTime,但我不喜欢约会的想法。

【问题讨论】:

标签: c# datetime


【解决方案1】:

虽然其他答案大多是正确的,TimeSpan 是唯一可以工作的内置类型,但重要的是要认识到“经过的时间测量”和“一天中的时间”之间存在明显差异.

  • 最明显的区别是一天中的某个时间必须少于 24 小时。 TimeSpan 对象可以覆盖的范围远不止这些。

  • 另一个区别是TimeSpan 类型可以是否定的。这代表时间倒退。负值作为时间是没有意义的。

  • 最后,时间包括任何可能适用于其所在时区的夏令时概念。因此,您不能将其视为“自午夜以来经过的时间”。

    • 如果是春季 DST 转换的那一天(在美国),则值 4:00 从午夜开始仅过去了 3 小时。
    • 如果是回退 DST 过渡的那一天(在美国),则值 4:00 实际上已经过去了 5 小时自午夜以来。
    • 而且由于世界各地的 DST 都不同,午夜完全有可能根本不存在,或者存在两次。这种情况发生在巴西等地。

因此,如果您使用TimeSpan 作为一天中的时间,您需要注意这些问题。 .NET 没有针对一天中某个时间的内置类型,因此这是一个可接受的折衷方案,即使它违反了它自己的设计。

即使是 .NET Framework 本身也做出了这种妥协。例如:

  • DateTime 类有一个TimeOfDay 属性,该属性返回一个TimeSpan
  • 如果您在 SQL Server 中有 time 类型,则通过 .NET SQL 客户端返回时它将是 TimeSpan

MSDN Reference DocumentationTimeSpan 类型有这样的说法:

TimeSpan 结构也可用于表示一天中的时间,但前提是时间与特定日期无关。否则,应使用 DateTime 或 DateTimeOffset 结构。

这基本上是我在上面第三点中提到的关于夏令时的另一种说法。

但是,如果您对在设计中做出妥协不感兴趣并且想要实时类型,那么请查看 Noda Time 库。

  • LocalTime 类型,它代表一天中的某个时间。 这是对所提问题的直接回答。
  • 有一个Duration 类型,它表示经过的时间度量。
  • 还有一个Period 类型,它表示日历上的位置移动——这是TimeSpan 无法做到的。例如,“3 年零 5 个月”将是 Period 值。
  • 还有一个Offset 类型,它类似于Duration,但用作时区的UTC 偏移量。它的范围仅限于该目的。

虽然有些人可能会说TimeSpan 更通用,因为它可以处理所有这些,但事实是它会让你陷入困境。通过分离类型,您可以获得安全性和一致性。

或者,您可以考虑将 Microsoft 提供的 System.Time 包作为 CoreFX Lab 的一部分。此包包含名为Time 的仅时间类型和名为Date 的仅日期类型的实现。您将需要使用 dotnet-corefxlab MyGet 提要来导入此包。

【讨论】:

  • 你只是想让它变得更复杂。其中大部分与问题根本无关。
  • @Guffa - 问题是“用 C# 表示它(一天中的某个时间)最好的类型是什么?” - 答案是来自 Noda Time 库的 LocalTime 类型。剩下的就是理由。
  • 你在这句话中给出了你自己对“它”的解释,但这不是问题所在。 OP 具有来自具有特定类型的数据库列的值,并且需要 C# 中的相应类型。没有比这更复杂的了。
  • @Guffa - 显然我们同意不同意。我坚持我的立场,我尊重你的立场。美好的一天。
【解决方案2】:

您可以在 .NET 中使用 TimeSpan 结构来表示时间。

【讨论】:

  • 但是 TimeSpan 不是一个时间范围吗?显然,结束时间未知,活动可能会从下午 2 点开始,并无限期地持续下去。使用 TimeSpan 仍然是个好主意吗?
  • 但是一天中的某个时间实际上只是从午夜开始经过的时间。所以,同样的概念,真的。
  • 我试试这个。谢谢。
  • @dommer - 不完全是。看我的回答。
  • TimeSpan 代表时间间隔。最好的方法应该是使用 DateTime 的时间组件。
【解决方案3】:

Jon Skeet 一直在研究名为 Noda Time 的东西,也许这会有所帮助。

Skeet 关于为什么它可能适合您的帖子:What's Wrong with DateTime Anyway?

【讨论】:

    【解决方案4】:

    你可以试试这样的

    TimeSpan ts = DateTime.Now.TimeOfDay
    

    您在哪里应用 DateTime 对象的时间属性并使用它。

    【讨论】:

      【解决方案5】:

      使用时间跨度来表示从午夜到时间的时间跨度。

      【讨论】:

      • 这是一种常见的误解,或者说是一种妥协。请参阅我的答案以了解更多详细信息。
      • @MattJohnson:不,这既不是误解也不是妥协。即使您对夏令时的看法是正确的,这也与问题无关,因为数据库中的数据类型具有完全相同的问题。使用 Timespan 保存 Time 值不会引入您提到的问题。
      • 嗨。实际上,不,这不是真的。假设他在谈论SQL Server time type,它代表一天中的时间,而不是经过的时间。我也谈到了这一点in this answer。在现实生活中,这可能会在用户输入验证中对您造成影响。字符串可能可以解析为有效的TimeSpan,但不适合数据库中的time 列。如果用户输入 24:00 作为一天中的某个时间,除非您采取额外步骤进行范围验证,否则这将失败
      • @MattJohnson:不,抱歉,你弄错了。这是真的。如果你愿意,你可以试着让它变得复杂,但事实并非如此。如何将值解析为 Timespan 值也与问题无关。
      【解决方案6】:

      我将使用TimeSpan 来表示这一点,TimeSpan 是自午夜以来的时间跨度。这与框架中 DateTime 的 TimeOfDay 属性相关。

      【讨论】:

      • 不完全是。看我的回答。
      • @MattJohnson 我看不出您的回答中的任何内容如何否定我写的内容。是的,TimeSpan 可以表示其他时间,但也可以完全接受用于表示从 (0,24] 小时开始的时间。
      • 嗨里德。一天中的时间实际上是[0,24),但无论如何,重点是我回答的第三个项目符号。您不能只说这是“自午夜以来经过的时间”,因为有些值是不正确的。 MSDN 参考的说法略有不同,我将更新我的答案以反映这一点。
      • @MattJohnson 我不是在和你争论,但TimeSpan 确实允许你表示 为真的值,这就是我所说的。
      • 当然。这就是为什么我称之为“妥协”。不是试图开始争论,只是这是一个常见的错误来源,所以我尽量做到准确。
      【解决方案7】:

      我们实际上推出了自己的 Time 课程。我们遇到的问题是 TimeSpan 不知道我们仍然需要的时区偏移量。所以我们创建了一个 TimeSpanOffset 类。有点类似于 DateTimeOffset 类。如果时区不重要,我肯定会坚持使用 TimeSpan。

      【讨论】:

        【解决方案8】:

        鉴于这个问题是我刚刚在 Google 搜索中获得的最高结果,可能值得一提的是,在即将发布的 .NET 6(目前定于 2021 年 11 月 9 日)之后,该问题的正确答案可能是the new TimeOnly struct.

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-11-07
          • 1970-01-01
          • 1970-01-01
          • 2011-02-27
          • 1970-01-01
          • 2022-01-01
          • 2019-05-10
          • 1970-01-01
          相关资源
          最近更新 更多