21
declare @str_datetime varchar(50)
set @str_datetime='30-04-2012 19:01:45' -- 30th April 2012
declare @dt_datetime datetime
select @dt_datetime=@str_datetime

This is giving following error:

Msg 242, Level 16, State 3, Line 4
The conversion of a varchar data type to a datetime data type resulted in an out-of-range value.

My question is how SQL Server decides which format to use for implicit datetime conversion?

4

3 回答 3

30

这可能取决于多种因素 - 操作系统的区域设置、当前用户的语言和日期格式设置。默认情况下,Windows 使用US English,用户的设置是US EnglishMDY

但这里有一些例子来说明这种情况如何改变。

用户正在使用英国语言​​设置:

-- works:
SET LANGUAGE BRITISH;
SELECT CONVERT(DATETIME, '30-04-2012 19:01:45');

-- fails:
SELECT CONVERT(DATETIME, '04/13/2012');
GO

(错误)

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

用户正在使用法语:

-- works:
SET LANGUAGE FRENCH;
SELECT CONVERT(DATETIME, '30-04-2012 19:01:45');

-- fails:
SELECT CONVERT(DATETIME, '04/13/2012');
GO

(错误)

Msg 242, Level 16, State 3, Line 1
La conversion d'un type de données varchar en type de données datetime a créé une valeur hors limites。

用户再次使用 Français:

SET LANGUAGE FRENCH;

-- fails (proving that, contrary to popular belief, YYYY-MM-DD is not always safe):
SELECT CONVERT(DATETIME, '2012-04-30');
GO

(错误)

Msg 242, Level 16, State 3, Line 1
La conversion d'un type de données varchar en type de données datetime a créé une valeur hors limites。

用户使用 DMY 而不是 MDY:

SET LANGUAGE ENGLISH;
SET DATEFORMAT DMY;

-- works:
SELECT CONVERT(DATETIME, '30-04-2012 19:01:45');

-- fails:
SELECT CONVERT(DATETIME, '04-30-2012');
GO

(错误)

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

您最好的选择始终是使用 ISO 标准、非区域、安全、明确的日期格式。我通常推荐的两个是:

YYYYMMDD                  - for date only.
YYYY-MM-DDTHH:MM:SS[.mmm] - for date + time, and yes that T is important.

这些都没有失败:

SET DATEFORMAT MDY;
SET LANGUAGE ENGLISH;
SELECT CONVERT(DATETIME, '20120430');
SELECT CONVERT(DATETIME, '2012-04-30T19:01:45');
SET LANGUAGE FRENCH;
SELECT CONVERT(DATETIME, '20120430');
SELECT CONVERT(DATETIME, '2012-04-30T19:01:45');
SET LANGUAGE BRITISH;
SELECT CONVERT(DATETIME, '20120430');
SELECT CONVERT(DATETIME, '2012-04-30T19:01:45');
SET DATEFORMAT DMY;
SELECT CONVERT(DATETIME, '20120430');
SELECT CONVERT(DATETIME, '2012-04-30T19:01:45');

因此,我强烈建议不要让用户输入自由文本日期格式(或者您自己使用不可靠的格式),而是控制您的输入字符串并确保它们遵守这些安全格式之一。那么无论用户有什么设置或基础区域设置是什么,您的日期将始终被解释为他们打算成为的日期。如果您当前让用户在表单上的文本字段中输入日期,请​​停止这样做并实现日历控件或至少一个选择列表,以便最终控制传递回 SQL Server 的字符串格式。

有关一些背景知识,请阅读 Tibor Karaszi 的“日期时间数据类型的终极指南”和我的帖子“要踢的坏习惯:错误处理日期/范围查询”。

于 2012-05-01T15:03:05.227 回答
1

您还可以更改每个登录和/或每个未来添加的登录的默认日期格式(无需在每个会话中执行“SET DATEFORMAT”。

您进入 SQL Management Studio / Security / Logins。右键单击登录名,然后单击属性。您将在底部看到“默认语言”。

如果您想确保将来添加的任何登录都获得“好”的语言。您右键单击服务器根目录,然后单击属性和高级页面。那里还有一个“默认语言”选项,用于新创建的登录名。

于 2014-01-15T16:43:43.423 回答
1

默认情况下,SQL Server 的日期格式为美国日期格式 MM/DD/YY,除非已安装 SQL Server 的本地化版本。此设置适用于以下情况:需要此功能的应用程序的部署方式确保在使用该应用程序的所有平台和位置以相同格式使用和插入日期。

但是,在某些情况下,日期必须采用 DD/MM/YY 格式,因为许多国家/地区使用这种格式,而不是美国默认的 MM/DD/YY。对于分布在世界各地的国际申请来说,这尤其是一个问题。

资源

所以你需要做的是事先设置日期格式:

SET DATEFORMAT dmy
GO

然后您的查询将起作用。

于 2012-05-01T14:20:33.853 回答