it-swarm.com.de

Zählen Sie Arbeitstage zwischen zwei Terminen

Wie kann ich die Anzahl der Arbeitstage zwischen zwei Daten in SQL Server berechnen? 

Montag bis Freitag und es muss T-SQL sein.

137
Ovidiu Pacurar

An Werktagen von Montag bis Freitag können Sie dies mit einem einzigen SELECT tun, wie hier:

DECLARE @StartDate DATETIME
DECLARE @EndDate DATETIME
SET @StartDate = '2008/10/01'
SET @EndDate = '2008/10/31'


SELECT
   (DATEDIFF(dd, @StartDate, @EndDate) + 1)
  -(DATEDIFF(wk, @StartDate, @EndDate) * 2)
  -(CASE WHEN DATENAME(dw, @StartDate) = 'Sunday' THEN 1 ELSE 0 END)
  -(CASE WHEN DATENAME(dw, @EndDate) = 'Saturday' THEN 1 ELSE 0 END)

Wenn Sie Ferien einbeziehen möchten, müssen Sie es ein bisschen ausarbeiten ...

261
CMS

In Berechnen von Arbeitstagen finden Sie einen guten Artikel zu diesem Thema, aber wie Sie sehen, ist es nicht so fortgeschritten.

--Changing current database to the Master database allows function to be shared by everyone.
USE MASTER
GO
--If the function already exists, drop it.
IF EXISTS
(
    SELECT *
    FROM dbo.SYSOBJECTS
    WHERE ID = OBJECT_ID(N'[dbo].[fn_WorkDays]')
    AND XType IN (N'FN', N'IF', N'TF')
)
DROP FUNCTION [dbo].[fn_WorkDays]
GO
 CREATE FUNCTION dbo.fn_WorkDays
--Presets
--Define the input parameters (OK if reversed by mistake).
(
    @StartDate DATETIME,
    @EndDate   DATETIME = NULL [email protected] replaced by @StartDate when DEFAULTed
)

--Define the output data type.
RETURNS INT

AS
--Calculate the RETURN of the function.
BEGIN
    --Declare local variables
    --Temporarily holds @EndDate during date reversal.
    DECLARE @Swap DATETIME

    --If the Start Date is null, return a NULL and exit.
    IF @StartDate IS NULL
        RETURN NULL

    --If the End Date is null, populate with Start Date value so will have two dates (required by DATEDIFF below).
     IF @EndDate IS NULL
        SELECT @EndDate = @StartDate

    --Strip the time element from both dates (just to be safe) by converting to whole days and back to a date.
    --Usually faster than CONVERT.
    --0 is a date (01/01/1900 00:00:00.000)
     SELECT @StartDate = DATEADD(dd,DATEDIFF(dd,0,@StartDate), 0),
            @EndDate   = DATEADD(dd,DATEDIFF(dd,0,@EndDate)  , 0)

    --If the inputs are in the wrong order, reverse them.
     IF @StartDate > @EndDate
        SELECT @Swap      = @EndDate,
               @EndDate   = @StartDate,
               @StartDate = @Swap

    --Calculate and return the number of workdays using the input parameters.
    --This is the meat of the function.
    --This is really just one formula with a couple of parts that are listed on separate lines for documentation purposes.
     RETURN (
        SELECT
        --Start with total number of days including weekends
        (DATEDIFF(dd,@StartDate, @EndDate)+1)
        --Subtact 2 days for each full weekend
        -(DATEDIFF(wk,@StartDate, @EndDate)*2)
        --If StartDate is a Sunday, Subtract 1
        -(CASE WHEN DATENAME(dw, @StartDate) = 'Sunday'
            THEN 1
            ELSE 0
        END)
        --If EndDate is a Saturday, Subtract 1
        -(CASE WHEN DATENAME(dw, @EndDate) = 'Saturday'
            THEN 1
            ELSE 0
        END)
        )
    END
GO

Wenn Sie einen benutzerdefinierten Kalender verwenden müssen, müssen Sie möglicherweise einige Überprüfungen und Parameter hinzufügen. Hoffentlich bietet es einen guten Ausgangspunkt.

