Czy da się wyświetlić liczbę godzin > 24 w DateTime

0

Witajcie,

Natknąłem się w jednym z projektów na taki kod:

select case when SIGN(DateDiff(mi, DateAdd(hour, -33, GETUTCDATE()), t.TaskTimeFrom )) = -1 then '-' else '' end +
                 case when SIGN(DateDiff(mi, DateAdd(hour, -33, GETUTCDATE()), t.TaskTimeFrom )) * 
                           DateDiff(mi, DateAdd(hour, -33, GETUTCDATE()), t.TaskTimeFrom ) / 60 < 10 then '0' else '' end +
                 convert(varchar(4), SIGN(DateDiff(mi, DateAdd(hour, -33, GETUTCDATE()), t.TaskTimeFrom )) * 
                      DateDiff(mi, DateAdd(hour, -33, GETUTCDATE()), t.TaskTimeFrom ) / 60) + ':' +
                 case when (SIGN(DateDiff(mi, DateAdd(hour, -33, GETUTCDATE()), t.TaskTimeFrom )) *
                              DateDiff(mi, DateAdd(hour, -33, GETUTCDATE()), t.TaskTimeFrom )) - ((SIGN(DateDiff(mi, DateAdd(hour, -33, GETUTCDATE()), t.TaskTimeFrom )) * 
                              DateDiff(mi, DateAdd(hour, -33, GETUTCDATE()), t.TaskTimeFrom ) / 60) * 60) < 10 then '0' else '' end + 
                 convert(varchar(2), (SIGN(DateDiff(mi, DateAdd(hour, -33, GETUTCDATE()), t.TaskTimeFrom )) *
                                        DateDiff(mi, DateAdd(hour, -33, GETUTCDATE()), t.TaskTimeFrom )) - ((SIGN(DateDiff(mi, DateAdd(hour, -33, GETUTCDATE()), t.TaskTimeFrom )) * 
                                        DateDiff(mi, DateAdd(hour, -33, GETUTCDATE()), t.TaskTimeFrom ) / 60) * 60) )
from v_tmp t
where ... 

Pole t.TaskTimeFrom jest zwykłym DateTime, a efekt wyjściowy ma być taki, że ta data ma się zawsze wyświetlać w postaci HH:MM tyle, że jak widać w na powyższym przypadku może być -33:00 lub 29:55 itd. Zawsze musi to być Znak+DwucyfrowaLiczbaZZeremZPrzoduJesliJest<10:DwucyfrowaLiczbaZZeremZPrzoduJesliJest<10
Pytanko do was czy macie pomysł jak to "uprościć"?

1

Ja trzymam czas trwania czegoś tam w sekundach z dokładnością do 4 miejsc po przecinku, w bazie danych jak Numeric(19,4).
Natomiast formatowaniem tego czasu zajmuje się aplikacja, a nie baza danych.
Dzięki temu mogę wyświetlić ten czas np tak: 26:04:01 lub tak 1 dzień 2 godz 4 min i 1 s

Jeśli nie możesz tego zmienić, to zamieniłbym wartość czasu jak ilość sekund (lub msec, jak komu potrzebne), która to wartość przekazałbym do UDFa i który to UDF zwróci reprezentację czasu trwania jako tekstu odpowiednio sformatowany. Kod takiego UDFa jest dość prosty, mniej więcej taki:

    ms := ADuration * MSecsPerSec;

    d  := ms div (SecsPerDay * MSecsPerSec);
    ms := ms mod (SecsPerDay * MSecsPerSec);

    h  := ms div (SecsPerHour * MSecsPerSec);
    ms := ms mod (SecsPerHour * MSecsPerSec);

    m  := ms div (SecsPerMin * MSecsPerSec);

    if m > 0 then
      ms := ms mod (SecsPerMin * MSecsPerSec);

    s  := ms div MSecsPerSec;
    ms := ms mod MSecsPerSec;

A potem wartości zamieniane są na reprezentację tekstową i sklejane do wynikowego stringa.

Wtedy cały ten SQL wyglądałby tak:

SELECT dbo.ufSecToText(DateDiff(ms, DateAdd(HOUR, -33, GETUTCDATE()), t.TaskTimeFrom))
FROM v_tmp t
0

W pierwszej wersji było to zrobione funkcją jednak zostało to wywalone ze względu na wydajność. Przy 80 tysiącach rekordów select z funkcją wynosił prawie 16 sekund natomiast z takim selectem jak to jest w pierwszym poście trwało to poniżej 1 sekundy. Przeanalizowałem jeszcze zapytanie i pozbyłem się tego '-' gdyż z obecnej funkcjonalności nigdy czas ujemny nie będzie. Resztę zmieniłem w ten sposób:

select convert(varchar(5), format(DateDiff(hh, DateAdd(hour, -33, GETUTCDATE()), t.TaskTimeFrom),'00') +  
                           format(DateDiff(mi, DateAdd(hour, -33, GETUTCDATE()), t.TaskTimeFrom) - 
                                  DateDiff(hh, DateAdd(hour, -33, GETUTCDATE()), t.TaskTimeFrom)*60,':00'))
from v_tmp t
where ...

Pytanie czy jeszcze w jakiś sposób da się to uprościć?

1 użytkowników online, w tym zalogowanych: 0, gości: 1