Floor a data w SQL server

W SQL Server, jak "podłożyć" DATETIME do sekundy/minuty/godziny/dnia / roku?

Powiedzmy, że mam randkę z 2008-09-17 12:56:53.430, następnie wyjście podłogi powinno być:

  • rok: 2008-01-01 00:00:00.000
  • miesiąc: 2008-09-01 00:00:00.000
  • Dzień: 2008-09-17 00:00:00.000
  • godzina: 2008-09-17 12:00:00.000
  • Minuta: 2008-09-17 12:56:00.000
  • drugi: 2008-09-17 12:56:53.000
Author: Brian Webster, 2008-09-17

9 answers

Kluczem jest użycie DATEADD i DATEDIFF wraz z odpowiednim wyliczeniem czasu SQL.

declare @datetime datetime;
set @datetime = getdate();
select @datetime;
select dateadd(year,datediff(year,0,@datetime),0);
select dateadd(month,datediff(month,0,@datetime),0);
select dateadd(day,datediff(day,0,@datetime),0);
select dateadd(hour,datediff(hour,0,@datetime),0);
select dateadd(minute,datediff(minute,0,@datetime),0);
select dateadd(second,datediff(second,'2000-01-01',@datetime),'2000-01-01');
select dateadd(week,datediff(week,0,@datetime),-1); --Beginning of week is Sunday
select dateadd(week,datediff(week,0,@datetime),0); --Beginning of week is Monday

Zauważ, że gdy przebijasz się przez sekundę, często otrzymasz przepełnienie arytmetyczne, jeśli użyjesz 0. Więc wybierz znaną wartość, która jest gwarantowana, że będzie niższa niż datetime próbujesz podłogi.

 92
Author: Portman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-07 02:17:01

W Sql serverze jest taka mała sztuczka:

SELECT CAST(FLOOR(CAST(CURRENT_TIMESTAMP AS float)) AS DATETIME)

Wrzucasz DateTime do float, który reprezentuje datę jako część całkowitą, a czas jako ułamek mijanego dnia. Odetnij tę część dziesiętną, a potem Wrzuć z powrotem do DateTime, i masz północ na początku tego dnia.

Jest to prawdopodobnie bardziej wydajne niż wszystkie rzeczy DATEADD i DATEDIFF. Z pewnością łatwiej jest pisać.

 28
Author: Chris Wuestefeld,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-17 19:08:32

Rozszerzając rozwiązanie Convert/Cast, w Microsoft SQL Server 2008 możesz wykonać następujące czynności:

cast(cast(getdate() as date) as datetime)

Wystarczy zastąpić getdate() dowolną kolumną, która jest datetime.

Nie ma żadnych łańcuchów zaangażowanych w tę konwersję.

Jest to w porządku dla zapytań ad-hoc lub aktualizacji, ale w przypadku łączenia kluczy lub mocno używanego przetwarzania może być lepiej obsłużyć konwersję w przetwarzaniu lub przedefiniować tabele, aby miały odpowiednie klucze i dane.

W 2005 roku możesz użyć piętro Messiera: cast(floor(cast(getdate() as float)) as datetime)

Myślę, że to też nie używa konwersji łańcuchów, ale nie mogę mówić o porównywaniu rzeczywistej wydajności w porównaniu z szacunkami fotela.

 11
Author: Moe Cazzell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-19 08:45:23

Użyłem @ odpowiedź Portmana wiele razy na przestrzeni lat jako odniesienia, gdy podłogi daty i przeniósł swoją pracę do funkcji, która może okazać się przydatna.

Nie roszczę sobie żadnych roszczeń do jego wydajności, a jedynie dostarczam go jako narzędzie dla użytkownika.

Pytam, jeśli zdecydujesz się na upvote tej odpowiedzi, proszę również upvote @Portman odpowiedź , ponieważ mój kod jest pochodną jego.

