Shw*_*ain 18 sql-server datetime implicit implicit-conversion
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
Run Code Online (Sandbox Code Playgroud)
这会产生以下错误:
消息242,级别16,状态3,行4
将varchar数据类型转换为日期时间数据类型导致超出范围的值.
我的问题是SQL Server如何决定使用哪种格式进行隐式日期时间转换?
Aar*_*and 27
这可能取决于多种因素 - 操作系统的区域设置,当前用户的语言和日期格式设置.默认情况下,Windows使用US English,用户的设置为US English和MDY.
但是这里有一些例子来说明这是如何改变的.
用户正在使用BRITISH语言设置:
-- works:
SET LANGUAGE BRITISH;
SELECT CONVERT(DATETIME, '30-04-2012 19:01:45');
-- fails:
SELECT CONVERT(DATETIME, '04/13/2012');
GO
Run Code Online (Sandbox Code Playgroud)
(错误)
消息242,级别16,状态3,行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
Run Code Online (Sandbox Code Playgroud)
(错误)
Msg 242,Level 16,State 3,Line 1
La conversion d'un typededonnéesvarcharen typededonnéesdatetimeacrééunevaleur 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
Run Code Online (Sandbox Code Playgroud)
(错误)
Msg 242,Level 16,State 3,Line 1
La conversion d'un typededonnéesvarcharen 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
Run Code Online (Sandbox Code Playgroud)
(错误)
消息242,级别16,状态3,行2
将varchar数据类型转换为日期时间数据类型导致超出范围的值.
您最好的选择是使用ISO标准,非区域,安全,明确的日期格式.我通常推荐的两个是:
YYYYMMDD - for date only.
YYYY-MM-DDTHH:MM:SS[.mmm] - for date + time, and yes that T is important.
Run Code Online (Sandbox Code Playgroud)
这些都没有失败:
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');
Run Code Online (Sandbox Code Playgroud)
因此,我强烈建议您不要让用户输入自由文本日期格式(或者您自己使用不可靠的格式),而是控制输入字符串并确保它们遵循这些安全格式之一.然后,无论用户具有什么设置或基础区域设置是什么,您的日期将始终被解释为它们的预期日期.如果您当前正在让用户在表单上的文本字段中输入日期,请停止执行该操作并实现日历控件或至少一个选择列表,以便最终控制传递回SQL Server的字符串格式.
在某些背景下,请阅读Tibor Karaszi的"日期时间数据类型的终极指南"和我的帖子"Kick Bad Babits :错误处理日期/范围查询".