दो तिथियों के बीच कार्य दिवसों की गणना करें


163

मैं SQL सर्वर में दो तिथियों के बीच कार्य दिवसों की संख्या की गणना कैसे कर सकता हूं?

सोमवार से शुक्रवार और यह टी-एसक्यूएल होना चाहिए।


5
क्या आप कार्यदिवस को परिभाषित कर सकते हैं? शुक्रवार किसी भी शुक्रवार के माध्यम से? प्रमुख छुट्टियों को छोड़कर? कौनसा देश? यह एसक्यूएल में किया जाना चाहिए?
डेव के

जवाबों:


301

कार्यदिवस के लिए, सोमवार से शुक्रवार, आप इसे एक ही चयन के साथ कर सकते हैं, जैसे:

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)

यदि आप छुट्टियों को शामिल करना चाहते हैं, तो आपको इसे थोड़ा काम करना होगा ...


3
मुझे बस एहसास हुआ कि यह कोड हमेशा काम नहीं करता है! मैंने इसे आज़माया: SET @StartDate = '28 -mar-2011 'SET @EndDate = '29 -mar-2011' इसका उत्तर इसे 2 दिनों के रूप में गिना गया
Huntreat

16
@grictreat यह ठीक काम करता है। यह सिर्फ इतना है कि @StartDate और @EndDate दोनों ही गिनती में शामिल हैं। यदि आप सोमवार से मंगलवार को 1 दिन के रूप में गिनना चाहते हैं, तो पहले DatedIFF के बाद "+ 1" हटा दें। फिर आपको शुक्र भी मिलेगा-> सत = 0, शुक्र-> सूर्य = 0, शुक्र-> सोम = 1।
जो डेलि