IF OBJECT_ID('fn_FloorDate') IS NOT NULL DROP FUNCTION fn_FloorDate
SET ANSI_NULLS OFF
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[fn_FloorDate] (
  @Date DATETIME = NULL,
  @DatePart VARCHAR(6) = 'day'
)
RETURNS DATETIME
AS
BEGIN
  IF (@Date IS NULL)
    SET @Date = GETDATE();

  RETURN
  CASE
    WHEN LOWER(@DatePart) = 'year' THEN DATEADD(YEAR, DATEDIFF(YEAR, 0, @Date), 0)
    WHEN LOWER(@DatePart) = 'month' THEN DATEADD(MONTH, DATEDIFF(MONTH, 0, @Date), 0)
    WHEN LOWER(@DatePart) = 'day' THEN DATEADD(DAY, DATEDIFF(DAY, 0, @Date), 0)
    WHEN LOWER(@DatePart) = 'hour' THEN DATEADD(HOUR, DATEDIFF(HOUR, 0, @Date), 0)
    WHEN LOWER(@DatePart) = 'minute' THEN DATEADD(MINUTE, DATEDIFF(MINUTE, 0, @Date), 0)
    WHEN LOWER(@DatePart) = 'second' THEN DATEADD(SECOND, DATEDIFF(SECOND, '2000-01-01', @Date), '2000-01-01')
    ELSE DATEADD(DAY, DATEDIFF(DAY, 0, @Date), 0)
  END;
END

Użycie:

DECLARE @date DATETIME;
SET @date = '2008-09-17 12:56:53.430';

SELECT
  @date AS [Now],--2008-09-17 12:56:53.430
  dbo.fn_FloorDate(@date, 'year') AS [Year],--2008-01-01 00:00:00.000
  dbo.fn_FloorDate(default, default) AS [NoParams],--2013-11-05 00:00:00.000
  dbo.fn_FloorDate(@date, default) AS [ShouldBeDay],--2008-09-17 00:00:00.000
  dbo.fn_FloorDate(@date, 'month') AS [Month],--2008-09-01 00:00:00.000
  dbo.fn_FloorDate(@date, 'day') AS [Day],--2008-09-17 00:00:00.000
  dbo.fn_FloorDate(@date, 'hour') AS [Hour],--2008-09-17 12:00:00.000
  dbo.fn_FloorDate(@date, 'minute') AS [Minute],--2008-09-17 12:56:00.000
  dbo.fn_FloorDate(@date, 'second') AS [Second];--2008-09-17 12:56:53.000
 6
Author: Dan Atkinson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:19

Funkcja CONVERT () może to również zrobić, w zależności od używanego stylu.

 2
Author: Joel Coehoorn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-17 17:04:00

Szkoda, że to nie Oracle, bo inaczej można by użyć trunc() lub to_char ().

Ale miałem podobne problemy z SQL serverem i użyłem metod CONVERT () i DateDiff (), jak wspomniano tutaj

 1
Author: typicalrunt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-17 17:27:37

Jest kilka sposobów na skórkę tego kota =)

select convert(datetime,convert(varchar,CURRENT_TIMESTAMP,101))
 0
Author: Sean,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-02 17:57:45

DateAdd wraz z DateDiff mogą pomóc w wykonaniu wielu różnych zadań. Na przykład możesz znaleźć ostatni dzień dowolnego miesiąca, a także możesz znaleźć ostatni dzień poprzedniego lub następnego miesiąca.

----Last Day of Previous Month
SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE()),0))
LastDay_PreviousMonth
----Last Day of Current Month
SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE())+1,0))
LastDay_CurrentMonth
----Last Day of Next Month
SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE())+2,0))
LastDay_NextMonth

Źródło

 0
Author: pinaldave,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-05 20:19:22

Ponieważ PostgreSQL jest również "serwerem SQL", wspomnę

date_trunc()
Co robi dokładnie to, o co prosisz z wdziękiem.

Na przykład:

 select date_trunc('hour',current_timestamp);
       date_trunc
------------------------
 2009-02-18 07:00:00-08
(1 row)

 -2
Author: wogsland,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-05 20:21:57