2010-11-10 2 views
10

почему из положить этот запрос:Как работает функция преобразования SQL при преобразовании datetime в float?

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

select convert(float, @currentdate) 

... это 40183?

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

+0

что еще вы ожидали ??? –

+0

Что именно вам нужно сделать? – hgulyan

+0

Я ожидал ошибку, я хочу знать, как она конвертирует datetime в float, внутренне, как это работает. –

ответ

10

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 = '190:00:00'; 
select CONVERT(float, @ADate); --should print 364.25 

Итак, для результатов, 40183 дней был принят, так как 01.01.1900 00:00:00 и 01/07/2010 00:00: 00

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

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

+0

о вашем формате даты - безопасный способ указать дату и время - это использовать ГГГГ-ММ-ДД и использовать «Т» вместо пространства, чтобы отделить компоненты даты и времени (только FYI) –

+0

@ Damien_The_Unbeliever, я использовал формат даты YYYY-MM-DD для всех основных движков базы данных ...но (верьте или нет) MS-SQL Express 2008 в Windows 7 Business 32bit Spanish, хочет его в формате ГГГГ-ДД-ММ! (просто FYI действительно): D – jachguate

+0

, если это всего лишь дата, тогда YYYYMMDD - единственный безопасный, однозначный формат (без тире). Конечно, если вы используете datetime2 или другие более новые типы, то все правила снова меняются :-) –

4

Значения 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

+0

Фактически в TSQL с 01.01.1900, все остальное - то же самое. – Vedran

0

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

Смежные вопросы