6
@JoeDaley को फॉलोअप के रूप में। जब आप गणना के प्रारंभ से बाहर करने के लिए दिनांकित के बाद + 1 को निकालते हैं, तो आपको इस के CASE भाग को समायोजित करने की भी आवश्यकता होती है। मैंने इसका उपयोग करके समाप्त किया: + (CASE WHEN DATENAME (dw, @StartDate) = 'शनिवार' को '1 ELSE 0 END) - (CASE WHEN DATENAME (dw, @EndDate =' Saturday 'THEN 1 ELSE 0 END)
Sequenzia

7
डेटानाम फ़ंक्शन स्थानीय-निर्भर है। एक और अधिक मजबूत, लेकिन अधिक अस्पष्ट समाधान अंतिम दो पंक्तियों को बदलने के लिए है:-(case datepart(dw, @StartDate)+@@datefirst when 8 then 1 else 0 end) -(case datepart(dw, @EndDate)+@@datefirst when 7 then 1 when 14 then 1 else 0 end)
तोरबेन क्लेन

2
@ सेक्ज़ेनिया की टिप्पणी को स्पष्ट करने के लिए, आप रविवार के बारे में पूरी तरह से मामले के बयानों को हटा देंगे, केवल छोड़कर+(CASE WHEN DATENAME(dw, @StartDate) = 'Saturday' THEN 1 ELSE 0 END) - (CASE WHEN DATENAME(dw, @EndDate) = 'Saturday' THEN 1 ELSE 0 END)
एंडी रेडडजेट

32

में गिना जा रहा है कार्य दिन आप इस विषय के बारे में एक अच्छा लेख पा सकते हैं, लेकिन जैसा कि आप देख सकते हैं यह है कि उन्नत नहीं है।

--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 --@EndDate 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

यदि आपको एक कस्टम कैलेंडर का उपयोग करने की आवश्यकता है, तो आपको कुछ चेक और कुछ मापदंडों को जोड़ने की आवश्यकता हो सकती है। उम्मीद है कि यह एक अच्छी शुरुआत प्रदान करेगा।


यह कैसे काम करता है यह समझने के लिए लिंक को शामिल करने के लिए धन्यवाद। Sqlservercentral पर लिखना बहुत अच्छा था!
क्रिस पोर्टर

20

बोगदान मैक्सिम और पीटर मोर्टेंसन को सभी क्रेडिट। यह उनका पद है, मैंने सिर्फ छुट्टियों को फ़ंक्शन में जोड़ा है (यह मानता है कि आपके पास एक टेबल "tblHolidays" है जिसमें एक डेटाइम फ़ील्ड "HolDate" है।

--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 --@EndDate 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)
*/

2
हाय दान बी। आपको यह बताने के लिए कि आपके संस्करण ने मान लिया है कि तालिका tblHolidays में शनिवार और सोमवार नहीं हैं, जो कभी-कभी होता है। वैसे भी, आपके संस्करण को साझा करने के लिए धन्यवाद। चीयर्स
जूलियो नोब्रे

3
जूलियो - हां - मेरा संस्करण मानता है कि शनिवार और रविवार (सोमवार नहीं) सप्ताहांत हैं, और इसके बाद "गैर-व्यवसाय" दिन नहीं है। लेकिन अगर आप सप्ताहांत में काम कर रहे हैं, तो मुझे लगता है कि हर रोज़ एक "कार्यदिवस" ​​होता है और आप खंड के शनिवार और रविवार के भाग की टिप्पणी कर सकते हैं और अपनी सभी छुट्टियों को tblHolidays तालिका में जोड़ सकते हैं।
दान बी

1
धन्यवाद डैन। मैंने इसे अपने फंक्शन में शामिल किया, वीकेंड्स के लिए एक चेक को जोड़ने के रूप में मेरी डेटडिमेंट्स टेबल में सभी तिथियां, छुट्टियां आदि शामिल हैं, आपके फंक्शन को लेते हुए, मैंने अभी जोड़ा: और IsWeekend = 0 जिसके बाद StartDate और EndDate के बीच [HolDate]
AlsoKnownAsJazz

यदि अवकाश तालिका में सप्ताहांत पर छुट्टियां होती हैं, तो आप इस तरह के मानदंड में संशोधन कर सकते हैं: WHERE HolDate BETWEEN @StartDate AND @EndDate AND DATEPART(dw, HolDate) BETWEEN 2 AND 6केवल सोमवार से शुक्रवार तक छुट्टियों की गणना करें।
आंद्रे

7

कार्य दिवसों की गणना करने के लिए एक और तरीका है एक WHILE लूप का उपयोग करना जो मूल रूप से एक तिथि सीमा के माध्यम से पुनरावृत्त करता है और इसे 1 से बढ़ाता है जब भी दिन सोमवार - शुक्रवार के भीतर पाए जाते हैं। WHILE लूप का उपयोग करके कार्य दिवसों की गणना के लिए पूरी स्क्रिप्ट नीचे दी गई है:

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

हालाँकि WHILE लूप विकल्प क्लीनर है और कोड की कम लाइनों का उपयोग करता है, लेकिन यह आपके वातावरण में एक प्रदर्शन अड़चन होने की संभावना है, खासकर जब आपकी तारीख कई वर्षों तक फैली हो।

आप इस लेख में काम के दिनों और घंटों की गणना करने के बारे में अधिक तरीके देख सकते हैं: https://www.sqlshack.com/how-to-calculate-work-days-and-hours-in-sql-server/


6

एक फ़ंक्शन के उपयोग के रूप में स्वीकृत उत्तर का मेरा संस्करण DATEPART, इसलिए मुझे लाइन पर एक स्ट्रिंग तुलना करने की आवश्यकता नहीं है

DATENAME(dw, @StartDate) = 'Sunday'

वैसे भी, यहाँ मेरा व्यवसाय दिनांकित कार्य है

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

5
 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 @TotalDays=@TotalDays-@ReducedDayswithEndDate
 SET @WeekPart=@TotalDays/7;
 SET @DatePart=@TotalDays%7;
 SET @WorkDays=(@WeekPart*5)+@DatePart

 RETURN @WorkDays

यदि आप कोड, एक्सएमएल या डेटा सैंपल पोस्ट करते हैं, तो कृपया टेक्स्ट एडिटर में उन पंक्तियों को हाइलाइट करें और एडिटर टूलबार पर "कोड सैंपल" बटन ({}) पर क्लिक करके अच्छी तरह से फॉर्मेट करें और सिंटैक्स इसे हाइलाइट करें!
marc_s

महान, इस का उपयोग कर डेटाबेस के लिए परिधि कार्यों या अपडेट की कोई आवश्यकता नहीं है। धन्यवाद। लवण बीटीडब्ल्यू :-)
ब्रायन स्कॉट

