TSQL 日期时间 ISO 8601

Posted

技术标签:

【中文标题】TSQL 日期时间 ISO 8601【英文标题】:TSQL DATETIME ISO 8601 【发布时间】:2010-10-23 05:32:02 【问题描述】:

我得到了一个需要 ISO 8601 日期格式的规范,有人知道转换代码或获取这两个示例的方法吗:

ISO 8601 Extended Date 2000-01-14T13:42Z 
ISO 8601 Basic Date 20090123T105321Z

【问题讨论】:

@WonderWorker 你的意思是datetimeoffsetdatetime2 也不考虑时区。值得注意的是datetimeoffset 不处理夏令时。 【参考方案1】:

这是一个非常古老的问题,但是由于我是在搜索时来到这里的,所以值得提出我的答案。

SELECT DATEPART(ISO_WEEK,'2020-11-13') AS ISO_8601_WeekNr

【讨论】:

【参考方案2】:

对于日期时间和日期时间 2 的 ISO 8601 格式,以下是 SQL Server 的建议。它不支持 datetime(yyyyMMddThhmmss) 的基本 ISO 8601 格式。

日期时间

YYYY-MM-DDThh:mm:ss[.mmm]

YYYYMMDD[hh:mm:ss[.mmm]]

例子:

    2004-05-23T14:25:10

    2004-05-23T14:25:10.487

日期时间2

YYYY-MM-DDThh:mm:ss[.nnnnnn]

YYYY-MM-DDThh:mm:ss[.nnnnnn] 例子:

    2004-05-23T14:25:10

    2004-05-23T14:25:10.8849926

您可以使用 126 选项转换它们

--Datetime

DECLARE @table Table(ExtendedDate DATETIME, BasicDate Datetime)

DECLARE @ExtendedDate VARCHAR(30) = '2020-07-01T08:39:17' , @BasicDate VARCHAR(30) = '2009-01-23T10:53:21.000'

INSERT INTO @table(ExtendedDate, BasicDate)
SELECT convert(datetime,@ExtendedDate,126) ,convert(datetime,@BasicDate,126)

SELECT * FROM @table
go

-- Datetime2

DECLARE @table Table(ExtendedDate DATETIME2, BasicDate Datetime2)

DECLARE @ExtendedDate VARCHAR(30) = '2000-01-14T13:42:00.0000000' , @BasicDate VARCHAR(30) = '2009-01-23T10:53:21.0000000'

INSERT INTO @table(ExtendedDate, BasicDate)
SELECT convert(datetime2,@ExtendedDate,126) ,convert(datetime2,@BasicDate,126)

SELECT * FROM @table
go

日期时间

+-------------------------+-------------------------+
|      ExtendedDate       |        BasicDate        |
+-------------------------+-------------------------+
| 2020-07-01 08:39:17.000 | 2009-01-23 10:53:21.000 |
+-------------------------+-------------------------+

日期时间2


+-----------------------------+-----------------------------+
|        ExtendedDate         |          BasicDate          |
+-----------------------------+-----------------------------+
| 2000-01-14 13:42:00.0000000 | 2009-01-23 10:53:21.0000000 |
+-----------------------------+-----------------------------+

【讨论】:

【参考方案3】:

如果您只需要以 ISO8601 格式输出包含尾随 Z 的日期,并且您至少在 SQL Server 2012 上,那么您可以使用FORMAT

SELECT FORMAT(GetUtcDate(),'yyyy-MM-ddTHH:mm:ssZ')

这会给你类似的东西:

2016-02-18T21:34:14Z

正如@Pxtl 在评论中指出的,FORMAT 可能会影响性能,与它带来的任何灵活性相比,必须考虑成本。

【讨论】:

这样更简洁,谢谢! 如何获得百万秒 SELECT FORMAT(GetUtcDate(),'yyyy-MM-ddTHH:mm:ss.SSSZ') 不适用于 SSS SELECT FORMAT(GetUtcDate(),'yyyy-MM-ddTHH:mm:ss.fffZ')对你有用吗? @ideAvi 我同意它更简洁,但请注意它可以是problematic at scale。【参考方案4】:

在谈到 ISO 日期时,从技术上讲,您有两种选择。

一般而言,如果您专门过滤 日期 值或希望以中性方式保留日期。 Microsoft 建议使用ymdy-m-d 的语言中性格式。两者都是有效的 ISO 格式。

请注意,“2007-02-12”形式仅被视为与语言无关 对于数据类型 DATE、DATETIME2 和 DATETIMEOFFSET。

因此,您最安全的选择是基于 always netural ymd 格式进行持久化/过滤。

代码:

select convert(char(10), getdate(), 126) -- ISO YYYY-MM-DD
select convert(char(8), getdate(), 112) -- ISO YYYYMMDD (safest)

【讨论】:

【参考方案5】:

在 SQL Server 中处理日期时,ISO-8601 格式可能是最好的选择,因为无论您的语言和文化设置如何,它都能正常工作。

为了将数据插入到 SQL Server 表中,您根本不需要任何转换代码或任何东西 - 只需将日期指定为文字字符串

INSERT INTO MyTable(DateColumn) VALUES('20090430 12:34:56.790')

你就完成了。

如果需要在 SELECT 上将日期列转换为 ISO-8601 格式,可以使用转换代码 126 或 127(带时区信息)来实现 ISO 格式。

