SQL Server如何确定隐式日期时间转换的格式?

时间:2012-05-01 14:11:56

标签: sql-server datetime implicit-conversion implicit

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

这会出现以下错误:

  

Msg 242,Level 16,State 3,Line 4
转换varchar   数据类型为日期时间数据类型导致超出范围的值。

我的问题是SQL Server如何决定使用哪种格式进行隐式日期时间转换?

3 个答案:

答案 0 :(得分:26)

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

但是这里有一些例子来说明这是如何改变的。

用户正在使用BRITISH语言设置:

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

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

(错误)

  

Msg 242,Level 16,State 3,Line 5
转换varchar数据   键入日期时间数据类型会导致超出范围的值。

用户正在使用Français:

-- 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éesvarcharen typededonnéesdatetimeacrééunevaleur hors   限制一个。

用户再次使用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 typededonnées   varchar en typededonnéesdatetimeacrééunevaleur 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

(错误)

  

Msg 242,Level 16,State 3,Line 2
转换varchar   数据类型为日期时间数据类型导致超出范围的值。

您最好的选择是使用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的"The ultimate guide to the datetime datatypes"和我的帖子"Bad Habits to Kick : Mis-handling date / range queries."

答案 1 :(得分:1)

  

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

     

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

Source

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

SET DATEFORMAT dmy
GO

然后你的查询就可以了。

答案 2 :(得分:1)

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

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

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