सुपर समाधान। मैं एक वेब यूनिवर्स में वेरिएबल्स का उपयोग करने के लिए सूत्रों में डूबा हुआ हूं ताकि 2 टेबल कॉलम में तारीखों के बीच सप्ताह के दिनों (एमएफ) की गणना की जा सके ... ((((DatedIFF, table.col1, table.col2) +1) - ((CASE DATENAME (कार्यदिवस, टेबल .col2) शनिवार को 'जब 1' रविवार 'तब 2 ELSE 0 END)) / 7) * 5) + (((DatedIFF (दिन, टेबल .col1, table.col2) ) +1) - ((CASE DATENAME (कार्यदिवस, तालिका .col2) शनिवार 'शनिवार' जब 1 रविवार 'तब 2 ELSE 0 END))% 7)
हिलेरी

5

(मैं विशेषाधिकारों पर टिप्पणी करने से कतराता हूं)

यदि आप CMS के सुरुचिपूर्ण समाधान में +1 दिन को त्यागने का निर्णय लेते हैं , तो ध्यान दें कि यदि आपकी आरंभ तिथि और अंतिम तिथि एक ही सप्ताहांत में है, तो आपको नकारात्मक उत्तर मिलता है। यानी, 2008/10/26 से 2008/10/26 रिटर्न -1।

मेरा बल्कि सरलीकृत समाधान:

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

.. जो कि अंतिम तिथि के बाद शुरू होने की तारीख के साथ सभी गलत पदों को भी शून्य पर सेट करता है। कुछ आप के लिए देख रहे हैं या नहीं हो सकता है।


5

छुट्टियों सहित तारीखों के अंतर के लिए मैं इस तरह गया:

1) छुट्टियों की तालिका:

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

2) मेरे पास इस तरह मेरी योजना तालिका थी और कॉलम भरना चाहते थे Work_Days जो खाली था:

    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) तो "Work_Days" प्राप्त करने के लिए बाद में मेरे कॉलम को बस भरना होगा:

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

उम्मीद है कि मैं मदद कर सकता हूं।

चियर्स


1
अपनी छुट्टियों के घटाव के बारे में। क्या होगा यदि प्रारंभ तिथि 1 जनवरी है और अंतिम तिथि 31 दिसंबर है? आप केवल 2 घटाएंगे - जो गलत है। मैं DATEIFF (दिन, Start_Date, दिनांक) और उसी के लिए End_Date का उपयोग करने के बजाय पूरे 'SELECT COUNT (*) FROM Holiday ...' का प्रस्ताव रखता हूं।
इलिया रात्केविच

4

यहां एक संस्करण है जो अच्छी तरह से काम करता है (मुझे लगता है)। हॉलिडे टेबल में Holiday_date कॉलम होते हैं जिसमें आपकी कंपनी की छुट्टियां होती हैं।

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 

उन छुट्टियों की तारीखें सप्ताहांत पर भी पड़ सकती हैं। और कुछ के लिए, रविवार को छुट्टी अगले सोमवार से बदल दी जाएगी।
इरावण सोतोमो

3

मुझे पता है कि यह एक पुराना प्रश्न है, लेकिन मेरे पास कार्यदिवस के लिए एक सूत्र की आवश्यकता है जो कि प्रारंभ की तारीख को छोड़कर मेरे पास कई आइटम हैं और दिनों को सही तरीके से संचित करने की आवश्यकता है।

किसी भी गैर-पुनरावृत्त उत्तर ने मेरे लिए काम नहीं किया।

मैंने जैसे डिफ्रेंटेशन का इस्तेमाल किया

सोमवार, मंगलवार, बुधवार, बुधवार और शुक्रवार को मध्यरात्रि की संख्या बीत जाती है

(अन्य सोमवार की बजाय शनिवार की आधी रात को गिन सकते हैं)

मैं इस सूत्र के साथ समाप्त हुआ

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
उस एक ने मेरे लिए किया लेकिन मुझे एक छोटा सा बदलाव करना था। यह @StartDateशनिवार या शुक्रवार का हिसाब नहीं है। यहाँ मेरा संस्करण है:DATEDIFF(day, @StartDate, @EndDate) - DATEDIFF(week, @StartDate, @EndDate) - DATEDIFF(week, DATEADD(day, 1, @StartDate), DATEADD(day, 1, @EndDate)) - (CASE WHEN DATEPART(WEEKDAY, @StartDate) IN (1, 7) THEN 1 ELSE 0 END) + 1
caiosm1005

@ caiosm1005, रविवार को रविवार का दिन 0, शनिवार को सोमवार का रिटर्न 1, शुक्रवार से शनिवार का रिटर्न 0. सभी मेरी परिभाषा के अनुरूप हैं। आपका कोड सही तरीके से जमा नहीं होगा (उदाहरण के लिए 6 शुक्रवार से शुक्रवार के लिए लौटें लेकिन सोमवार को सोमवार के लिए)
एड्रिनम

