【问题标题】:How to handle static time如何处理静态时间
【发布时间】:2014-05-10 15:40:35
【问题描述】:

我正在寻找一些处理和存储静态时间值的最佳做法。

静态时间通常是重复事件的时间,例如体育中心的活动、餐厅的营业时间、电视节目每天播出的时间。

此时间值不受特定日期的约束,并且不受夏令时的影响。例如,一家餐厅在冬季和夏季都会在上午 11:00 营业。

处理这种情况的最佳方法是什么?这种值应该如何存储? 我主要对自动 TimeZone 和 DST 调整(应该避免)以及保持时间值独立于任何特定日期的问题感兴趣。

目前我发现的最佳策略是:

  1. 将时间存储为自午夜以来的整数秒数,
  2. 将时间存储为字符串。

我确实阅读了this question,但主要是关于正常时间值,而不是我描述的用例。

更新

我正在开发的库:github

【问题讨论】:

  • 您是否询问任何特定的语言、平台、数据库等?还是一般?
  • 总的来说,我对处理和存储此类数据的策略很感兴趣。不过,我正在用 Ruby 实现它。

标签: time timezone dst


【解决方案1】:

关于数据库存储,按照从最喜欢到最不喜欢的顺序考虑以下选项:

  • 如果您的数据库支持,请使用 TIME 类型,例如在 SQL Server(2008 及更高版本)、MySQL 和 Postgres 中,或在 Oracle 中使用 INTERVAL HOUR TO SECOND

  • 对小时和分钟使用单独的整数字段(如果需要,还可以使用秒)。如果您的数据库支持,请考虑使用自定义的用户定义类型将它们绑定在一起。

  • 使用带有前导零的 24 小时格式的字符串,例如 "01:23:00""12:00:00""23:59:00"。如果您包含秒数,则总是 包含秒数。您希望保持字符串按字典顺序排序。不要混合和匹配格式。保持一致。

关于存储自午夜以来经过的整分钟(或秒)的方法,我建议避免使用它。当您实际存储经过的持续时间时,这很有效,但在存储一天中的某个时间时就不是很好了。考虑:

  • 并非每天都有午夜。在某些时区(例如:巴西),在春季夏令时转换当天,时钟从 23:59:59 变为 01:00:00。

  • 在具有 DST 的任何时区中,“自午夜以来经过的时间”可能对您撒谎。即使存在午夜,如果您将 10:00 保存为“10 小时”,那么这可能是一个错误的陈述。如果考虑到每年 DST 转换所涉及的两天,那么从午夜开始可能已经过去了 9 小时或 11 小时。

  • 在您的应用程序的某个时间点,您可能会将此时间值应用于某个特定日期。当您这样做时,如果您使用“经过时间”语义,您可能会想简单地将经过时间添加到相关日期的午夜。由于我刚才提到的原因,这将导致 DST 过渡日出现错误。如果您在存储中表示“一天中的时间”,则更有可能将它们正确组合在一起。当然,这在很大程度上取决于您使用的语言和 API。

对于其中任何一个,在使用重复模式时要小心。假设您在酒吧每晚关门时存储“02:00:00”的时间。当 DST 向前跳时,那个时间可能不存在,当它回落时,它会存在两次。当您将时间应用于任何特定日期时,您需要准备好检查这种情况。

您应该做什么完全取决于您的用例。在许多情况下,明智的做法是在前跳间隙中向前跳一小时,并在后退重叠的两个点中选择第一个。但是YMMV。

另请参阅DST tag wiki

对于每个 cmets,看起来 the "tod" gem 足以满足您的 Ruby 代码。

【讨论】:

  • 感谢您的精彩见解。但是,恐怕您错过了重点:我不想支持 DST 或时区。每天早上 10:00 营业的餐厅将在 1 月或 7 月的 10:00 营业,无论是否有 DST。即使 DST 已在前一天晚上开始,餐厅将仍然在 10:00 营业。 :-)
  • 此外,将其保存为“自午夜以来的整数秒数”的想法来自我需要将数据存储在单个数据库列(MySQL 或 Postgres)中。它似乎比使用 VARCHAR 更快。
  • 我明白了。关于存储 - 这些方法中的任何一种都可以。当您将时间应用到特定日期时,您必须关注 DST。因此,您存储餐厅的营业时间为上午 10:00 至次日凌晨 2:00(也许他们有深夜用餐或酒吧)。当你问“餐厅什么时候开放今天”时,就是 DST 发挥作用的时候。
  • 可以使用整数秒或分钟,但你应该小心,因为在应用它时你不能只将那个时间添加到午夜。您还必须针对 DST 进行调整。单独构造时间要容易得多,然后将其与日期结合(而不是添加)。
  • 这是非常好的建议,谢谢。我打算不将这些时间值与日期结合起来(我将它们视为静态标签),但您所描述的绝对是我应该考虑的。例如,我正在实现将它们转换为成熟的 Time 对象的方法,这可能是一项关键操作。