28
Bogdan Maxim

Alles Gute an Bogdan Maxim & Peter Mortensen. Dies ist ihr Beitrag, ich habe gerade die Funktion um Feiertage erweitert. 

--Changing current database to the Master database allows function to be shared by everyone.
USE MASTER
GO
--If the function already exists, drop it.
IF EXISTS
(
    SELECT *
    FROM dbo.SYSOBJECTS
    WHERE ID = OBJECT_ID(N'[dbo].[fn_WorkDays]')
    AND XType IN (N'FN', N'IF', N'TF')
)

DROP FUNCTION [dbo].[fn_WorkDays]
GO
 CREATE FUNCTION dbo.fn_WorkDays
--Presets
--Define the input parameters (OK if reversed by mistake).
(
    @StartDate DATETIME,
    @EndDate   DATETIME = NULL [email protected] replaced by @StartDate when DEFAULTed
)

--Define the output data type.
RETURNS INT

AS
--Calculate the RETURN of the function.
BEGIN
    --Declare local variables
    --Temporarily holds @EndDate during date reversal.
    DECLARE @Swap DATETIME

    --If the Start Date is null, return a NULL and exit.
    IF @StartDate IS NULL
        RETURN NULL

    --If the End Date is null, populate with Start Date value so will have two dates (required by DATEDIFF below).
    IF @EndDate IS NULL
        SELECT @EndDate = @StartDate

    --Strip the time element from both dates (just to be safe) by converting to whole days and back to a date.
    --Usually faster than CONVERT.
    --0 is a date (01/01/1900 00:00:00.000)
    SELECT @StartDate = DATEADD(dd,DATEDIFF(dd,0,@StartDate), 0),
            @EndDate   = DATEADD(dd,DATEDIFF(dd,0,@EndDate)  , 0)

    --If the inputs are in the wrong order, reverse them.
    IF @StartDate > @EndDate
        SELECT @Swap      = @EndDate,
               @EndDate   = @StartDate,
               @StartDate = @Swap

    --Calculate and return the number of workdays using the input parameters.
    --This is the meat of the function.
    --This is really just one formula with a couple of parts that are listed on separate lines for documentation purposes.
    RETURN (
        SELECT
        --Start with total number of days including weekends
        (DATEDIFF(dd,@StartDate, @EndDate)+1)
        --Subtact 2 days for each full weekend
        -(DATEDIFF(wk,@StartDate, @EndDate)*2)
        --If StartDate is a Sunday, Subtract 1
        -(CASE WHEN DATENAME(dw, @StartDate) = 'Sunday'
            THEN 1
            ELSE 0
        END)
        --If EndDate is a Saturday, Subtract 1
        -(CASE WHEN DATENAME(dw, @EndDate) = 'Saturday'
            THEN 1
            ELSE 0
        END)
        --Subtract all holidays
        -(Select Count(*) from [DB04\DB04].[Gateway].[dbo].[tblHolidays]
          where  [HolDate] between @StartDate and @EndDate )
        )
    END  
GO
-- Test Script
/*
declare @EndDate datetime= dateadd(m,2,getdate())
print @EndDate
select  [Master].[dbo].[fn_WorkDays] (getdate(), @EndDate)
*/
15
Dan B

Ein anderer Ansatz zur Berechnung von Arbeitstagen besteht darin, eine WHILE-Schleife zu verwenden, die im Wesentlichen einen Datumsbereich durchläuft und den Wert um 1 erhöht, wenn Tage gefunden werden, die sich innerhalb von Montag bis Freitag befinden. Das vollständige Skript zur Berechnung von Arbeitstagen mit der WHILE-Schleife wird unten gezeigt:

CREATE FUNCTION [dbo].[fn_GetTotalWorkingDaysUsingLoop]
(@DateFrom DATE,
@DateTo   DATE
)
RETURNS INT
AS
     BEGIN
         DECLARE @TotWorkingDays INT= 0;
         WHILE @DateFrom <= @DateTo
             BEGIN
                 IF DATENAME(WEEKDAY, @DateFrom) IN('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday')
                     BEGIN
                         SET @TotWorkingDays = @TotWorkingDays + 1;
                 END;
                 SET @DateFrom = DATEADD(DAY, 1, @DateFrom);
             END;
         RETURN @TotWorkingDays;
     END;
