SQL datetime2 не может хранить дату и время

Похоже, что datetime2 в некоторых случаях не может содержать значение datetime. Ожидается ли это?

Обратите внимание на последние 2 столбца. Или это преобразование портит данные?

SELECT
    DATETIMEFROMPARTS (2021, 2, 28, 10, 11, 12, 267),
    CONVERT(datetime, DATETIMEFROMPARTS (2021, 2, 28, 10, 11, 12, 267)),
    CONVERT(datetime2, DATETIMEFROMPARTS (2021, 2, 28, 10, 11, 12, 267)),
    CAST(DATETIMEFROMPARTS (2021, 2, 28, 10, 11, 12, 267) AS datetime2)

введите здесь описание изображения

Мне на самом деле не нужны эти преобразования, но у меня проблемы с Entity Framework, который генерирует SQL, преобразующий мой datetime в datetime2, что приводит к небольшим различиям при загрузке его в C# DateTime


person Stig    schedule 28.02.2021    source источник
comment
Что вы имеете в виду, что он не может содержать значение datetime? datetime имеет точность до 1/300 секунды, datetime2 может иметь точность до 1/1000000 секунды. Он может содержать каждое значение datetime и более.   -  person Larnu    schedule 28.02.2021
comment
Да, это то, что я ожидал, но SQL, который я предоставил, говорит о другом.   -  person Stig    schedule 28.02.2021
comment
Нет, @Стиг.   -  person Larnu    schedule 28.02.2021
comment
Более короткий ответ - читайте документацию.   -  person SMor    schedule 28.02.2021
comment
@SMor Я прочитал это. Но если datetime использует точную базу для бесконечной десятичной дроби (1/300), как datetime2 должен представлять это? (с той же точностью)   -  person Stig    schedule 28.02.2021


Ответы (2)


Ваше неправильное понимание заключается в том, что вы думаете, что datetime имеет точность до 1/1000 секунды; это нет. .267 не .267000 в datetime, это .266666~, потому что datetime имеет точность до 1/300 секунды.

Поэтому, когда вы конвертируете datetime в datetime2 с точностью 4 или более, эта 1/300-я секунда будет представлена ​​правильно. Таким образом, 267 для datetime = .2666667 для datetime2(7).

Если вы хотите 267, используйте datetime2(3), а не datetime2(7).

Примечание: в версии 2014 (и более ранней) SQL Server неправильно преобразовывал .267 в 267000 для более новых типов данных даты и типа. Это было изменено в SQL Server 2016. См. Ключевые изменения в SQL Server 2016 (13.x).

person Larnu    schedule 28.02.2021
comment
Хорошо, спасибо, поэтому при приведении datetime к datetime2 (без указания точности) вы можете получить другое значение. На самом деле это немного странно, поскольку спецификация даты и времени MS говорит, что точность округляется до приращения 0,000, 0,003 или 0,007 секунды. Если бы это было так, он должен идеально вписаться в файл datetime2. - person Stig; 28.02.2021
comment
может дать вам другое значение Нет, это дает вам точное значение, а не другое значение. значение datetime 2021-01-01T10:00:00.267 и значение datetime2(7) 2021-01-01T10:00:00.2666667 являются одним и тем же точным значением, поскольку оба типа данных представляют 2/300 секунды с максимально возможной точностью, @Stig . - person Larnu; 28.02.2021
comment
Если дата-время имеет точность до 1/300 (бесконечная дробь), не будет ли она в этих случаях более точной по сравнению с datetime2? - person Stig; 28.02.2021
comment
1/300 != 0,003000 @Stig .... 1/300 = 0,003333333~ Так же, как 2/600 - person Larnu; 28.02.2021
comment
Я бы не согласился, это не то же самое значение. Также при загрузке в .Net DateTime они не равны. - person Stig; 28.02.2021
comment
Они ЯВЛЯЮТСЯ равными, @Stig... Это не обсуждается, это элементарная математика. Снова 1/300 = 0.0033333~, а не 0.0030000 (последнее 3/1000). - person Larnu; 28.02.2021
comment
Именно в этом моя точка зрения. datetime представляет 2,66666666666666 (и т. д.), а datetime представляет только 2,666667. Это как сравнивать Decimals и double/float - person Stig; 28.02.2021
comment
Кажется, я не могу убедить тебя, что 1/300 != 3/1000 здесь, @Stig. Я объяснил, если вам не нравится причина, потому что так работает математика и точность, то я не могу вам здесь помочь; ваше понимание просто ошибочно. Уверяю вас, если бы у меня было значение 1/3 и я бы увеличил точность с 1 десятичной точки до 7, я бы не ожидал 0.3000000, так как это неправильно. - person Larnu; 28.02.2021
comment
Давайте продолжим обсуждение в чате. - person Stig; 28.02.2021
comment
Мне больше нечего здесь обсуждать, @Stig. Я указал причину; то, как работают числа, не изменится. - person Larnu; 28.02.2021
comment
Если вы действительно все еще не убеждены, прочтите документ, на который я ссылался: При уровне совместимости базы данных 130 неявные преобразования типов данных datetime в datetime2 показывают повышенную точность за счет учета долей миллисекунд, что приводит к различным преобразованным значениям. Используйте явное приведение к типу данных datetime2 всякий раз, когда существует сценарий смешанного сравнения между типами данных datetime и datetime2. Дополнительные сведения см. в этой статье службы поддержки Microsoft. - person Larnu; 28.02.2021
comment
Вы немного поторопились со своими вердиктами, я полностью согласен, что 1/300 != 3/1000, никогда не говорил, что это не так. Но когда тип данных datetime имеет тип хранения на основе дробей, он может представлять значения, которые не может использовать datetime2. 1/3 — это не то же самое, что 0,3333333. - person Stig; 28.02.2021
comment
И спасибо за ссылку - person Stig; 28.02.2021
comment
Я должен был написать Но когда тип хранения данных типа datetime основан на бесконечной десятичной дроби, он может представлять значения, которые не может datetime2 - person Stig; 28.02.2021

DATETIMEFROMPARTS возвращает datetime с точностью до 1/300 секунды. когда вы ПРИВОДИТЕ datetime к datetime2(7), дробная часть расширяется до точности 7.

Используйте DATETIME2FROMPARTS с требуемой точностью:

SELECT convert(datetime2, DATETIME2FROMPARTS (2021,2,28,10,11,12,267,3));
SELECT convert(datetime2, DATETIME2FROMPARTS (2021,2,28,10,11,12,2670000,7));

CONVERT здесь не нужен, если только вы не хотите изменить точность результата.

person Dan Guzman    schedule 28.02.2021