【问题标题】:How do I stop SQL Server swapping the month and day?如何停止 SQL Server 交换月份和日期?
【发布时间】:2020-04-24 19:39:11
【问题描述】:

我有以下疑问:

DECLARE @someDateTime DATETIME = '2019-12-01 00:00:00.000'; -- 1st December 2019
SELECT @someDateTime;

结果

2019-01-12 00:00:00.000

我预计结果是 2019-12-01 00:00:00.000(2019 年 12 月 1st 日) - 出于某种未知原因,月份和日期互换。

直到最近,我从未对这种格式有任何疑问。

如何以“YYYY-MM-DD HH:mm:ss.000”格式输入日期,并让它在分配给变量/显示在选择中后保持该格式?
什么设置决定了这种可能已经改变的格式?

可能有用的信息

dbcc useroptions

结果:

Set Option | Value
----------   -----
...
language   | British
dateformat | dmy
...

我尝试过的事情:

查询 1

将日期更改为如果交换将无效的内容

DECLARE @someDateTime DATETIME = '2019-12-20 00:00:00.000';
SELECT @someDateTime;

结果:

消息 242,第 16 级,状态 3,第 4 行
将 varchar 数据类型转换为 datetime 数据类型导致值超出范围。

查询 2

变量声明后设置

DECLARE @someDateTime DATETIME;
SET @someDateTime = '2019-12-01 00:00:00.000';
SELECT @someDateTime;

结果 - 不理想:

2019-01-12 00:00:00.000

查询 3

将变量插入到表变量中

DECLARE @someDateTime DATETIME = '2019-12-01 00:00:00.000';
DECLARE @someTable TABLE (someDateTimeColumn DATETIME);
INSERT @someTable VALUES (@someDateTime);
SELECT * FROM @someTable

结果 - 不理想:

someDateTimeColumn
------------------
2019-01-12 00:00:00.000

查询 4

将数据直接插入到表变量中

DECLARE @someTable TABLE (someDateTimeColumn DATETIME);
INSERT @someTable VALUES ('2019-12-01 00:00:00.000');
SELECT * FROM @someTable

结果:不理想

someDateTimeColumn
------------------
2019-01-12 00:00:00.000

查询 5

更改输入字符串的格式

DECLARE @someDateTime DATETIME = '01/12/2019';
SELECT @someDateTime;

结果 - 期望的

2019-12-01 00:00:00.000

查询 6

更改输入字符串的格式

DECLARE @someDateTime DATETIME = '2019-12-01T00:00:00.00';
SELECT @someDateTime;

结果 - 期望:

2019-12-01 00:00:00.000

查询 7

更改输入字符串的格式

DECLARE @someDateTime DATETIME = '2019-12-01';
SELECT @someDateTime;

结果 - 不理想:

2019-01-12 00:00:00.000

查询 8

使用SET DATEFORMAT

SET DATEFORMAT ymd
DECLARE @someDateTime DATETIME = '2019-12-01';
SELECT @someDateTime;

结果 - 期望的

2019-12-01 00:00:00.000

【问题讨论】:

  • SET DATEFORMAT ymd 确实会产生所需的输出。但这在没有它的情况下之前确实有效。我不确定发生了什么变化。
  • 对于初学者,请使用datetime2 而不是datetime。 “新”(15 岁)类型没有旧的怪癖。其次,使用完整的 ISO8601 格式,包括T
  • @marmitegeek 显然有人更改了服务器级别的默认设置。
  • Tibor here 详细讨论了所有内容。短版 - 日期时间的分隔格式受语言设置和日期格式设置的影响。有多种格式总是能被正确解释。

标签: sql sql-server datetime sql-server-2016 datetime-format


【解决方案1】:

您可以使用文字格式 YYYYMMDD,无论您的 SQL Server 的区域设置如何,它始终被解释为年-月-日:

DECLARE @someDateTime DATETIME = '20191201 00:00:00.000';

【讨论】:

  • 正如 OP 所提到的,完整的 ISO8601(带 T)也可以使用
【解决方案2】:

一种解决方案是使用完整的 ISO8601 格式,即2019-12-01T00:00:00.000,另一种解决方案是使用未分隔的日期格式,即20191201 00:00:00.000。更好的解决方案是切换到datetime2

datetime2 是在 15 年前(或者是 11 年前)推出的,以摆脱 datetime 的怪癖,例如毫秒不准确、任意精度、奇怪的算术和......解析特性。比如datetime2对ISO8601格式的解析不受DATEFORMAT的影响:

SET DATEFORMAT ydm
DECLARE @someDateTime DATETIME2(0) = '2019-12-01 00:00:00.000'
select @someDateTime
------
2019-12-01 00:00:00

这可以保护您的代码免受不幸的服务器设置修改

【讨论】:

  • 不知道 ISO8601 +1。每天在这个网站上学习新东西:-)
  • @TimBiegeleisen 这里的问题是,OP 所写的是我们都认为的 ISO8601,除非我们不这样做(即发生错误时)。我肯定会。我没想到完整的格式会是模糊的,例如,只是日期格式。 PS:我应该听从我的建议,把所有东西都切换到datetime2
【解决方案3】:

在阅读了@SMor 评论中的this 文章、我的同事通过 google 搜索发表的评论,并回忆起我几个月前所做的事情后,我想我已经弄清楚发生了什么以及发生了什么变化。

默认情况下,我的数据库用户设置为:

language   | us_english
dateformat | mdy

因此,当读取字符串 '2019-12-01' 时,SQL Server 期待 mm-dd-yyyy

SQL 服务器虽然很聪明。它看到第一部分 2019 并意识到它实际上是年份,所以它将年份移到年底,然后再试一次。*

它现在有12-01-2019,与它所期望的格式相匹配。

当您在 SSMS 中打开帐户属性时,语言下拉菜单默认为列表中的第一种语言 (Arabic)。
几个月前我碰巧在那里做一些不相关的事情,并决定确保我没有不小心将其设置为Arabic,我也会更改它。

我选择了British

我的数据库用户现在设置为:

language   | British
dateformat | dmy

因此,当读取字符串 '2019-12-01' 时,SQL Server 期待 dd-mm-yyyy

一旦它改变了年份,它就会变成12-01-2019,它解释为dd-mm-yyyy,这样我就得到了2019 年 1 月 12 日th 而不是 12 月 1 日st 2019

 

今天是漫长的一天。

 

*请注意,这是对我如何理解此问题的相当简化的解释。这可能不是它在现实中的实际功能,但可以满足我对这个问题的好奇心。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多