Saya baru menyadari bahwa kode ini tidak berfungsi selalu! saya mencoba ini: SET @StartDate = '28 -mar-2011 'SET @EndDate = '29 -mar-2011' jawaban yang dihitung sebagai 2 hari
greektreat
16
@ greektreat Ini berfungsi dengan baik. Hanya saja @StartDate dan @EndDate sudah termasuk dalam hitungan. Jika Anda ingin Senin hingga Selasa dihitung sebagai 1 hari, cukup hapus "+ 1" setelah DATEIFF pertama. Maka Anda juga akan mendapatkan Fri-> Sat = 0, Fri-> Sun = 0, Fri-> Mon = 1.
Joe Daley
6
Sebagai tindak lanjut ke @JoeDaley. Ketika Anda menghapus +1 setelah DATEDIFF untuk mengecualikan tanggal mulai dari hitungan Anda juga perlu menyesuaikan bagian KASUS ini. Saya akhirnya menggunakan ini: + (KASUS KETIKA DATENAME (dw, @StartDate) = 'Sabtu' KEMUDIAN 1 LAIN 0 AKHIR) - (KASUS KETIKA DATENAME (dw, @EndDate) = 'Sabtu' KEMUDIAN 1 KEMUDIAN 1
SELURUH
7
Fungsi nama file tergantung pada lokal. Solusi yang lebih kuat tetapi juga lebih tidak jelas adalah mengganti dua baris terakhir dengan:-(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)
Torben Klein
2
Untuk mengklarifikasi komentar @ Sequenzia, Anda akan MENGHAPUS seluruh pernyataan kasus tentang hari Minggu, hanya menyisakan+(CASE WHEN DATENAME(dw, @StartDate) = 'Saturday' THEN 1 ELSE 0 END) - (CASE WHEN DATENAME(dw, @EndDate) = 'Saturday' THEN 1 ELSE 0 END)
Andy Raddatz
32
Dalam Menghitung Hari Kerja, Anda dapat menemukan artikel bagus tentang subjek ini, tetapi seperti yang Anda lihat, artikel itu tidak terlalu canggih.
--Changing current database to the Master database allows function to be shared by everyone.USE MASTER
GO
--If the function already exists, drop it.IFEXISTS(SELECT*FROM dbo.SYSOBJECTS
WHERE ID = OBJECT_ID(N'[dbo].[fn_WorkDays]')AND XType IN(N'FN', N'IF', N'TF'))DROPFUNCTION[dbo].[fn_WorkDays]
GO
CREATEFUNCTION 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 ISNULLRETURNNULL--If the End Date is null, populate with Start Date value so will have two dates (required by DATEDIFF below).IF@EndDate ISNULLSELECT@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-(CASEWHEN DATENAME(dw,@StartDate)='Sunday'THEN1ELSE0END)--If EndDate is a Saturday, Subtract 1-(CASEWHEN DATENAME(dw,@EndDate)='Saturday'THEN1ELSE0END))END
GO
Jika Anda perlu menggunakan kalender khusus, Anda mungkin perlu menambahkan beberapa cek dan beberapa parameter. Semoga ini akan memberikan titik awal yang baik.
Terima kasih telah menyertakan tautan untuk memahami cara kerjanya. Tulisan di sqlservercentral sangat bagus!
Chris Porter
20
Semua Kredit untuk Bogdan Maxim & Peter Mortensen. Ini adalah posting mereka, saya baru saja menambahkan hari libur ke fungsi (Ini mengasumsikan Anda memiliki tabel "tblHolidays" dengan bidang datetime "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.IFEXISTS(SELECT*FROM dbo.SYSOBJECTS
WHERE ID = OBJECT_ID(N'[dbo].[fn_WorkDays]')AND XType IN(N'FN', N'IF', N'TF'))DROPFUNCTION[dbo].[fn_WorkDays]
GO
CREATEFUNCTION 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 ISNULLRETURNNULL--If the End Date is null, populate with Start Date value so will have two dates (required by DATEDIFF below).IF@EndDate ISNULLSELECT@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-(CASEWHEN DATENAME(dw,@StartDate)='Sunday'THEN1ELSE0END)--If EndDate is a Saturday, Subtract 1-(CASEWHEN DATENAME(dw,@EndDate)='Saturday'THEN1ELSE0END)--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)
*/
Hai Dan B. Hanya untuk memberi tahu Anda bahwa versi Anda mengasumsikan bahwa tabel tblHolidays tidak mengandung hari Sabtu dan Senin, yang, kadang-kadang terjadi. Bagaimanapun, terima kasih telah berbagi versi Anda. Cheers
Julio Nobre
3
Julio - Ya - Versi saya berasumsi bahwa hari Sabtu dan Minggu (bukan hari Senin) adalah akhir pekan, dan karenanya bukan hari "non-bisnis". Tetapi jika Anda bekerja di akhir pekan, maka saya kira setiap hari adalah "hari kerja" dan Anda dapat mengomentari bagian hari Sabtu & Minggu dari klausa dan hanya menambahkan semua liburan Anda ke tabel tblHolidays.
Dan B
1
Terima kasih Dan. Saya memasukkan ini ke dalam fungsi saya, menambahkan cek untuk akhir pekan karena tabel DateDimensions saya mencakup semua tanggal, hari libur, dll. Mengambil fungsi Anda, saya baru saja menambahkan: dan IsWeekend = 0 setelah di mana [HolDate] antara StartDate dan EndDate)
AlsoKnownAsJazz
Jika tabel Liburan berisi hari libur di akhir pekan, Anda dapat mengubah kriteria seperti ini: WHERE HolDate BETWEEN @StartDate AND @EndDate AND DATEPART(dw, HolDate) BETWEEN 2 AND 6hanya menghitung hari libur dari Senin hingga Jumat.
Andre
7
Pendekatan lain untuk menghitung hari kerja adalah dengan menggunakan loop WHILE yang pada dasarnya iterasi melalui rentang tanggal dan menambahnya dengan 1 setiap kali hari ditemukan dalam hari Senin - Jumat. Script lengkap untuk menghitung hari kerja menggunakan loop WHILE ditunjukkan di bawah ini:
CREATEFUNCTION[dbo].[fn_GetTotalWorkingDaysUsingLoop](@DateFrom DATE,@DateTo DATE
)
RETURNS INT
ASBEGINDECLARE@TotWorkingDays INT=0;WHILE@DateFrom <=@DateTo
BEGINIF DATENAME(WEEKDAY,@DateFrom)IN('Monday','Tuesday','Wednesday','Thursday','Friday')BEGINSET@TotWorkingDays =@TotWorkingDays +1;END;SET@DateFrom = DATEADD(DAY,1,@DateFrom);END;RETURN@TotWorkingDays;END;
GO
Meskipun opsi WHILE loop lebih bersih dan menggunakan lebih sedikit baris kode, ini berpotensi menjadi hambatan kinerja di lingkungan Anda, terutama ketika rentang tanggal Anda mencakup beberapa tahun.
Versi saya dari jawaban yang diterima sebagai fungsi menggunakan DATEPART, jadi saya tidak perlu melakukan perbandingan string pada baris dengan
DATENAME(dw,@StartDate)='Sunday'
Bagaimanapun, inilah fungsi tanggal bisnis saya
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATEFUNCTION BDATEDIFF
(@startdate as DATETIME,@enddate as DATETIME
)
RETURNS INT
ASBEGINDECLARE@res int
SET@res =(DATEDIFF(dd,@startdate,@enddate)+1)-(DATEDIFF(wk,@startdate,@enddate)*2)-(CASEWHEN DATEPART(dw,@startdate)=1THEN1ELSE0END)-(CASEWHEN DATEPART(dw,@enddate)=7THEN1ELSE0END)RETURN@res
END
GO
DECLARE@TotalDays INT,@WorkDays INT
DECLARE@ReducedDayswithEndDate INT
DECLARE@WeekPart INT
DECLARE@DatePart INT
SET@TotalDays= DATEDIFF(day,@StartDate,@EndDate)+1SELECT@ReducedDayswithEndDate =CASE DATENAME(weekday,@EndDate)WHEN'Saturday'THEN1WHEN'Sunday'THEN2ELSE0ENDSET@TotalDays=@TotalDays-@ReducedDayswithEndDate
SET@WeekPart=@TotalDays/7;SET@DatePart=@TotalDays%7;SET@WorkDays=(@WeekPart*5)+@DatePart
RETURN@WorkDays
Jika Anda memposting kode, XML, atau sampel data, harap sorot baris itu di editor teks dan klik tombol "kode sampel" ({}) pada bilah alat editor untuk memformat dan sintaksis dengan baik!
marc_s
Hebat, tidak perlu untuk fungsi pinggiran atau pembaruan ke database menggunakan ini. Terima kasih. Love the saltire btw :-)
Brian Scott
Solusi super. Saya subbed dalam rumus untuk variabel untuk digunakan dalam webi Universe untuk menghitung hari kerja (MF) antara tanggal dalam 2 kolom tabel seperti begitu ... ((((DATEIFF (hari, table.col1, table.col2) +1) - ((KASUS DATENAME (hari kerja, table.col2) KETIKA 'Sabtu' KEMUDIAN 1 KETIKA 'Minggu' KEMUDIAN 2 LAIN 0 AKHIR))) / 7) * 5) + (((DATEIFF (hari, table.col1, table.col2 ) +1) - ((KASUS DATENAME (hari kerja, table.col2) KETIKA 'Sabtu' KEMUDIAN 1 KETIKA 'Minggu' KEMUDIAN 2 LAIN 0 AKHIR)))% 7)
Hilary
5
(Saya beberapa poin malu mengomentari hak istimewa)
Jika Anda memutuskan untuk melupakan hari +1 dalam solusi elegan CMS , perhatikan bahwa jika tanggal mulai dan tanggal akhir Anda berada di akhir pekan yang sama, Anda mendapat jawaban negatif. Yaitu, 2008/10/26 hingga 2008/10/26 mengembalikan -1.
.. yang juga mengatur semua posting yang salah dengan tanggal mulai setelah tanggal berakhir menjadi nol. Sesuatu yang Anda mungkin atau mungkin tidak cari.
Mengenai pengurangan liburan Anda. Bagaimana jika tanggal mulai 1 Januari dan tanggal berakhir 31 Desember? Anda hanya akan mengurangi 2 - yang salah. Saya mengusulkan untuk menggunakan DATEDIFF (hari, Start_Date, Tanggal) dan sama untuk End_Date daripada keseluruhan 'SELECT COUNT (*) FROM Holiday ...'.
Illia Ratkevych
4
Berikut adalah versi yang berfungsi dengan baik (saya pikir). Tabel hari libur berisi kolom Holiday_date yang berisi hari libur yang diamati perusahaan Anda.
Tanggal liburan itu mungkin jatuh pada akhir pekan juga. Dan bagi sebagian orang, liburan pada hari Minggu akan digantikan oleh hari Senin berikutnya.
Irawan Soetomo
3
Saya tahu ini adalah pertanyaan lama tetapi saya membutuhkan formula untuk hari kerja tidak termasuk tanggal mulai karena saya memiliki beberapa item dan perlu hari untuk diakumulasikan dengan benar.
Tidak ada jawaban yang tidak berulang yang bekerja untuk saya.
Saya menggunakan definisi seperti
Jumlah tengah malam hingga Senin, Selasa, Rabu, Kamis, dan Jumat dilewati
(orang lain mungkin menghitung tengah malam hingga Sabtu, bukan Senin)
Yang itu melakukannya untuk saya, tetapi saya harus melakukan perubahan kecil. Itu bukan akuntansi untuk kapan @StartDatehari Sabtu atau Jumat. Ini versi saya: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, saturday to sunday return 0, saturday to monday return 1, friday to saturday return 0. Semua konsisten dengan definisi saya. Kode Anda tidak akan terakumulasi dengan benar (mis.
Kembalikan
3
Ini pada dasarnya adalah jawaban CMS tanpa bergantung pada pengaturan bahasa tertentu. Dan karena kami memotret untuk generik, itu berarti ia harus bekerja untuk semua @@datefirstpengaturan juga.
datediff(day,<start>,<end>)+1- datediff(week,<start>,<end>)*2/* if start is a Sunday, adjust by -1 */+casewhen datepart(weekday,<start>)=8-@@datefirst then-1else0end/* if end is a Saturday, adjust by -1 */+casewhen datepart(weekday,<end>)=(13-@@datefirst)%7+1then-1else0end
datediff(week, ...)selalu menggunakan batas Sabtu-ke-Minggu selama berminggu-minggu, sehingga ungkapan itu deterministik dan tidak perlu diubah (selama definisi kami tentang hari kerja secara konsisten Senin hingga Jumat). Penomoran hari berbeda-beda sesuai dengan @@datefirstpengaturan dan pengaturan perhitungan yang dimodifikasi menangani koreksi ini dengan komplikasi kecil dari beberapa aritmatika modular.
Cara yang lebih bersih untuk menangani masalah Sabtu / Minggu adalah menerjemahkan tanggal sebelum mengekstraksi nilai satu hari dalam seminggu. Setelah bergeser, nilainya akan kembali sesuai dengan penomoran tetap (dan mungkin lebih akrab) yang dimulai dengan 1 pada hari Minggu dan berakhir dengan 7 pada hari Sabtu.
Saya telah melacak bentuk solusi ini paling tidak sejauh tahun 2002 dan artikel Itzik Ben-Gan. ( https://technet.microsoft.com/en-us/library/aa175781(v=sql.80).aspx ) Meskipun perlu sedikit penyesuaian karena datejenis yang lebih baru tidak memungkinkan aritmatika tanggal, namun identik.
EDIT: Saya menambahkan kembali +1yang entah bagaimana telah ditinggalkan. Penting juga dicatat bahwa metode ini selalu menghitung hari awal dan akhir. Ini juga mengasumsikan bahwa tanggal akhir adalah pada atau setelah tanggal mulai.
Perhatikan bahwa ini akan mengembalikan hasil yang salah untuk banyak tanggal di akhir pekan sehingga mereka tidak menambahkan upp (Fri-> Mon harus sama dengan Fri-> Sat + Sat-> Sun + Sun-> Mon). Fri-> Sat harus 0 (benar), Sat-> Sun harus 0 (salah -1), Sun-> Mon harus 1 (salah 0). Kesalahan lain yang mengikuti dari ini adalah Sat-> Sat = -1, Sun-> Sun = -1, Sun-> Sat = 4
adrianm
@adrianm Saya yakin saya telah memperbaiki masalah ini. Sebenarnya masalahnya adalah selalu rusak karena saya entah bagaimana telah menjatuhkan bagian itu secara tidak sengaja.
shawnt00
Terima kasih atas pembaruannya. Saya pikir formula Anda tidak termasuk tanggal mulai yang saya butuhkan. Memecahkannya sendiri dan menambahkannya sebagai jawaban lain.
adrianm
2
Menggunakan tabel tanggal:
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;
Jika tidak memilikinya, Anda dapat menggunakan tabel angka:
DECLARE@StartDate datetime ='2014-01-01',@EndDate datetime ='2014-01-31';SELECT
SUM(CASEWHEN DATEPART(dw, DATEADD(dd, Number-1,@StartDate))BETWEEN2AND6THEN1ELSE0END)As NumberOfWeekDays
FROM dbo.Numbers
WHERE Number <= DATEDIFF(dd,@StartDate,@EndDate)+1-- Number table starts at 1, we want a 0 base
Keduanya harus cepat dan menghilangkan ambiguitas / kompleksitas. Opsi pertama adalah yang terbaik tetapi jika Anda tidak memiliki tabel kalender Anda bisa membuat tabel angka dengan CTE.
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)+1SELECT@ReducedDayswithEndDate =CASE DATENAME(weekday,@EndDate)WHEN'Saturday'THEN1WHEN'Sunday'THEN2ELSE0ENDSET@TotalDays=@TotalDays-@ReducedDayswithEndDate
SET@WeekPart=@TotalDays/7;SET@DatePart=@TotalDays%7;SET@WorkDays=(@WeekPart*5)+@DatePart
SELECT@WorkDays
Saya mengambil berbagai contoh di sini, tetapi dalam situasi khusus saya, kami memiliki @PromisedDate untuk pengiriman dan @ReceivedDate untuk penerimaan barang yang sebenarnya. Ketika sebuah item diterima sebelum "PromisedDate" perhitungannya tidak total dengan benar kecuali saya memesan tanggal yang dilewatkan ke fungsi berdasarkan pesanan kalender. Tidak ingin memeriksa tanggal setiap kali, saya mengubah fungsi untuk menangani ini untuk saya.
CreateFUNCTION[dbo].[fnGetBusinessDays](@PromiseDate date,@ReceivedDate date
)
RETURNS integer
ASBEGINDECLARE@days integer
SELECT@days =Casewhen@PromiseDate >@ReceivedDate Then
DATEDIFF(d,@PromiseDate,@ReceivedDate)+
ABS(DATEDIFF(wk,@PromiseDate,@ReceivedDate))*2+CASEWHEN DATENAME(dw,@PromiseDate)<>'Saturday'AND DATENAME(dw,@ReceivedDate)='Saturday'THEN1WHEN DATENAME(dw,@PromiseDate)='Saturday'AND DATENAME(dw,@ReceivedDate)<>'Saturday'THEN-1ELSE0END+(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-CASEWHEN DATENAME(dw,@PromiseDate)<>'Saturday'AND DATENAME(dw,@ReceivedDate)='Saturday'THEN1WHEN DATENAME(dw,@PromiseDate)='Saturday'AND DATENAME(dw,@ReceivedDate)<>'Saturday'THEN-1ELSE0END-(Select COUNT(*)FROM CompanyHolidays
WHERE HolidayDate BETWEEN@PromiseDate and@ReceivedDate
AND DATENAME(dw, HolidayDate)<>'Saturday'AND DATENAME(dw, HolidayDate)<>'Sunday')EndRETURN(@days)END
Jika Anda perlu menambahkan hari kerja ke tanggal tertentu, Anda dapat membuat fungsi yang tergantung pada tabel kalender, yang dijelaskan di bawah ini:
CREATETABLE Calendar
(
dt SMALLDATETIME PRIMARYKEY,
IsWorkDay BIT
);--fill the rows with normal days, weekends and holidays.createfunction AddWorkingDays (@initialDate smalldatetime,@numberOfDays int)
returns smalldatetime asbegindeclare@result smalldatetime
set@result =(select t.dt from(select dt, ROW_NUMBER()over(orderby dt)as daysAhead from calendar
where dt >@initialDate
and IsWorkDay =1) t
where t.daysAhead =@numberOfDays
)return@result
end
Seperti halnya DATEIFF, saya tidak menganggap tanggal akhir sebagai bagian dari interval. Jumlah (misalnya) hari Minggu antara @StartDate dan @EndDate adalah jumlah hari Minggu antara Senin "awal" dan @EndDate dikurangi jumlah hari Minggu antara Senin "awal" ini dan @StartDate. Mengetahui hal ini, kita dapat menghitung jumlah hari kerja sebagai berikut:
CREATEFUNCTION dbo.fn_WorkDays(@StartDate DATETIME,@EndDate DATETIME=NULL)
RETURNS INT
ASBEGINDECLARE@Days int
SET@Days =0IF@EndDate =NULLSET@EndDate = EOMONTH(@StartDate)--last date of the monthWHILE DATEDIFF(dd,@StartDate,@EndDate)>=0BEGINIF DATENAME(dw,@StartDate)<>'Saturday'and DATENAME(dw,@StartDate)<>'Sunday'andNot((Day(@StartDate)=1And Month(@StartDate)=1))--New Year's Day.andNot((Day(@StartDate)=4And Month(@StartDate)=7))--Independence Day.BEGINSET@Days =@Days +1ENDSET@StartDate = DATEADD(dd,1,@StartDate)ENDRETURN@Days
END
Saya menemukan TSQL di bawah ini solusi yang cukup elegan (saya tidak memiliki izin untuk menjalankan fungsi). Saya menemukan DATEDIFFmengabaikanDATEFIRST dan saya ingin hari pertama dalam seminggu menjadi hari Senin. Saya juga ingin hari kerja pertama ditetapkan nol dan jika jatuh pada akhir pekan Senin akan menjadi nol. Ini dapat membantu seseorang yang memiliki persyaratan yang sedikit berbeda :)
Itu tidak menangani hari libur bank
SET DATEFIRST 1SELECT,(DATEDIFF(DD,[StartDate],[EndDate]))-(DATEDIFF(wk,[StartDate],[EndDate]))-(DATEDIFF(wk, DATEADD(dd,-@@DATEFIRST,[StartDate]), DATEADD(dd,-@@DATEFIRST,[EndDate])))AS[WorkingDays]FROM/*Your Table*/
Salah satu pendekatan adalah 'berjalan tanggal' dari awal sampai selesai bersama dengan ekspresi kasus yang memeriksa apakah hari itu bukan hari Sabtu atau Minggu dan menandai itu (1 untuk hari kerja, 0 untuk akhir pekan). Dan pada akhirnya hanya menjumlahkan bendera (itu akan sama dengan hitungan 1-bendera karena bendera lainnya adalah 0) untuk memberi Anda jumlah hari kerja.
Anda dapat menggunakan jenis fungsi utilitas GetNums (startNumber, endNumber) yang menghasilkan serangkaian angka untuk 'perulangan' dari tanggal mulai hingga tanggal berakhir. Rujuk http://tsql.solidq.com/SourceCodes/GetNums.txt untuk implementasi. Logikanya juga dapat diperpanjang untuk melayani liburan (katakanlah jika Anda memiliki meja liburan)
declare@date1 as datetime ='19900101'declare@date2 as datetime ='19900120'select sum(casewhen DATENAME(DW,currentDate)notin('Saturday','Sunday')then1else0end)as noOfWorkDays
from dbo.GetNums(0,DATEDIFF(day,@date1,@date2)-1)as Num
crossapply(select DATEADD(day,n,@date1))as Dates(currentDate)
Saya meminjam beberapa ide dari orang lain untuk menciptakan solusi saya. Saya menggunakan kode sebaris untuk mengabaikan akhir pekan dan hari libur federal AS. Di lingkungan saya, EndDate mungkin nol, tetapi itu tidak akan pernah mendahului StartDate.
CREATEFUNCTION dbo.ufn_CalculateBusinessDays(@StartDate DATE,@EndDate DATE =NULL)
RETURNS INT
ASBEGINDECLARE@TotalBusinessDays INT =0;DECLARE@TestDate DATE =@StartDate;IF@EndDate ISNULLRETURNNULL;WHILE@TestDate <@EndDate
BEGINDECLARE@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 holidaySELECT@TotalBusinessDays +=(SELECTCASE--Saturday OR SundayWHEN@DayOfWeek IN(6,7)THEN0--New Year's DayWHEN@Month =1AND@Day =1THEN0--MLK Jr. DayWHEN@Month =1AND@DayOfWeek =1AND@DayOccurrence =3THEN0--G. Washington's BirthdayWHEN@Month =2AND@DayOfWeek =1AND@DayOccurrence =3THEN0--Memorial DayWHEN@Month =5AND@DayOfWeek =1AND@Day BETWEEN25AND31THEN0--Independence DayWHEN@Month =7AND@Day =4THEN0--Labor DayWHEN@Month =9AND@DayOfWeek =1AND@DayOccurrence =1THEN0--Columbus DayWHEN@Month =10AND@DayOfWeek =1AND@DayOccurrence =2THEN0--Veterans DayWHEN@Month =11AND@Day =11THEN0--ThanksgivingWHEN@Month =11AND@DayOfWeek =4AND@DayOccurrence =4THEN0--ChristmasWHEN@Month =12AND@Day =25THEN0ELSE1ENDAS Result);SET@TestDate = DATEADD(dd,1,@TestDate);ENDRETURN@TotalBusinessDays;END
Jawaban:
Untuk hari kerja, Senin hingga Jumat, Anda dapat melakukannya dengan SELECT tunggal, seperti ini:
Jika Anda ingin memasukkan liburan, Anda harus menyelesaikannya ...
sumber
-(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)
+(CASE WHEN DATENAME(dw, @StartDate) = 'Saturday' THEN 1 ELSE 0 END) - (CASE WHEN DATENAME(dw, @EndDate) = 'Saturday' THEN 1 ELSE 0 END)
Dalam Menghitung Hari Kerja, Anda dapat menemukan artikel bagus tentang subjek ini, tetapi seperti yang Anda lihat, artikel itu tidak terlalu canggih.
Jika Anda perlu menggunakan kalender khusus, Anda mungkin perlu menambahkan beberapa cek dan beberapa parameter. Semoga ini akan memberikan titik awal yang baik.
sumber
Semua Kredit untuk Bogdan Maxim & Peter Mortensen. Ini adalah posting mereka, saya baru saja menambahkan hari libur ke fungsi (Ini mengasumsikan Anda memiliki tabel "tblHolidays" dengan bidang datetime "HolDate".
sumber
WHERE HolDate BETWEEN @StartDate AND @EndDate AND DATEPART(dw, HolDate) BETWEEN 2 AND 6
hanya menghitung hari libur dari Senin hingga Jumat.Pendekatan lain untuk menghitung hari kerja adalah dengan menggunakan loop WHILE yang pada dasarnya iterasi melalui rentang tanggal dan menambahnya dengan 1 setiap kali hari ditemukan dalam hari Senin - Jumat. Script lengkap untuk menghitung hari kerja menggunakan loop WHILE ditunjukkan di bawah ini:
Meskipun opsi WHILE loop lebih bersih dan menggunakan lebih sedikit baris kode, ini berpotensi menjadi hambatan kinerja di lingkungan Anda, terutama ketika rentang tanggal Anda mencakup beberapa tahun.
Anda dapat melihat lebih banyak metode tentang cara menghitung hari dan jam kerja di artikel ini: https://www.sqlshack.com/how-to-calculate-work-days-and-hours-in-sql-server/
sumber
Versi saya dari jawaban yang diterima sebagai fungsi menggunakan
DATEPART
, jadi saya tidak perlu melakukan perbandingan string pada baris denganBagaimanapun, inilah fungsi tanggal bisnis saya
sumber
sumber
(Saya beberapa poin malu mengomentari hak istimewa)
Jika Anda memutuskan untuk melupakan hari +1 dalam solusi elegan CMS , perhatikan bahwa jika tanggal mulai dan tanggal akhir Anda berada di akhir pekan yang sama, Anda mendapat jawaban negatif. Yaitu, 2008/10/26 hingga 2008/10/26 mengembalikan -1.
solusi saya yang agak sederhana:
.. yang juga mengatur semua posting yang salah dengan tanggal mulai setelah tanggal berakhir menjadi nol. Sesuatu yang Anda mungkin atau mungkin tidak cari.
sumber
Untuk perbedaan antara tanggal termasuk hari libur, saya pergi ke sini:
1) Meja dengan Hari Libur:
2) Saya punya Tabel perencanaan saya seperti ini dan ingin mengisi kolom Work_Days yang kosong:
3) Jadi untuk mendapatkan "Work_Days" untuk kemudian mengisi kolom saya harus:
Semoga saya bisa membantu.
Bersulang
sumber
Berikut adalah versi yang berfungsi dengan baik (saya pikir). Tabel hari libur berisi kolom Holiday_date yang berisi hari libur yang diamati perusahaan Anda.
sumber
Saya tahu ini adalah pertanyaan lama tetapi saya membutuhkan formula untuk hari kerja tidak termasuk tanggal mulai karena saya memiliki beberapa item dan perlu hari untuk diakumulasikan dengan benar.
Tidak ada jawaban yang tidak berulang yang bekerja untuk saya.
Saya menggunakan definisi seperti
(orang lain mungkin menghitung tengah malam hingga Sabtu, bukan Senin)
Saya berakhir dengan formula ini
sumber
@StartDate
hari Sabtu atau Jumat. Ini versi saya: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
Ini pada dasarnya adalah jawaban CMS tanpa bergantung pada pengaturan bahasa tertentu. Dan karena kami memotret untuk generik, itu berarti ia harus bekerja untuk semua
@@datefirst
pengaturan juga.datediff(week, ...)
selalu menggunakan batas Sabtu-ke-Minggu selama berminggu-minggu, sehingga ungkapan itu deterministik dan tidak perlu diubah (selama definisi kami tentang hari kerja secara konsisten Senin hingga Jumat). Penomoran hari berbeda-beda sesuai dengan@@datefirst
pengaturan dan pengaturan perhitungan yang dimodifikasi menangani koreksi ini dengan komplikasi kecil dari beberapa aritmatika modular.Cara yang lebih bersih untuk menangani masalah Sabtu / Minggu adalah menerjemahkan tanggal sebelum mengekstraksi nilai satu hari dalam seminggu. Setelah bergeser, nilainya akan kembali sesuai dengan penomoran tetap (dan mungkin lebih akrab) yang dimulai dengan 1 pada hari Minggu dan berakhir dengan 7 pada hari Sabtu.
Saya telah melacak bentuk solusi ini paling tidak sejauh tahun 2002 dan artikel Itzik Ben-Gan. ( https://technet.microsoft.com/en-us/library/aa175781(v=sql.80).aspx ) Meskipun perlu sedikit penyesuaian karena
date
jenis yang lebih baru tidak memungkinkan aritmatika tanggal, namun identik.EDIT: Saya menambahkan kembali
+1
yang entah bagaimana telah ditinggalkan. Penting juga dicatat bahwa metode ini selalu menghitung hari awal dan akhir. Ini juga mengasumsikan bahwa tanggal akhir adalah pada atau setelah tanggal mulai.sumber
Menggunakan tabel tanggal:
Jika tidak memilikinya, Anda dapat menggunakan tabel angka:
Keduanya harus cepat dan menghilangkan ambiguitas / kompleksitas. Opsi pertama adalah yang terbaik tetapi jika Anda tidak memiliki tabel kalender Anda bisa membuat tabel angka dengan CTE.
sumber
sumber
sumber
Saya mengambil berbagai contoh di sini, tetapi dalam situasi khusus saya, kami memiliki @PromisedDate untuk pengiriman dan @ReceivedDate untuk penerimaan barang yang sebenarnya. Ketika sebuah item diterima sebelum "PromisedDate" perhitungannya tidak total dengan benar kecuali saya memesan tanggal yang dilewatkan ke fungsi berdasarkan pesanan kalender. Tidak ingin memeriksa tanggal setiap kali, saya mengubah fungsi untuk menangani ini untuk saya.
sumber
Jika Anda perlu menambahkan hari kerja ke tanggal tertentu, Anda dapat membuat fungsi yang tergantung pada tabel kalender, yang dijelaskan di bawah ini:
sumber
Seperti halnya DATEIFF, saya tidak menganggap tanggal akhir sebagai bagian dari interval. Jumlah (misalnya) hari Minggu antara @StartDate dan @EndDate adalah jumlah hari Minggu antara Senin "awal" dan @EndDate dikurangi jumlah hari Minggu antara Senin "awal" ini dan @StartDate. Mengetahui hal ini, kita dapat menghitung jumlah hari kerja sebagai berikut:
Salam Hormat!
sumber
Itu bekerja untuk saya, di negara saya pada hari Sabtu dan Minggu adalah hari-hari yang tidak bekerja.
Bagi saya penting saat @StartDate dan @EndDate.
sumber
Buat fungsi seperti:
Anda dapat memanggil fungsi seperti:
Atau seperti:
sumber
Akhir
sumber
Saya menemukan TSQL di bawah ini solusi yang cukup elegan (saya tidak memiliki izin untuk menjalankan fungsi). Saya menemukan
DATEDIFF
mengabaikanDATEFIRST
dan saya ingin hari pertama dalam seminggu menjadi hari Senin. Saya juga ingin hari kerja pertama ditetapkan nol dan jika jatuh pada akhir pekan Senin akan menjadi nol. Ini dapat membantu seseorang yang memiliki persyaratan yang sedikit berbeda :)Itu tidak menangani hari libur bank
sumber
Salah satu pendekatan adalah 'berjalan tanggal' dari awal sampai selesai bersama dengan ekspresi kasus yang memeriksa apakah hari itu bukan hari Sabtu atau Minggu dan menandai itu (1 untuk hari kerja, 0 untuk akhir pekan). Dan pada akhirnya hanya menjumlahkan bendera (itu akan sama dengan hitungan 1-bendera karena bendera lainnya adalah 0) untuk memberi Anda jumlah hari kerja.
Anda dapat menggunakan jenis fungsi utilitas GetNums (startNumber, endNumber) yang menghasilkan serangkaian angka untuk 'perulangan' dari tanggal mulai hingga tanggal berakhir. Rujuk http://tsql.solidq.com/SourceCodes/GetNums.txt untuk implementasi. Logikanya juga dapat diperpanjang untuk melayani liburan (katakanlah jika Anda memiliki meja liburan)
sumber
Saya meminjam beberapa ide dari orang lain untuk menciptakan solusi saya. Saya menggunakan kode sebaris untuk mengabaikan akhir pekan dan hari libur federal AS. Di lingkungan saya, EndDate mungkin nol, tetapi itu tidak akan pernah mendahului StartDate.
sumber