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 你的意思是datetimeoffset
? datetime2
也不考虑时区。值得注意的是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 建议使用ymd
或y-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