Как узнать сколько часов было 4 часа между двумя датами в TSQL - PullRequest
1 голос
/ 18 октября 2019

Мне нужно узнать, сколько определенного часа произошло между двумя датами в TSQL. Некоторые примеры:

Следующий результат даст результат = 1

declare @date1 datetime = '2019-10-01 00:00:00.000';
declare @date2 datetime = '2019-10-02 00:00:00.000';

Следующий результат даст результат = 0, поскольку в промежутке между

declare @date1 datetime = '2019-10-01 05:00:00.000';
declare @date2 datetime = '2019-10-02 00:00:00.000';
* было 0 4AM. 1008 * Следующее дало бы результат = 2, так как в промежутке между
declare @date1 datetime = '2019-10-01 03:00:00.000';
declare @date2 datetime = '2019-10-02 05:00:00.000';

было бы 2 4AM, следующее дало бы результат = 2, поскольку было 2 4AM, даже если они находятся только на4:00 AM время

declare @date1 datetime = '2019-10-01 04:00:00.000';
declare @date2 datetime = '2019-10-02 04:00:00.000';

Я пробовал что-то подобное ... но он дает неправильный ответ

DECLARE @startdate AS DATETIME = '2019-10-01 03:00:00.000'
DECLARE @enddate   AS DATETIME = '2019-10-02 00:00:00.000'
DECLARE @hour int = 4

SELECT DATEDIFF(HOUR, @startdate, @endDate) / 24
     + 1 
     + CASE WHEN DATEPART(HOUR, @startdate) <= @hour AND 
                 DATEPART(HOUR, @endDate) >= @hour
            THEN 0
            ELSE -1
       END

Любой, кто может пролить свет, был бы признателен

Ответы [ 4 ]

5 голосов
/ 18 октября 2019

Самый простой способ - удалить 4 часа из обоих значений, а затем получить разницу в днях:

DECLARE @date1 datetime = '2019-10-01 00:00:00.000';
DECLARE @date2 datetime = '2019-10-02 00:00:00.000';

SELECT DATEDIFF(DAY,DATEADD(HOUR, -4, @date1),DATEADD(HOUR, -4, @date2)); --RETURNS 31, as there are 31 days bewteen 10 Jan and 10 Feb
GO

DECLARE @date1 datetime = '2019-10-01T04:30:00.000';
DECLARE @date2 datetime = '2019-10-02T03:59:00.000';

SELECT DATEDIFF(DAY,DATEADD(HOUR, -4, @date1),DATEADD(HOUR, -4, @date2)); --RETURNS 0, as 04:00 never got to

GO

DECLARE @date1 datetime = '2019-10-01T03:30:00.000';
DECLARE @date2 datetime = '2019-10-03T04:30:00.000';

SELECT DATEDIFF(DAY,DATEADD(HOUR, -4, @date1),DATEADD(HOUR, -4, @date2)); --RETURNS 3, as 04:00 occurs on 01, 02 and 03 of October

Похоже, что ОП также хочет подсчитать событие 04:00. Поэтому я удаляю еще одну секунду от времени начала:

DECLARE @date1 datetime = '2019-10-01T04:00:00.000';
DECLARE @date2 datetime = '2019-10-02T04:00:00.000';

SELECT DATEDIFF(DAY,DATEADD(SECOND,-1,DATEADD(HOUR, -4, @date1)),DATEADD(HOUR, -4, @date2)); --returns 2

DECLARE @date1 datetime = '2019-10-01T04:00:00.000';
DECLARE @date2 datetime = '2019-10-01T04:00:01.000';

SELECT DATEDIFF(DAY,DATEADD(SECOND,-1,DATEADD(HOUR, -4, @date1)),DATEADD(HOUR, -4, @date2)); --Returns 1

Если вы на самом деле храните значения с точностью до 1/300 секунды, то не используйте 1 секунду, используйте 3 миллисекунды, чтобыпредельная точность.

1 голос
/ 19 октября 2019

Если две даты находятся на расстоянии n часов, то между ними FLOOR(n / 24) 4 утра;плюс еще один, если 4:00 лежит между часом начала и датой окончания (проверить, что 04:00 между 03:00 - 05:00, легко, проверить, что 04:00 между 05:00 - 03:00 - сложно):

SELECT date1
     , date2
     , DATEDIFF(HOUR, date1, date2) / 24 + CASE
           WHEN H1 <= H2 AND (H1 <= 4 AND 4 <= H2) OR H1 >  H2 AND (H1 <= 4 OR  4 <= H2) THEN 1
           ELSE 0
       END AS result
FROM tests
CROSS APPLY (SELECT DATEPART(HOUR, date1), DATEPART(HOUR, date2)) AS x(h1, h2)

Демонстрация на дб <> fiddle

0 голосов
/ 18 октября 2019

Это звучит как попытка подсчитать дни в одном часовом поясе, когда значения хранятся в другом, вероятно, UTC.

Один из вариантов - использовать TODATETIMEOFFSET для преобразования даты UTC в целевой часовой пояс:

SELECT datediff(d,todatetimeoffset(@date1,'+04:00'), todatetimeoffset(@date2,'+04:00'))

Это делает расчет часового пояса явным. Он не будет обрабатывать изменения дневного света, так как смещение должно быть указано явно. В случае изменения правил перехода на летнее время само приложение должно быть изменено для изменения смещений.

В SQL Server 2016 и более поздних версиях AT TIME ZONE позволяет напрямую указать имя часового пояса и применять любыеправила часового пояса, указанные для этого часового пояса.

select 
    datediff(d, @date1 at time zone 'Caucasus Standard Time',
                @date2 at time zone 'Caucasus Standard Time')

Правила часовых поясов распространяются через Обновления Windows, что означает, что изменения правил больше не требуют изменений в приложении или базе данных.

0 голосов
/ 18 октября 2019
DECLARE @date1 datetime = '2019-10-01 04:00:00.000';
DECLARE @date2 datetime = '2019-10-02 04:00:00.000';

DECLARE @Hr INT=4
DECLARE @AMorPM CHAR(2)='PM'

;WITH CTE AS
(
    SELECT @date1 AS DateStart
    UNION ALL
    SELECT DATEADD(HOUR,1,DateStart)
    FROM CTE 
    WHERE DateStart < @date2
)
SELECT COUNT(CASE WHEN DateStart > 12 THEN DateStart-12 ELSE DateStart END) AS TotalTimes
FROM CTE
WHERE (
        (@AMorPM='AM' AND DATEPART(HOUR,DateStart)=@Hr) OR 
        (@AMorPM='PM' AND DATEPART(HOUR,DateStart)-12=@Hr)
      )
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...