3

यह मूल रूप से एक विशेष भाषा सेटिंग पर निर्भरता के बिना सीएमएस का जवाब है। और जब से हम जेनेरिक के लिए शूटिंग कर रहे हैं, इसका मतलब है कि इसे सभी @@datefirstसेटिंग्स के लिए भी काम करना चाहिए ।

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, ...)हमेशा सप्ताह के लिए शनिवार-से-रविवार की सीमा का उपयोग करता है, ताकि अभिव्यक्ति नियतात्मक हो और इसे संशोधित करने की आवश्यकता न हो (जब तक कि कार्यदिवस की हमारी परिभाषा शुक्रवार के माध्यम से लगातार सोमवार हो।) दिन की संख्या @@datefirstसेटिंग के अनुसार भिन्न होती है । संशोधित गणना कुछ मॉड्यूलर अंकगणित की छोटी जटिलता के साथ इस सुधार को संभालती है।

शनिवार / रविवार की बात से निपटने के लिए एक क्लीनर तरीका सप्ताह के मूल्य का एक दिन निकालने से पहले की तारीखों का अनुवाद करना है। शिफ्टिंग के बाद, मान एक निश्चित (और शायद अधिक परिचित) क्रमांक के अनुसार वापस आ जाएंगे जो रविवार को 1 से शुरू होता है और शनिवार को 7 के साथ समाप्त होता है।

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

मैंने समाधान के इस रूप को कम से कम 2002 और इत्ज़िक बेन-गण लेख के रूप में ट्रैक किया है। ( https://technet.microsoft.com/en-us/library/aa175781(v=sql.80).aspx ) हालांकि इसे नए dateप्रकार की छोटी सी तारीख की आवश्यकता है क्योंकि नए प्रकार तारीख अंकगणित की अनुमति नहीं देते हैं, यह अन्यथा समान है।

संपादित करें: मैंने वापस जोड़ा है +1कि किसी भी तरह छोड़ दिया गया था। यह भी ध्यान देने योग्य है कि यह विधि हमेशा शुरुआत और अंत के दिनों को गिनती है। यह यह भी मानता है कि अंतिम तिथि प्रारंभ तिथि के बाद या उसके बाद है।


ध्यान दें कि यह सप्ताहांत में कई तिथियों के लिए गलत परिणाम लौटाएगा, ताकि वे upp (शुक्र-> सोम को शुक्र-> सत + सत-> सूर्य + सूर्य-> सोम) के समान न जोड़ें। शुक्र-> सत ० (सही) होना चाहिए, सत-> सूर्य ० (गलत -1) होना चाहिए, सूर्य-> सोम १ (गलत ०) होना चाहिए। इसके बाद की अन्य त्रुटियाँ हैं-> सत = -1, सूर्य-> सूर्य = -1, सूर्य-> शनि = 4
एड्रिनल

@adrianm मुझे विश्वास है कि मैंने मुद्दों को सही कर दिया था। दरअसल समस्या यह थी कि यह हमेशा एक-एक करके बंद हो जाता था क्योंकि मैं किसी तरह उस हिस्से को दुर्घटना से गिरा देता था।
shawnt00

अद्यतन के लिए धन्यवाद। मुझे लगा कि आपका फॉर्मूला स्टार्ट डेट को छोड़ रहा है जो मुझे चाहिए। इसे स्वयं हल किया और इसे दूसरे उत्तर के रूप में जोड़ा।
एड्रिनल जूल

2

दिनांक तालिका का उपयोग करना:

    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;

यदि आपके पास ऐसा नहीं है, तो आप एक संख्या तालिका का उपयोग कर सकते हैं:

    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

वे दोनों तेज होना चाहिए और यह अस्पष्टता / जटिलता को बाहर निकालता है। पहला विकल्प सबसे अच्छा है लेकिन अगर आपके पास कैलेंडर टेबल नहीं है तो आप CTE के साथ नंबर टेबल बना सकते हैं।


1
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 @TotalDays=@TotalDays-@ReducedDayswithEndDate

SET @WeekPart=@TotalDays/7;

SET @DatePart=@TotalDays%7;

SET @WorkDays=(@WeekPart*5)+@DatePart

SELECT @WorkDays

यदि आप किसी फंक्शन का उपयोग करने जा रहे हैं, तो मेजर मेयरेलस के जवाब
जेम्स जेनकिंस

1
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

मैंने विभिन्न उदाहरण यहां दिए हैं, लेकिन मेरी विशेष स्थिति में हमारे पास डिलीवरी के लिए एक @PromisedDate और आइटम की वास्तविक प्राप्ति के लिए एक @ReceivedDate है। जब "वादा" से पहले एक आइटम प्राप्त किया गया था, तो गणना सही ढंग से टोटल नहीं हो रही थी, जब तक कि मैं कैलेंडर आदेश के अनुसार फ़ंक्शन में पारित तारीखों का आदेश नहीं देता। हर बार तारीखों की जांच नहीं करने के कारण, मैंने इसे संभालने के लिए फ़ंक्शन को बदल दिया।

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

यदि आपको दी गई तारीख में कार्य दिवस जोड़ने की आवश्यकता है, तो आप एक फ़ंक्शन बना सकते हैं जो कैलेंडर तालिका पर निर्भर करता है, नीचे वर्णित है:

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

DatedIFF के साथ, मैं अंत की तारीख को अंतराल का हिस्सा नहीं मानता। (उदाहरण के लिए) रविवार की संख्या @StartDate और @EndDate के बीच के रविवारों की संख्या "प्रारंभिक" सोमवार और @EndDate के बीच के रविवारों की संख्या है, जो इस "प्रारंभिक" सोमवार और @StartDate के बीच है। यह जानते हुए, हम कार्यदिवसों की संख्या की गणना इस प्रकार कर सकते हैं:

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

सादर!


उत्तम! यह वही है जिसे मैं देख रहा था। विशेष धन्यवाद!
प्रेत

0

वह मेरे लिए काम कर रहा है, मेरे देश में शनिवार और रविवार गैर-कार्य दिवस हैं।

मेरे लिए @StartDate और @EndDate का समय महत्वपूर्ण है।

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

फ़ंक्शन बनाएं जैसे:

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

आप फ़ंक्शन को कॉल कर सकते हैं जैसे:

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

या पसंद करें:

select dbo.fn_WorkDays(StartDate, EndDate) 
from table1

0
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

समाप्त


0

मैं नीचे TSQL एक काफी सुंदर समाधान पाया (मैं कार्यों को चलाने के लिए अनुमति नहीं है)। मुझे DATEDIFFनज़रअंदाज़ कर दिया गया DATEFIRSTऔर मैं चाहता था कि सप्ताह का पहला दिन सोमवार हो। मैं यह भी चाहता था कि पहला कार्य दिवस एक शून्य निर्धारित किया जाए और यदि यह सोमवार को गिरता है तो यह शून्य होगा। यह किसी ऐसे व्यक्ति की मदद कर सकता है जिसकी थोड़ी अलग आवश्यकता है :)

