Как работает функция преобразования SQL при преобразовании datetime в float?

почему этот вопрос:

declare @currentDate as datetime
    set @currentDate ='01/07/2010'

select convert(float, @currentdate) 

... - 40183?

Итак, для тех, кто запутывается в моем вопросе, мой вопрос: как узнать результат вышеуказанного запроса, не выполнив его?

Ответ 1

DateTime часто представляется в виде дневного счета с заданной даты (обычно известной как эпоха) на целой части и процентного дня, прошедшего с середины ночи на дробной части.

SQL Server не является исключением из этого, поэтому преобразование в Float имеет большой смысл. День 0 - 01 января 1900 00:00:00 (AFAIK, в определенном часовом поясе, поэтому вы должны считать это "местным временем" ).

Итак, вы можете попробовать следующее:

declare @ADate DateTime;
set @ADate = '19000101 00:00:00';
select CONVERT(float, @ADate);  --should print 0
set @ADate = '19000101 12:00:00';
select CONVERT(float, @ADate);  --should print 0.5
set @ADate = '19001231 06:00:00';
select CONVERT(float, @ADate);  --should print 364.25

Итак, для ваших результатов прошло 40183 дня с 01.01.190000 00:00:00 и 01/07/2010 00:00:00

Уточнение: системы, подобные Unix, используют другой подход для хранения данных: секунды с момента Unix (1 января 1970 года 00:00:00 UTC), который более известен как время эпохи.

[Изменить] Формат даты этого ответа был изменен на формат YYYYMMDD на 20140416, после нескольких лет опыта работы с SQL Server (и, как сказал @Damien в своем комментарии) это единственный безопасный формат.

Ответ 2

Значения DateTime фактически хранятся в виде двух четырехбайтовых целых чисел под капотом. Первое четырехбайтовое целое число представляет количество дней с 1900-01-01. Второе четырехбайтовое целое число хранится в миллисекундах с полуночи. Когда вы конвертируете datetime в float, десятичная часть представляет процент от прошедшего 24-дневного периода. Таким образом, 0,5 представляет собой полдень.

Ответ 3

В основном это преобразование datetime в дату OLE. В документации для System.DateTime.ToOADate() есть достойное описание процесса:

http://msdn.microsoft.com/en-us/library/system.datetime.tooadate.aspx

Быстрое объяснение состоит в том, что целая часть - это количество дней с 12/30/1899. Дробная часть (нуль в этом случае) - это время, деленное на 24.

Ответ 4

Это поможет вам понять реализацию TSQL (или реализовать свои собственные):

DECLARE
    @date DATETIME = '20180125 09:15:30.549',
    @date_dec DECIMAL (26,10) = 43123.3857702546

SELECT
    CAST(@date_dec AS DATETIME) AS [TSQL cast to DATETIME],
    CAST(@date AS DECIMAL (26,10)) AS [TSQL cast to DECIMAL]

SELECT
    DATEADD(DAY, FLOOR(@date_dec), 
        DATEADD(HOUR, FLOOR(@date_dec % 1 * 24), 
            DATEADD(MINUTE, FLOOR((@date_dec % 1 * 24) % 1 * 60), 
                DATEADD(SECOND, FLOOR(((@date_dec % 1 * 24) % 1 * 60) % 1 * 60), 
                    DATEADD(MILLISECOND, FLOOR((((@date_dec % 1 * 24) % 1 * 60) % 1 * 60) % 1 * 1000), '19000101')
                )
            )
        )
    ) AS [Manual cast to DATETIME],
    DATEDIFF(DAY, '19000101', @date) 
    + (
        DATEPART(HOUR, @date) 
        + (
            DATEPART(MINUTE, @date) 
            + (
                DATEPART(SECOND, @date)
                + DATEPART(MILLISECOND, @date) / CAST(1000 AS FLOAT)
              ) / CAST(60 AS FLOAT)
          ) / CAST(60 AS FLOAT)
      ) / CAST(24 AS DECIMAL (26,10)) AS [Manual cast to DECIMAL]

Обратите внимание, что результат не всегда совпадает с тем, что TSQL теряет точность на последней миллисекундовой цифре.