【解决方案2】:

这个问题似乎有点模糊,但我会试一试。

一般来说,使用整数对我来说似乎已经足够了。它易于比较,易于添加或减去持续时间(秒),并且节省空间和时间。如果您使用的是面向对象的语言,您可以考虑将其包装在一个类中。

据我所知,在 C 或 C++ 中没有满足您需求的现有类。

在 .NET 世界中,TimeSpan 类可能对您的目的有用。它有一些便利,例如:您可以从DateTime.TimeOfDay 获取 TimeSpan 值;您可以添加带有间隔的TimeSpanTimeSpan);您可以分别获取小时、分钟和秒组件;等等

如果您使用 Python,datime.time 也是一个不错的选择。它专为像您这样的用途而设计。

我不知道其他语言的其他优秀候选人。

【讨论】:

  • 谢谢。 Python 的datetime.time 听起来正是我想要的。太糟糕了,我和 Ruby 一起工作。是的,我用一个暴露类时间接口的类来包装整数表示。
  • @tompave 我快速检查了一下,没有找到任何符合您要求的“标准”Ruby 类....
【解决方案3】:

为 Java 说话:

在 Java 中,旧的java.util.Date(尽管它的名称是一个全局时间戳)或java.util.GregorianCalendar(它是一种日期、时间和区域等的组合)并没有很好地涵盖您描述的用例.),但是:

Java 8 中,您拥有新的内置类java.time.LocalTime,它很好地涵盖了您的用例。前身是外部和流行的 Java 库 JodaTime 中同名的类 LocalTime,它从 Java 5 开始工作。此外,在我自己的 alpha-state-library 中,我有 net.time4j.PlainTime 类型,它是相似的,但也提供 24:00 支持(例如商店营业时间)。总而言之,Java 是一种非常适合的语言,它具有有趣的时间库,大部分可以做你想做的事。详细:

a) TimeZone 和 DST 调整不由上述 Java 类处理。相反,只有当您将这样一个普通的墙上时间转换为另一种类型(如 org.joda.time.DateTime 包含对时区的引用时)才会处理它们。

b) 事实上,这些时间类也完全独立于日历日期。

c) 内部存储策略适用于 JSR-310 (Java 8):

private final byte hour;
private final byte minute;
private final byte second;
private final int nano;

JodaTime 使用另一种本地毫秒策略(从午夜开始经过的时间)。

【讨论】:

  • 谢谢。自 Java 5 早期以来,我没有使用过 Java,但我明白你的意思。内部存储策略的细节特别有用,因为我在 Ruby 中实现了类似的东西。理想情况下,我想将其存储在单个数据库列中。
【解决方案4】:

除非您还知道日/月/年,否则您无法表示时间。没有“不应该受夏令时影响”这样的事情,因为有许多复杂的问题需要处理,包括闰秒等。在人类看来,时间是一个复杂的东西,不能轻易用数学方法处理。

如果您确实需要存储“上午 11 点”而不关联任何日期,那么这就是您应该存储的内容。只需存储上午 11 点(或者可能只是 11 点,使用 24 小时时间)。

然后,如果您需要进行任何数学运算,则必须在对时间进行任何操作之前应用日期。

我还会避免将“上午 11 点”存储为“距午夜 x 秒”。你真的应该只使用 11 小时,因为这是用户看到的,然后有一个好的日期/时间库将其转换为有用的格式。例如,告诉用户餐厅现在是否营业,您会将其传递给日期库,其中包含今天的日期。

【讨论】:

  • 感谢您的见解。但是我认为 Python 有一个库可以完全按照我的描述进行。
  • @tompave 那么你为什么不把它作为答案发布呢?
  • 其中一个答案中提到了,但在实施策略方面并不是很有帮助。不过,很多人都在添加有趣的观察结果。
猜你喜欢
  • 2018-08-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-07
相关资源
最近更新 更多