GO

Obwohl die WHILE-Schleifenoption sauberer ist und weniger Codezeilen verwendet, kann sie in Ihrer Umgebung zu einem Leistungsengpass werden, insbesondere wenn Ihr Datumsbereich mehrere Jahre umfasst.

Weitere Methoden zum Berechnen von Arbeitstagen und -stunden finden Sie in diesem Artikel: https://www.sqlshack.com/how-to-calculate-work-days-and-hours-in-sql- Server/

6
AliceF

Meine Version der akzeptierten Antwort als Funktion verwendet DATEPART, sodass ich keinen Stringvergleich in der Zeile mit durchführen muss 

DATENAME(dw, @StartDate) = 'Sunday'

Wie auch immer, hier ist meine Geschäftsdatenfunktion

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE FUNCTION BDATEDIFF
(
    @startdate as DATETIME,
    @enddate as DATETIME
)
RETURNS INT
AS
BEGIN
    DECLARE @res int

SET @res = (DATEDIFF(dd, @startdate, @enddate) + 1)
    -(DATEDIFF(wk, @startdate, @enddate) * 2)
    -(CASE WHEN DATEPART(dw, @startdate) = 1 THEN 1 ELSE 0 END)
    -(CASE WHEN DATEPART(dw, @enddate) = 7 THEN 1 ELSE 0 END)

    RETURN @res
END
GO
6
Carter Cole

Für den Unterschied zwischen den Daten einschließlich der Feiertage bin ich folgendermaßen gegangen:

1) Tabelle mit Feiertagen:

    CREATE TABLE [dbo].[Holiday](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](50) NULL,
[Date] [datetime] NOT NULL)

2) Ich hatte meine Planungstabelle wie diese und wollte die Spalte Work_Days füllen, die leer war:

    CREATE TABLE [dbo].[Plan_Phase](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Id_Plan] [int] NOT NULL,
[Id_Phase] [int] NOT NULL,
[Start_Date] [datetime] NULL,
[End_Date] [datetime] NULL,
[Work_Days] [int] NULL)

3) Um also "Work_Days" später in meine Kolumne eintragen zu können, musste:

SELECT Start_Date, End_Date,
 (DATEDIFF(dd, Start_Date, End_Date) + 1)
-(DATEDIFF(wk, Start_Date, End_Date) * 2)
-(SELECT COUNT(*) From Holiday Where Date  >= Start_Date AND Date <= End_Date)
-(CASE WHEN DATENAME(dw, Start_Date) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, End_Date) = 'Saturday' THEN 1 ELSE 0 END)
-(CASE WHEN (SELECT COUNT(*) From Holiday Where Start_Date  = Date) > 0 THEN 1 ELSE 0 END)
-(CASE WHEN (SELECT COUNT(*) From Holiday Where End_Date  = Date) > 0 THEN 1 ELSE 0 END) AS Work_Days
from Plan_Phase

Hoffe, dass ich helfen konnte.

Prost

5
joaopintocruz

(Ich bin ein paar Punkte, um Privilegien zu kommentieren)

Wenn Sie sich entschließen, auf den +1 Tag in elegante Lösung von CMS zu verzichten, beachten Sie, dass, wenn Ihr Start- und Enddatum am selben Wochenende liegen, Sie eine negative Antwort erhalten. Das heißt, 26.10.2008 bis 26.10.2008 ergibt -1.

meine eher einfache Lösung:

