tl;博士
用途:
YYYY-MM-DDTHH:MM:SS.S…Z
2016-09-17T18:28:27Z
严格的 ISO 8601 格式
Answer by GVillani82 是正确的,应该被接受。唯一的问题是引用了错误声明的 SQLite 文档:
TEXT 作为 ISO8601 字符串 ("YYYY-MM-DD HH:MM:SS.SSS")
该语句有两点错误:中间的空格和小数部分的三位数字。
T 在中间
严格来说,中间有空格的格式不符合ISO 8601。 ISO 8601 标准要求在中间使用T,而不是空格。引用 the Wikipedia page 总结 ISO 8601 标准:
…连接完整的日期表达式、作为分隔符的字母 T 和有效的时间表达式。例如,“2007-04-05T14:30”。
T 只能在数据发送者和接收者的特殊安排下被替换为空格。
更令人困惑的是,中间有空格的格式确实符合 SQL 标准对日期时间格式的定义。 SQL 规范早于 ISO 8601。ISO 8601 正迅速成为首选格式,因为它继续在全球范围内被商业世界以及现代计算机协议采用。
小数部分
ISO 8601 标准允许秒的小数部分中包含任意数量的数字。引用的文档暗示需要三个数字,但实际上允许任何数字,包括零(根本没有数字,整秒)。
三位代表milliseconds,六位代表microseconds,九位代表nanoseconds。这些都是主流的面向业务的应用程序中常用的。任何更精细的部分只能在科学/工程类型的应用中看到。
java.time 类使用nanosecond 分辨率,而旧的日期时间Java 类仅限于毫秒。
实用性
这两个问题不仅仅是学术问题,而是提出了实际问题。
在 Java 环境中,我们可能会从 SQLite 中提取此字符串,然后将其解析为 java.time 对象。 java.time 类是处理日期时间编程的现代方式。这个框架的灵感来自Joda-Time(领导这项工作的同一个人,Stephen Colbourne),由JSR 310 定义,内置于 Java 8 及更高版本中,正式取代了麻烦的旧日期时间类,向后移植到 Java 6 和 7在ThreeTen-Backport 项目中并进一步适应Android 在ThreeTenABP 项目中。
在解析/生成表示日期时间值的字符串时,java.time 类默认使用标准 ISO 8601 格式。但是 java.time 只使用严格的定义。这意味着 T 在日期时间的中间。
Instant instant = Instant.parse( "2016-09-17T18:28:27Z" );
问题是解析被SQLite文档错误标记为ISO 8601的格式,中间有SPACE将无法被java.time解析。换个方向,java.time 生成的字符串默认会在中间有T,而不是SPACE。
解决方案很简单:只需使用严格的 ISO 8601 定义,中间加上 T。
如果您对SQLite documentation page on date-time functions 进行了足够深入的阅读,您会看到它提到:
...“T”是分隔日期和时间的文字字符,符合 ISO-8601 的要求
这种带有T 的格式受SQLite 及其日期时间函数的支持。此外,该文档指出,Z 的时区指示符也支持Zulu UTC。
...可以选择后跟“[+-]HH:MM”或只是“Z”形式的时区指示符。日期和时间函数在内部使用 UTC 或“zulu”时间,因此“Z”后缀是空操作。
因此,我建议将在 SQLite 中存储时刻的最明智方法调整为 UTC,并使用严格的 ISO 8601 格式,包括末尾的 Z:2016-09-17T18:28:27Z
至于小数秒,SQLite 文档说,虽然只有前三个小数位数对其 SQLite 函数有意义,但您实际上可以存储任意数量的数字。因此,java.time 中允许的纳秒内最多 9 位数字显然可以成功存储,尽管没有精确比较:2016-09-17T18:28:27.123456789Z
如果这种比较精度对您的应用来说是个问题,您可以使用可以处理纳秒的 java.time 类在应用的 Java 端进行比较工作,或者您可以考虑将日期时间值截断为毫秒解析度。 java.time 类提供了一种方便的截断方法。
其他选项
选项呢?
- REAL 作为儒略日数。
- INTEGER 作为 Unix 时间,自 1970-01-01 00:00:00 UTC 以来的秒数。
Floating point technology 用于实数,例如 Java 中的float/Float 和double/Double,故意牺牲准确性来换取执行速度。这意味着无关的数字经常出现在分数的右侧。虽然这在某些科学/工程/游戏领域可能是可以容忍的,但在金钱问题或日期时间值的某些用途中是不可接受的。所以,在我看来,这不是一个好主意。
从-epoch 计数,例如自 1970 年初以来 UTC 的秒数不是一个好主意。虽然 java.time 类在后台使用这种方法来实际跟踪时间,但我们有这些封面是有原因的。这样的整数对人类读者没有意义,无法辨别日期时间值,因此可能无法检测到错误。数据类型本身是模棱两可的,因为我们必须猜测预期的粒度,一些计算机系统使用整秒作为计数,其他计算机系统使用毫秒或微秒或纳秒或其他粒度。至于时代,这也是模棱两可的,因为至少有一个couple dozen epoch points 已在各种计算系统中使用。
其他数据库
请注意,SQLite 从来没有打算成为一个严肃的重型数据库。因此,SQLite 中的lite。 inventor has explained 他打算让 SQLite 成为编写纯文本文件的升级替代方案。他从未打算让 SQLite 成为更严肃的数据库的竞争对手。
因此,如果您遇到 SQLite 限制的痛点,您的需求可能已经超出了 SQLite 的设计参数。如果您需要更严肃的数据库,请使用更严肃的数据库。
在 Android 环境中,我首先考虑的是H2 Database Engine。这种纯 Java、开源、免费的数据库产品正在积极开发并越来越受欢迎。见: