2013-06-14 14 views
8

Se ho 2 date, so che posso calcolare quanti giorni, ore, minuti ecc sono tra le 2 date utilizzando datediff, ad esempio:Verificare se un intervallo di date ha un fine settimana

declare @start datetime; 
set @start = '2013-06-14'; 

declare @end datetime; 
set @end = '2013-06-15'; 

select datediff(hour, @start, @end); 

Come fare Capisco se l'intervallo di date include un fine settimana?

Il motivo per cui voglio sapere se l'intervallo di date include un fine settimana è perché voglio sottrarre il fine settimana dal conteggio del giorno o dell'ora. Ad esempio, se il giorno di inizio è venerdì e la data di fine è lunedì, dovrei ricevere solo 1 o 24 ore.

Datepart 1 = Sunday e datepart 7 = Saturday sul mio server.

+0

Ciò che definisce un "week-end?" Le vacanze ("weekend di tre giorni") contano? – zimdanen

+0

In questo caso, un fine settimana significa semplicemente sabato e/o domenica. Proverò le vacanze pubbliche in un secondo momento, ma non è importante per questa domanda. :) – oshirowanen

+0

Prima se il diff è 6 o più uno di quei giorni è un fine settimana. Se il diff è zero, è necessario controllare il giorno della settimana per sabato o domenica. Quindi assumere la domenica è il giorno della settimana 0. Se il giorno della settimana per la data di inizio è maggiore del giorno della settimana per la data di fine, ha almeno un giorno di fine settimana nell'intervallo. –

risposta

6

Ho una funzione che calcola giorni lavorativi tra le 2 date, la query di base è

declare @start datetime; 
set @start = '2013-06-14'; 

declare @end datetime; 
set @end = '2013-06-17'; 
SELECT 
    (DATEDIFF(dd, @Start, @end) +1) -- total number of days (inclusive) 
    -(DATEDIFF(wk, @Start, @end) * 2) -- number of complete weekends in period 
    -- remove partial weekend days, ie if starts on sunday or ends on saturday 
    -(CASE WHEN DATENAME(dw, @Start) = 'Sunday' THEN 1 ELSE 0 END) 
    -(CASE WHEN DATENAME(dw, @end) = 'Saturday' THEN 1 ELSE 0 END) 

così da poter capire se le date comprendere il fine settimana, se giorni diversi a lavorare per datediff in giorni

SELECT case when (DATEDIFF(dd, @Start, @end) +1) <> 
    (DATEDIFF(dd, @Start, @end) +1) -- total number of days (inclusive) 
    -(DATEDIFF(wk, @Start, @end) * 2) -- number of complete weekends in period 
    -- remove partial weekend days, ie if starts on sunday or ends on saturday 
    -(CASE WHEN DATENAME(dw, @Start) = 'Sunday' THEN 1 ELSE 0 END) 
    -(CASE WHEN DATENAME(dw, @end) = 'Saturday' THEN 1 ELSE 0 END) then 'Yes' else 'No' end as IncludesWeekends 

o semplice

SELECT (DATEDIFF(wk, @Start, @end) * 2) +(CASE WHEN DATENAME(dw, @Start) = 'Sunday' THEN 1 ELSE 0 END)  +(CASE WHEN DATENAME(dw, @end) = 'Saturday' THEN 1 ELSE 0 END) as weekendDays 
+0

Sembra che la somma degli ultimi 3 termini gli dia ciò che vuole veramente, ovvero il numero di giorni del fine settimana inclusi nell'intervallo di date. –

+2

, SELEZIONA (DATEDIFF (wk, @Start, @end) * 2) + (CASE WHEN DATENAME (dw, @Start) = 'Sunday' THEN 1 ELSE 0 END) + (CASE WHEN DATENAME (dw, @end) = 'Saturday' THEN 1 ELSE 0 END) come week end dovrebbe farlo - aggiornerò la risposta – JamieA

+0

Bello, molto semplice! –

3

avete un giorno fine settimana se una delle seguenti tre condizioni:

  1. Il giorno della settimana (come un numero intero) alla data di chiusura è inferiore al giorno della settimana di inizio data

  2. in entrambi i giorni è di per sé un giorno di fine settimana

  3. La gamma comprende almeno sei giorni

.

select 
    Coalesce(
    --rule 1 
    case when datepart(dw,@end) - datepart(dw,@start) < 0 then 'Weekend' else null end, 
    -- rule 2 
    -- depends on server rules for when the week starts 
    -- I think this code uses sql server defaults 
    case when datepart(dw,@end) in (1,7) or datepart(dw,@start) in (1,7) then 'Weekend' else null end, 
    --rule 3 
    -- six days is long enough 
    case when datediff(d, @start, @end) >= 6 then 'Weekend' Else null end, 
    -- default 
    'Weekday') 
+0

@LeeMeador La regola 3 è vera, da mercoledì a mercoledì è 8 giorni – SQLMenace

+0

datepart 1 sul mio server è domenica e il 7 è sabato. – oshirowanen

+0

Ottimizzato la regola per renderlo più chiaro. –

1

Un modo, solo che vi mostra come è possibile utilizzare una tabella di numeri per questa

declare @start datetime; 
set @start = '2013-06-14'; 

declare @end datetime; 
set @end = '2013-06-15'; -- play around by making this 2013-06-14 and other dates 


IF EXISTS (SELECT * FROM(
SELECT DATEADD(dd,number,@start) AS SomeDAte 
FROM master..spt_values 
WHERE type = 'P' 
AND DATEADD(dd,number,@start) BETWEEN @start AND @end) x 
WHERE DATEPART(dw,SomeDate) IN(1,7)) -- US assumed here 
SELECT 'Yes' 
ELSE 
SELECT 'No' 

Esempio di restituire tutti i fine settimana tra le due date

declare @start datetime; 
set @start = '2013-06-14'; 

declare @end datetime; 
set @end = '2013-06-30'; 



SELECT DATEADD(dd,number,@start) AS SomeDAte 
FROM master..spt_values 
WHERE type = 'P' 
AND DATEADD(dd,number,@start) BETWEEN @start AND @end 
AND DATEPART(dw,DATEADD(dd,number,@start)) IN(1,7) 

Risultati

2013-06-15 00:00:00.000 
2013-06-16 00:00:00.000 
2013-06-22 00:00:00.000 
2013-06-23 00:00:00.000 
2013-06-29 00:00:00.000 
2013-06-30 00:00:00.000 
0

Puoi utilizzare le seguenti funzioni. Il primo sposta un dato inizio o fine del lunedì (venerdì se indietro) se inizia nel fine settimana. Il secondo calcola i secondi tra due date senza fine settimana. Quindi devi solo verificare se il totale dei giorni è uguale ai giorni senza weksends (demo sotto).

CREATE FUNCTION [dbo].[__CorrectDate](
    @date DATETIME, 
    @forward INT 
) 

RETURNS DATETIME AS BEGIN 
    IF (DATEPART(dw, @date) > 5) BEGIN 

     IF (@forward = 1) BEGIN 
      SET @date = @date + (8 - DATEPART(dw, @date)) 
      SET @date = DateAdd(Hour, (8 - DatePart(Hour, @date)), @date) 
     END ELSE BEGIN 
      SET @date = @date - (DATEPART(dw, @date)- 5) 
      SET @date = DateAdd(Hour, (18 - DatePart(Hour, @date)), @date) 
     END 
     SET @date = DateAdd(Minute, -DatePart(Minute, @date), @date) 
     SET @date = DateAdd(Second, -DatePart(Second, @date), @date) 
    END 

    RETURN @date 
END 

GO 

CREATE FUNCTION [dbo].[__DateDiff_NoWeekends](
    @date1 DATETIME, 
    @date2 DATETIME 
) 

RETURNS INT AS BEGIN 
    DECLARE @retValue INT 

    SET @date1 = dbo.__CorrectDate(@date1, 1) 
    SET @date2 = dbo.__CorrectDate(@date2, 0) 

    IF (@date1 >= @date2) 
     SET @retValue = 0 
    ELSE BEGIN 
     DECLARE @days INT, @weekday INT 
     SET @days = DATEDIFF(d, @date1, @date2) 
     SET @weekday = DATEPART(dw, @date1) - 1 

     SET @retValue = DATEDIFF(s, @date1, @date2) - 2 * 24 * 3600 * ((@days + @weekday)/7) 
    END 

    RETURN @retValue 
END 

quindi è possibile ottenere le informazioni in questo modo:

declare @start datetime 
set @start = '20130614' 

declare @end datetime 
set @end = '20130615' 

declare @daysTotal int 
declare @daysWoWeekends int 

SET @daysTotal = DATEDIFF(dd, @start, @end) 
SET @daysWoWeekends = dbo.__DateDiff_NoWeekends(@start, @end)/(24 * 3600) 

SELECT CASE WHEN @daysTotal = @daysWoWeekends 
     THEN 'No weekend between' 
     ELSE 'There are weeksends' END, 
     @daysTotal, 
     @daysWoWeekends,@start,@end 

Ecco un demo: http://sqlfiddle.com/#!6/7cda7/11

There are weeksends 1 0 June, 14 2013 00:00:00+0000 June, 15 2013 00:00:00+0000 
0

Ecco la semplice e generalizzare query. puoi ottenere risultati tramite query ricorsive. Controlla la seguente domanda

with mycte as 
(
    select cast('2013-06-14' as datetime) DateValue 
    union all 
    select DateValue + 1 from mycte where DateValue + 1 < '2013-06-17' 
) 

select count(*) as days , count(*)*24 as hours 
from mycte 
WHERE DATENAME(weekday ,DateValue) != 'SATURDAY' AND 
DATENAME(weekday ,DateValue) != 'SUNDAY' 
OPTION (MAXRECURSION 0) 

sicuramente funzionerà per voi.

+0

Questo è stato d'aiuto? –

0

È possibile utilizzare una CTE ricorsiva per ottenere le date tra la gamma

 WITH CTE_DatesTable 
      AS (SELECT @MinDate AS [EffectiveDate] 
       UNION ALL 
       SELECT DATEADD(dd, 1, [EffectiveDate]) 
       FROM  CTE_DatesTable 
       WHERE DATEADD(dd, 1, [EffectiveDate]) <= @MaxDate) 

      SELECT [EffectiveDate] 
      FROM CTE_DatesTable 
    OPTION (MAXRECURSION 0); 

e poi filtrare i fine settimana utilizzando ..

((DATEPART(dw, DT.EffectiveDate) + @@DATEFIRST) % 7) NOT IN (0, 1) 
Problemi correlati