Как SQL Server определяет формат для неявного преобразования даты и времени?

declare @str_datetime varchar(50)
set @str_datetime='30-04-2012 19:01:45' -- 30th April 2012
declare @dt_datetime datetime
select @[email protected]_datetime

Это приводит к следующей ошибке:

Msg 242, уровень 16, состояние 3, строка 4
Преобразование varchar тип данных для типа данных даты и времени привел к превышению значения.

Мой вопрос в том, как SQL Server решает, какой формат использовать для неявного преобразования даты и времени?

Ответы

Ответ 1

Это может зависеть от множества факторов - региональных настроек операционной системы, текущего языка пользователя и настроек даты. По умолчанию 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

(ошибка)

Msg 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

(ошибка)

Msg 242, уровень 16, состояние 3, строка 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, уровень 16, состояние 3, строка 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

(ошибка)

Msg 242, уровень 16, состояние 3, строка 2
Преобразование varchar тип данных для типа данных даты и времени привел к превышению значения.

Лучше всего всегда использовать стандартные, нерегиональные, безопасные и недвусмысленные форматы даты. Обычно я рекомендую:

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 "Конечный путеводитель по datetime datatypes" и мой пост "Плохие привычки к удару: запросы на обработку/задание неверной обработки" .

Ответ 2

По умолчанию формат даты для SQL-сервера соответствует формату даты в США. MM/DD/YY, , если не установлена ​​локализованная версия SQL Server. Этот параметр подходит для случаев, когда приложение, требующее этого функциональность развертывается способом, гарантирующим, что используются даты и вставлены в том же формате на всех платформах и в местах где используется приложение.

Однако в некоторых случаях дата должна быть в формате DD/MM/YY, потому что многие страны/регионы используют этот формат, а не по умолчанию в США. MM/DD/YY. Это особенно актуально для международных приложений которые распространяются по всему миру.

Источник

Итак, вам, что вам нужно сделать, это установить формат даты перед рукой так:

SET DATEFORMAT dmy
GO

И тогда ваш запрос будет работать.

Ответ 3

Вы также можете изменить формат даты по умолчанию для каждого входа и/или для каждого будущего добавленного входа (без необходимости выполнять "SET DATEFORMAT" в каждом сеансе.

Вы заходите в SQL Management Studio/Security/Logins. Щелкните правой кнопкой мыши логин, затем выберите Свойства. Вы увидите "Язык по умолчанию" внизу.

Если вы хотите, чтобы все логины, добавленные в будущем, получили "хороший" язык. Вы щелкните правой кнопкой мыши на корне сервера, затем на странице "Свойства" и "Дополнительно". Существует также опция "Язык по умолчанию", которая используется для вновь созданных логинов.