DateTime、Epoch 和 DocumentDb

DateTime, the Epoch and DocumentDb

所以我阅读了这篇关于使用 datetime in Azure DocumentDb 的非常有趣的博客。问题在于,目前 Azure DocumentDb 不支持日期时间字段的范围搜索。原因是 DocumentDb 基于 json 并且没有日期时间类型,因此通常将其放在 xml 日期时间格式的字符串中。

(显然 Mongo 没有那个问题,它的 bson 格式添加了 datetime 类型(以及其他))

无论如何,这篇文章描述了在 json 中以纪元 (unix) 时间存储日期时间,本质上是将日期时间存储为自 01-01-1970 以来的秒数。 epoch 的一个问题是它不考虑闰秒,但我现在可以接受。

我的问题是我也想以这种格式存储出生日期。现在我可以将 01-01-1900 作为开始日期并将自该日期以来的天数存储在一个 int 中。虽然我很确定这会很好,但感觉纪元是一个成熟的概念,但生日的感觉就像我在建立自己的约定,这是我通常想避免的事情。

是否有将日期存储标准化为数字的既定标准?哪个日期应该是基准日期?

根据我的经验,我还没有遇到比 UNIX 时代更 'established' 的标准。话虽如此,之前已经讨论了时间存储的一些 architectural/technological 方面: Timestamps and time zone conversions in Java and MySQL

我想问为什么要冒险使用您自己的约定?这是一个风险,因为:如果某个时候你想增加一天的时间,也许可以根据人们出生的确切时间来排序。这个问题可以扩展到:如果在某个时候你想测量更通用或更细粒度的时刻怎么办?您将不得不将整个功能(可能贯穿应用程序的许多层)转换为更通用的 mechanism/convention。另一个(类似的)问题是:您是否始终为数据库中的人员测量千载难逢的事件,或者他们是否能够创建新的、无限的事件?随着事件数量的增加,碰撞的风险也会增加,并且天数将不如以秒或毫秒为单位的时间戳更合适。

UNIX 时间基本上无处不在,在大多数编程语言中您都有特殊的方法来获取它。我将在我的项目中始终支持和实施的计时架构是这样的: http://www.currentmillis.com/tutorials/system-currentTimeMillis.html

正如我对上面链接问题的回答中所述,自 UNIX 纪元以来将时间存储为毫秒的优点是:

  • 架构清晰:服务器端使用 UTC,客户端显示 通过当地时区的时间
  • 数据库简单:你存储一个 数字(毫秒)而不是像这样的复杂数据结构 日期时间
  • 编程效率:在大多数编程语言中,您 有 date/time 个对象自 Epoch 以来能够花费毫秒 构造时(允许自动转换 到客户端时区)

因为您提到了 C#,所以想到了 DateTime.MinValue。这基本上是第 0 年(1 月 1 日午夜)。

此外,这将是一些代码,可以让您获得自您选择的参考日期(无论它是什么)以来的毫秒数,但请注意,1900 仍然不同于 .NET 的 'epoch'(DateTime.MinValue)

// Unix Epoch
(DateTime.UtcNow - new DateTime (1970, 1, 1)).TotalMilliseconds
// NTP Epoch
(DateTime.UtcNow - new DateTime (1900, 1, 1)).TotalMilliseconds

是正确的,除了我怀疑 "well established",数十亿的 Microsoft Excel、LibreOffice 和 Lotus 1-2-3 电子表格都有自己的epoch 可能远远超过 Unix 时间使用量。或者十亿台 Apple Cocoa 设备和电脑都有自己的时代。

请注意,couple dozen different epochs 已被各种计算机环境使用。 Unix 时代远非孤立无援,甚至不占主导地位。

另请注意,没有 Unix time 这样的东西。变体包括使用整秒、毫秒、微秒或纳秒。

如果可能,使用日期时间数据类型。请务必研究文档并进行实验以清楚地了解它的行为。

在无法使用数据类型的情况下,回退到使用各种 ISO 8601 格式的字符串。其中一些标准格式按字母时间顺序排序,尤其是对于仅日期值:YYYY-MM-DD。

我所知道的每个日期时间跟踪系统都忽略了闰秒。它们的目的是让我们的小时时钟与日历同步,因此出于商业目的,Leap Second 在某种意义上应该被忽略。

约会时间工作是一项非常棘手和狡猾的工作。搜索 Whosebug 以发现许多问题。尽量避免推出自己的解决方案。特别是对于 C#,请查看 Noda Time library.

首先,更新:DocumentDB 现在支持字符串和数字的范围索引。您必须正确设置索引才能正常工作。

现在,给大家推荐一下。我已经成功地将 ISO-8601 时间戳存储为字符串。这是 DocumentDB SDK 用于处理 DateTime 的默认格式,因此它比转换为整数更省力。

ISO-8601 date/time 字符串有几个符合您需要的属性。

  1. 字母数字排序顺序是按时间顺序排列的,因此它与使用 >、<、>=、<= 和 BETWEEN 的查询子句完美配合,假设您具有适当精度的范围索引(-1 表示全精度);
  2. 它们是人类可读的,所以如果您正在浏览 table,数据是有意义的;
  3. 此格式允许指定更小的粒度 date/time。例如,您应该说“2015-03”表示三月,或者说“2015-03-24”表示 2015 年 3 月 24 日。然后您可以使用此过滤器 "startedOn >= 2015-03-24 AND startedOn < 2015-03-25" 发出查询以查找所有内容于 2015 年 3 月 24 日开始。由于字符串比较的性质,即使 startedOn 存储为完整的 ISO-8601 字符串(如“2015-03-24T12:34:56.789Z”),此方法也有效。

我已经写过关于这种方法的文章 here