SELECT CONVERT(VARCHAR(33), DateColumn, 126) FROM MyTable

应该给你:

2009-04-30T12:34:56.790

【讨论】:

@Jeremy Ross - 使用 CONVERT(nvarchar(30), DateField, 126)。那么你应该得到 2004-12-14T10:05:59.000 如果字段是 datetimeoffset,126 似乎包含时区信息。 127 将其转换为 UTC。 @hvd 这可能证明 varchar 与 char 是合理的(如果尾随空格会成为问题;我对此表示怀疑);这并不意味着你应该完全放弃一个长度。请read this in full。这是关于一致性并且始终使用明确的长度,即使它似乎并不重要。至于 DateField 与 DateColumn - 因为我是人类? @hvd 那么为什么要删除长度呢?如果您真的想要,您可以通过使用varchar(23)(使用旧日期/时间数据类型的最长可能值)或varchar(33)(新类型的最长可能值)并更正我错过的名称来改进我的编辑只是完全撤消它。现在,您的回复实际上会默默地截断 datetimeoffset 值,因为当您不包含长度时,在这种情况下,它将截断为 30 个字符。至少在我的编辑下,对于为什么不会有任何混淆。 @marc_s 127 也不添加 Z。【参考方案6】:

天哪,不!如果您在 SQL Server 中存储格式化的日期,您将面临一个痛苦的世界。始终存储您的日期和时间以及 SQL Server“日期/时间”数据类型之一(DATETIME、DATE、TIME、DATETIME2 等)。让前端代码解析显示方法,并且仅在您构建临时表以从中构建文件时存储格式化的日期。如果您绝对必须从 SQL Server 显示 ISO 日期/时间格式,请仅在显示时执行。我怎么强调都不为过……不要在 SQL Server 中存储格式化的日期/时间。

编辑。造成这种情况的原因有很多,但最明显的是,即使使用良好的 ISO 格式(可排序),所有未来的日期计算和搜索(例如,搜索给定月份中的所有行)都至少需要一个隐式转换(这需要额外的时间),如果存储的格式化日期不是您当前需要的格式,您需要先将其转换为日期,然后再转换为您想要的格式。

前端代码也是如此。如果您存储格式化的日期(即文本),它需要相同的旋转来显示由 Windows 或应用程序定义的本地日期格式。

我的建议是始终将日期/时间存储为 DATETIME 或其他时间数据类型,并且仅在显示时间格式化日期。

【讨论】:

我认为您误解了 - 将 '20121001' 插入 DateTime 列将始终转换相同,无论区域设置如何 - Marc 并不是建议列类型应该是字符串。 -1 OP 询问如何 完成某事,而不是询问是否应该完成的建议。这不是原始问题的答案,而是基于对用户最初提出问题的原因几乎没有洞察力的意见。 OP 很可能对此有严格的要求,而您的回应根本没有帮助他。这类东西应该作为 cmets 发布。答案应始终提供答案。 @Blockloop,如果有人问如何朝自己的头部开枪,你不告诉他们这不是一个好主意,就像不告诉那些问如何做错事的人一样失职SQL 服务器。其他赶时间的人可能不会花时间阅读单纯的 cmets。 ;-) @JeffModen “答案应始终提供答案”直接引用自 FAQ。您的回复没有回答 OP 的问题。如果说这个比喻的人即将被活活烧死,那么头部中的一枪是更好的选择。上下文杀死。 ;-) 如果您必须告诉 OP 为什么您认为他的决定是错误的,请在回答之前说明原因。 @Blockloop,回头看看,你是绝对正确的。我认为人们会知道原因是理所当然的。谢谢你的好意见。尽管我迟到了几年,但我已经更新了我的回复。【参考方案7】:

这个

SELECT CONVERT(NVARCHAR(30), GETDATE(), 126)

会产生这个

2009-05-01T14:18:12.430

更多详情请访问MSDN。

【讨论】:

赞成这个答案,因为 NVARCHAR 不返回空格填充。 你不需要包含 (30) 部分。 @PhillipSenn 我强烈建议保留它,即使它在技术上是多余的。没有明确大小的nvarchar 在某些情况下默认为30,在其他情况下默认为1,这会损害可读性。试试select convert(nvarchar, getdate(), 126); declare @v nvarchar = convert(nvarchar, getdate(), 126);:第一条语句表明这不会截断。第二条语句看起来好像该值存储在完全相同类型的变量中。我想说,这是 SQL Server 的一个非常不直观的方面。 @RichardAyotte 空间填充什么时候重要? GETDATE() 何时会包含 Unicode 字符(换句话说,为什么是 nvarchar 而不是 varchar)? @AaronBertrand varchar 更好。我注意到你更新了接受的答案,所以我的投票和评论现在已经过时了。

以上是关于TSQL 日期时间 ISO 8601的主要内容,如果未能解决你的问题,请参考以下文章

在 Excel 中解析 ISO8601 日期/时间(包括 TimeZone)

Tabulator 5.0 - 解析日期时间 luxon - 日期时间 ISO 8601

日期和时间格式(ISO 8601)

将时区偏移量(ISO 8601 格式)添加到原始日期时间

将 ISO 8601 日期时间字符串转换为 **Date** 对象时,如何将日期时间重新定位到当前时区?

ORA-01821: 本地时间的 ISO 8601 日期的日期格式无法识别错误