यह बैंक की छुट्टियों को नहीं संभालता है

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

0

एक दृष्टिकोण एक मामले की अभिव्यक्ति के साथ शुरू से अंत तक तारीखों को 'चलना' है जो यह जांचता है कि क्या दिन शनिवार या रविवार नहीं है और इसे हरी झंडी दिखा रहा है (सप्ताहांत के लिए 1, सप्ताहांत के लिए 0)। और अंत में बस झंडे (यह 1-झंडे की गिनती के बराबर होगा क्योंकि अन्य ध्वज 0 है) आपको सप्ताह के दिनों की संख्या देगा।

आप GetNums (startNumber, endNumber) प्रकार के उपयोगिता फ़ंक्शन का उपयोग कर सकते हैं जो प्रारंभ तिथि से लेकर समाप्ति तिथि तक 'लूपिंग' के लिए संख्याओं की एक श्रृंखला उत्पन्न करता है। एक कार्यान्वयन के लिए http://tsql.solidq.com/SourceCodes/GetNums.txt देखें । तर्क को छुट्टियों के लिए पूरा करने के लिए भी बढ़ाया जा सकता है (यदि आपके पास एक अवकाश तालिका है)

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

मैंने अपना समाधान बनाने के लिए दूसरों से कुछ विचार उधार लिए। मैं सप्ताहांत और अमेरिकी संघीय छुट्टियों को अनदेखा करने के लिए इनलाइन कोड का उपयोग करता हूं। मेरे वातावरण में, EndDate अशक्त हो सकता है, लेकिन यह StartDate से पहले कभी नहीं होगा।

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
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.