select @Result = (..CMS's answer..)
if  (@Result < 0)
        select @Result = 0
    RETURN @Result

.. was auch alle fehlerhaften Beiträge mit Startdatum nach Enddatum auf Null setzt. Etwas, nach dem Sie suchen können oder nicht.

5
phareim

Hier ist eine Version, die gut funktioniert (denke ich). Die Tabelle "Holiday_date" enthält Holiday_date-Spalten, die von Ihrem Unternehmen festgelegte Feiertage enthalten.

DECLARE @RAWDAYS INT

   SELECT @RAWDAYS =  DATEDIFF(day, @StartDate, @EndDate )--+1
                    -( 2 * DATEDIFF( week, @StartDate, @EndDate ) )
                    + CASE WHEN DATENAME(dw, @StartDate) = 'Saturday' THEN 1 ELSE 0 END
                    - CASE WHEN DATENAME(dw, @EndDate) = 'Saturday' THEN 1 ELSE 0 END 

   SELECT  @RAWDAYS - COUNT(*) 
     FROM HOLIDAY NumberOfBusinessDays
    WHERE [Holiday_Date] BETWEEN @StartDate+1 AND @EndDate 
4
user2733766
 DECLARE @TotalDays INT,@WorkDays INT
 DECLARE @ReducedDayswithEndDate INT
 DECLARE @WeekPart INT
 DECLARE @DatePart INT

 SET @TotalDays= DATEDIFF(day, @StartDate, @EndDate) +1
 SELECT @ReducedDayswithEndDate = CASE DATENAME(weekday, @EndDate)
  WHEN 'Saturday' THEN 1
  WHEN 'Sunday' THEN 2
  ELSE 0 END 
 SET @[email protected]@ReducedDayswithEndDate
 SET @[email protected]/7;
 SET @[email protected]%7;
 SET @WorkDays=(@WeekPart*5)[email protected]

 RETURN @WorkDays
4
Muthuvel

Verwenden einer Datumstabelle:

    DECLARE 
        @StartDate date = '2014-01-01',
        @EndDate date = '2014-01-31'; 
    SELECT 
        COUNT(*) As NumberOfWeekDays
    FROM dbo.Calendar
    WHERE CalendarDate BETWEEN @StartDate AND @EndDate
      AND IsWorkDay = 1;

Wenn Sie das nicht haben, können Sie eine Zahlentabelle verwenden:

    DECLARE 
    @StartDate datetime = '2014-01-01',
    @EndDate datetime = '2014-01-31'; 
    SELECT 
    SUM(CASE WHEN DATEPART(dw, DATEADD(dd, Number-1, @StartDate)) BETWEEN 2 AND 6 THEN 1 ELSE 0 END) As NumberOfWeekDays
    FROM dbo.Numbers
    WHERE Number <= DATEDIFF(dd, @StartDate, @EndDate) + 1 -- Number table starts at 1, we want a 0 base

Sie sollten beide schnell sein und die Mehrdeutigkeit/Komplexität aufheben. Die erste Option ist die beste, aber wenn Sie keine Kalendertabelle haben, können Sie immer eine Zahlentabelle mit einem CTE erstellen.

2
Brian

Dies ist im Wesentlichen die Antwort von CMS, ohne sich auf eine bestimmte Spracheinstellung zu verlassen. Und da wir generisch arbeiten, sollte dies auch für alle @@datefirst-Einstellungen gelten.

datediff(day, <start>, <end>) + 1 - datediff(week, <start>, <end>) * 2
    /* if start is a Sunday, adjust by -1 */
  + case when datepart(weekday, <start>) = 8 - @@datefirst then -1 else 0 end
    /* if end is a Saturday, adjust by -1 */
  + case when datepart(weekday, <end>) = (13 - @@datefirst) % 7 + 1 then -1 else 0 end

datediff(week, ...) verwendet immer wochenlang eine Samstag-Sonntag-Grenze, sodass der Ausdruck deterministisch ist und nicht geändert werden muss (sofern unsere Definition von Wochentagen konsistent von Montag bis Freitag ist.) Die Tag-Nummerierung hängt von der Einstellung von @@datefirst ab und die modifizierten Berechnungen handhaben diese Korrektur mit der kleinen Komplikation einiger modularer Arithmetik.

Eine sauberere Methode, um mit der Sache Samstag/Sonntag umzugehen, besteht darin, die Daten vor dem Extrahieren eines Wochentagswerts zu übersetzen. Nach der Verschiebung stimmen die Werte wieder mit einer festen (und wahrscheinlich vertrauten) Nummerierung überein, die am Sonntag mit 1 beginnt und am Samstag mit 7 endet.

datediff(day, <start>, <end>) + 1 - datediff(week, <start>, <end>) * 2
  + case when datepart(weekday, dateadd(day, @@datefirst, <start>)) = 1 then -1 else 0 end
  + case when datepart(weekday, dateadd(day, @@datefirst, <end>))   = 7 then -1 else 0 end

Ich habe diese Form der Lösung mindestens bis 2002 und einen Artikel von Itzik Ben-Gan verfolgt. ( https://technet.Microsoft.com/de-de/library/aa175781(v=sql.80).aspx ) Obwohl es einen kleinen Tweak brauchte, da neuere date-Typen keine Datumsberechnung zulassen, ist es ist sonst identisch.

EDIT: Ich habe den +1 wieder hinzugefügt, der irgendwie weggelassen wurde. Es ist auch erwähnenswert, dass diese Methode immer die Start- und Endtage zählt. Es wird auch davon ausgegangen, dass das Enddatum auf oder nach dem Startdatum liegt.

2
shawnt00

Ich weiß, dass dies eine alte Frage ist, aber ich brauchte eine Formel für Arbeitstage ohne das Startdatum, da ich mehrere Artikel habe und die Tage brauchen, um sich richtig anzusammeln.

Keine der nicht-iterativen Antworten funktionierte für mich.

Ich habe eine Definition wie verwendet

Die Anzahl der Zeiten von Mitternacht bis Montag, Dienstag, Mittwoch, Donnerstag und Freitag ist vergangen

(Andere zählen Mitternacht bis Samstag anstelle von Montag)

Ich bin mit dieser Formel gelandet

SELECT DATEDIFF(day, @StartDate, @EndDate) /* all midnights passed */
     - DATEDIFF(week, @StartDate, @EndDate) /* remove sunday midnights */
     - DATEDIFF(week, DATEADD(day, 1, @StartDate), DATEADD(day, 1, @EndDate)) /* remove saturday midnights */
1
adrianm

Wenn Sie Arbeitstage zu einem bestimmten Datum hinzufügen müssen, können Sie eine Funktion erstellen, die von einer Kalendertabelle abhängig ist (siehe unten):

CREATE TABLE Calendar
(
  dt SMALLDATETIME PRIMARY KEY, 
  IsWorkDay BIT
);

--fill the rows with normal days, weekends and holidays.


create function AddWorkingDays (@initialDate smalldatetime, @numberOfDays int)
    returns smalldatetime as 

    begin
        declare @result smalldatetime
        set @result = 
        (
            select t.dt from
            (
                select dt, ROW_NUMBER() over (order by dt) as daysAhead from calendar 
                where dt > @initialDate
                and IsWorkDay = 1
                ) t
            where t.daysAhead = @numberOfDays
        )

        return @result
    end
1

Ich habe die verschiedenen Beispiele hier genommen, aber in meiner speziellen Situation haben wir ein @PromisedDate für die Lieferung und ein @ReceivedDate für den tatsächlichen Erhalt des Artikels. Wenn ein Artikel vor dem "PromisedDate" empfangen wurde, wurden die Berechnungen nicht korrekt summiert, es sei denn, ich ordnete die in der Funktion übergebenen Daten per Kalenderreihenfolge an. Da ich nicht jedes Mal die Daten überprüfen wollte, änderte ich die Funktion, um dies für mich zu erledigen.

Create FUNCTION [dbo].[fnGetBusinessDays]
(
 @PromiseDate date,
 @ReceivedDate date
)
RETURNS integer
AS
BEGIN
 DECLARE @days integer

 SELECT @days = 
    Case when @PromiseDate > @ReceivedDate Then
        DATEDIFF(d,@PromiseDate,@ReceivedDate) + 
        ABS(DATEDIFF(wk,@PromiseDate,@ReceivedDate)) * 2 +
        CASE 
            WHEN DATENAME(dw, @PromiseDate) <> 'Saturday' AND DATENAME(dw, @ReceivedDate) = 'Saturday' THEN 1 
            WHEN DATENAME(dw, @PromiseDate) = 'Saturday' AND DATENAME(dw, @ReceivedDate) <> 'Saturday' THEN -1 
            ELSE 0
        END +
        (Select COUNT(*) FROM CompanyHolidays 
            WHERE HolidayDate BETWEEN @ReceivedDate AND @PromiseDate 
            AND DATENAME(dw, HolidayDate) <> 'Saturday' AND DATENAME(dw, HolidayDate) <> 'Sunday')
    Else
        DATEDIFF(d,@PromiseDate,@ReceivedDate)  -
        ABS(DATEDIFF(wk,@PromiseDate,@ReceivedDate)) * 2  -
            CASE 
                WHEN DATENAME(dw, @PromiseDate) <> 'Saturday' AND DATENAME(dw, @ReceivedDate) = 'Saturday' THEN 1 
                WHEN DATENAME(dw, @PromiseDate) = 'Saturday' AND DATENAME(dw, @ReceivedDate) <> 'Saturday' THEN -1 
                ELSE 0
            END -
        (Select COUNT(*) FROM CompanyHolidays 
            WHERE HolidayDate BETWEEN @PromiseDate and @ReceivedDate 
            AND DATENAME(dw, HolidayDate) <> 'Saturday' AND DATENAME(dw, HolidayDate) <> 'Sunday')
    End


 RETURN (@days)

END
1
RobertD
DECLARE @StartDate datetime,@EndDate datetime

select @StartDate='3/2/2010', @EndDate='3/7/2010'

DECLARE @TotalDays INT,@WorkDays INT

DECLARE @ReducedDayswithEndDate INT

DECLARE @WeekPart INT

DECLARE @DatePart INT

SET @TotalDays= DATEDIFF(day, @StartDate, @EndDate) +1

SELECT @ReducedDayswithEndDate = CASE DATENAME(weekday, @EndDate)
    WHEN 'Saturday' THEN 1
    WHEN 'Sunday' THEN 2
    ELSE 0 END

SET @[email protected]@ReducedDayswithEndDate

SET @[email protected]/7;

SET @[email protected]%7;

SET @WorkDays=(@WeekPart*5)[email protected]

SELECT @WorkDays
1
Muthuvel
CREATE FUNCTION x
(
    @StartDate DATETIME,
    @EndDate DATETIME
)
RETURNS INT
AS
BEGIN
    DECLARE @Teller INT

    SET @StartDate = DATEADD(dd,1,@StartDate)

    SET @Teller = 0
    IF DATEDIFF(dd,@StartDate,@EndDate) <= 0
    BEGIN
        SET @Teller = 0 
    END
    ELSE
    BEGIN
        WHILE
            DATEDIFF(dd,@StartDate,@EndDate) >= 0
        BEGIN
            IF DATEPART(dw,@StartDate) < 6
            BEGIN
                SET @Teller = @Teller + 1
            END
            SET @StartDate = DATEADD(dd,1,@StartDate)
        END
    END
    RETURN @Teller
END
1
bel

Ein Ansatz besteht darin, die Termine von Anfang bis Ende in Verbindung mit einem Fallausdruck zu verfolgen, der prüft, ob der Tag kein Samstag oder Sonntag ist, und eine Markierung (1 für Wochentag, 0 für Wochenende). Und am Ende nur Sum-Flags (es würde gleich der Anzahl von 1-Flags sein, da das andere Flag 0 ist), um die Anzahl der Wochentage anzugeben.

Sie können eine Dienstprogrammfunktion vom Typ GetNums (startNumber, endNumber) verwenden, die eine Reihe von Zahlen für das "Looping" vom Startdatum bis zum Enddatum generiert. Informationen zur Implementierung finden Sie unter http://tsql.solidq.com/SourceCodes/GetNums.txt . Die Logik kann auch für Feiertage erweitert werden (sagen Sie, wenn Sie einen Feiertagstisch haben)

declare @date1 as datetime = '19900101'
declare @date2 as datetime = '19900120'

select  sum(case when DATENAME(DW,currentDate) not in ('Saturday', 'Sunday') then 1 else 0 end) as noOfWorkDays
from dbo.GetNums(0,DATEDIFF(day,@date1, @date2)-1) as Num
cross apply (select DATEADD(day,n,@date1)) as Dates(currentDate)
0
umbersar

Wie bei DATEDIFF betrachte ich das Enddatum nicht als Teil des Intervalls. Die Anzahl der (z. B.) Sonntage zwischen @StartDate und @EndDate ist die Anzahl der Sonntage zwischen einem "ersten" Montag und dem @EndDate minus die Anzahl der Sonntage zwischen diesem "ersten" Montag und dem @StartDate. Wenn wir dies wissen, können wir die Anzahl der Arbeitstage wie folgt berechnen:

DECLARE @StartDate DATETIME
DECLARE @EndDate DATETIME
SET @StartDate = '2018/01/01'
SET @EndDate = '2019/01/01'

SELECT DATEDIFF(Day, @StartDate, @EndDate) -- Total Days
  - (DATEDIFF(Day, 0, @EndDate)/7 - DATEDIFF(Day, 0, @StartDate)/7) -- Sundays
  - (DATEDIFF(Day, -1, @EndDate)/7 - DATEDIFF(Day, -1, @StartDate)/7) -- Saturdays

Freundliche Grüße!

0
Wolfgang Kais
Create Function dbo.DateDiff_WeekDays 
(
@StartDate  DateTime,
@EndDate    DateTime
)
Returns Int
As

Begin   

Declare @Result Int = 0

While   @StartDate <= @EndDate
Begin 
    If DateName(DW, @StartDate) not in ('Saturday','Sunday')
        Begin
            Set @Result = @Result +1
        End
        Set @StartDate = DateAdd(Day, +1, @StartDate)
End

Return @Result

Ende

0
pix1985

Ich habe einige Ideen von anderen ausgeliehen, um meine Lösung zu erstellen. Ich verwende Inline-Code, um Wochenenden und US-Bundesfeiertage zu ignorieren. In meiner Umgebung ist EndDate möglicherweise null, wird jedoch niemals vor StartDate angegeben.

CREATE FUNCTION dbo.ufn_CalculateBusinessDays(
@StartDate DATE,
@EndDate DATE = NULL)

RETURNS INT
AS

BEGIN
DECLARE @TotalBusinessDays INT = 0;
DECLARE @TestDate DATE = @StartDate;


IF @EndDate IS NULL
    RETURN NULL;

WHILE @TestDate < @EndDate
BEGIN
    DECLARE @Month INT = DATEPART(MM, @TestDate);
    DECLARE @Day INT = DATEPART(DD, @TestDate);
    DECLARE @DayOfWeek INT = DATEPART(WEEKDAY, @TestDate) - 1; --Monday = 1, Tuesday = 2, etc.
    DECLARE @DayOccurrence INT = (@Day - 1) / 7 + 1; --Nth day of month (3rd Monday, for example)

    --Increment business day counter if not a weekend or holiday
    SELECT @TotalBusinessDays += (
        SELECT CASE
            --Saturday OR Sunday
            WHEN @DayOfWeek IN (6,7) THEN 0
            --New Year's Day
            WHEN @Month = 1 AND @Day = 1 THEN 0
            --MLK Jr. Day
            WHEN @Month = 1 AND @DayOfWeek = 1 AND @DayOccurrence = 3 THEN 0
            --G. Washington's Birthday
            WHEN @Month = 2 AND @DayOfWeek = 1 AND @DayOccurrence = 3 THEN 0
            --Memorial Day
            WHEN @Month = 5 AND @DayOfWeek = 1 AND @Day BETWEEN 25 AND 31 THEN 0
            --Independence Day
            WHEN @Month = 7 AND @Day = 4 THEN 0
            --Labor Day
            WHEN @Month = 9 AND @DayOfWeek = 1 AND @DayOccurrence = 1 THEN 0
            --Columbus Day
            WHEN @Month = 10 AND @DayOfWeek = 1 AND @DayOccurrence = 2 THEN 0
            --Veterans Day
            WHEN @Month = 11 AND @Day = 11 THEN 0
            --Thanksgiving
            WHEN @Month = 11 AND @DayOfWeek = 4 AND @DayOccurrence = 4 THEN 0
            --Christmas
            WHEN @Month = 12 AND @Day = 25 THEN 0
            ELSE 1
            END AS Result);

    SET @TestDate = DATEADD(dd, 1, @TestDate);
END

RETURN @TotalBusinessDays;
END
0
Gary

Ich fand die folgende TSQL eine ziemlich elegante Lösung (ich habe keine Berechtigung zum Ausführen von Funktionen). Ich fand die DATEDIFF ignoriert DATEFIRST und ich wollte, dass mein erster Tag der Woche ein Montag ist. Ich wollte auch, dass der erste Arbeitstag auf Null gesetzt wird, und wenn es an einem Wochenende fällt, ist Montag Null. Dies kann jemandem helfen, der eine etwas andere Anforderung hat :) 

Es behandelt keine Feiertage

SET DATEFIRST 1
SELECT
,(DATEDIFF(DD,  [StartDate], [EndDate]))        
-(DATEDIFF(wk,  [StartDate], [EndDate]))        
-(DATEDIFF(wk, DATEADD(dd,[email protected]@DATEFIRST,[StartDate]), DATEADD(dd,[email protected]@DATEFIRST,[EndDate]))) AS [WorkingDays] 
FROM /*Your Table*/ 
0
Baseline9

Funktion erstellen wie:

CREATE FUNCTION dbo.fn_WorkDays(@StartDate DATETIME, @EndDate DATETIME= NULL )
RETURNS INT 
AS
BEGIN
       DECLARE @Days int
       SET @Days = 0

       IF @EndDate = NULL
              SET @EndDate = EOMONTH(@StartDate) --last date of the month

       WHILE DATEDIFF(dd,@StartDate,@EndDate) >= 0
       BEGIN
              IF DATENAME(dw, @StartDate) <> 'Saturday' 
                     and DATENAME(dw, @StartDate) <> 'Sunday' 
                     and Not ((Day(@StartDate) = 1 And Month(@StartDate) = 1)) --New Year's Day.
                     and Not ((Day(@StartDate) = 4 And Month(@StartDate) = 7)) --Independence Day.
              BEGIN
                     SET @Days = @Days + 1
              END

              SET @StartDate = DATEADD(dd,1,@StartDate)
       END

       RETURN  @Days
END

Sie können die Funktion wie folgt aufrufen: 

select dbo.fn_WorkDays('1/1/2016', '9/25/2016')

Oder wie:

select dbo.fn_WorkDays(StartDate, EndDate) 
from table1
0
Igor Krupitsky

Das ist für mich in meinem Land am Samstag und Sonntag arbeitsfrei.

Für mich ist die Zeit von @StartDate und @EndDate wichtig.

CREATE FUNCTION [dbo].[fnGetCountWorkingBusinessDays]
(
    @StartDate as DATETIME,
    @EndDate as DATETIME
)
RETURNS INT
AS
BEGIN
    DECLARE @res int

SET @StartDate = CASE 
    WHEN DATENAME(dw, @StartDate) = 'Saturday' THEN DATEADD(dd, 2, DATEDIFF(dd, 0, @StartDate))
    WHEN DATENAME(dw, @StartDate) = 'Sunday' THEN DATEADD(dd, 1, DATEDIFF(dd, 0, @StartDate))
    ELSE @StartDate END

SET @EndDate = CASE 
    WHEN DATENAME(dw, @EndDate) = 'Saturday' THEN DATEADD(dd, 0, DATEDIFF(dd, 0, @EndDate))
    WHEN DATENAME(dw, @EndDate) = 'Sunday' THEN DATEADD(dd, -1, DATEDIFF(dd, 0, @EndDate))
    ELSE @EndDate END


SET @res =
    (DATEDIFF(hour, @StartDate, @EndDate) / 24)
  - (DATEDIFF(wk, @StartDate, @EndDate) * 2)

SET @res = CASE WHEN @res < 0 THEN 0 ELSE @res END

    RETURN @res
END

GO
0
user3424126