में सी #, मैं कैसे की संख्या की गणना कर सकते हैं व्यापार दो तिथियों के बीच (या काम करने के दिन) दिनों?
में सी #, मैं कैसे की संख्या की गणना कर सकते हैं व्यापार दो तिथियों के बीच (या काम करने के दिन) दिनों?
जवाबों:
मैंने पहले भी ऐसा काम किया है और मुझे इसका हल मिल गया है। मैं बीच में सभी दिनों की गणना करने से बचूंगा जब यह परिहार्य होगा, जो कि यहां है। जैसा कि मैंने ऊपर दिए गए एक उत्तर में देखा था, मैं डेटटाइम इंस्टेंस का एक गुच्छा बनाने का उल्लेख नहीं करता हूं। यह वास्तव में प्रसंस्करण शक्ति की बर्बादी है। विशेष रूप से वास्तविक दुनिया की स्थिति में, जब आपको कई महीनों के समय अंतराल की जांच करनी होगी। नीचे दिए गए टिप्पणियों के साथ, मेरा कोड देखें।
/// <summary>
/// Calculates number of business days, taking into account:
/// - weekends (Saturdays and Sundays)
/// - bank holidays in the middle of the week
/// </summary>
/// <param name="firstDay">First day in the time interval</param>
/// <param name="lastDay">Last day in the time interval</param>
/// <param name="bankHolidays">List of bank holidays excluding weekends</param>
/// <returns>Number of business days during the 'span'</returns>
public static int BusinessDaysUntil(this DateTime firstDay, DateTime lastDay, params DateTime[] bankHolidays)
{
firstDay = firstDay.Date;
lastDay = lastDay.Date;
if (firstDay > lastDay)
throw new ArgumentException("Incorrect last day " + lastDay);
TimeSpan span = lastDay - firstDay;
int businessDays = span.Days + 1;
int fullWeekCount = businessDays / 7;
// find out if there are weekends during the time exceedng the full weeks
if (businessDays > fullWeekCount*7)
{
// we are here to find out if there is a 1-day or 2-days weekend
// in the time interval remaining after subtracting the complete weeks
int firstDayOfWeek = (int) firstDay.DayOfWeek;
int lastDayOfWeek = (int) lastDay.DayOfWeek;
if (lastDayOfWeek < firstDayOfWeek)
lastDayOfWeek += 7;
if (firstDayOfWeek <= 6)
{
if (lastDayOfWeek >= 7)// Both Saturday and Sunday are in the remaining time interval
businessDays -= 2;
else if (lastDayOfWeek >= 6)// Only Saturday is in the remaining time interval
businessDays -= 1;
}
else if (firstDayOfWeek <= 7 && lastDayOfWeek >= 7)// Only Sunday is in the remaining time interval
businessDays -= 1;
}
// subtract the weekends during the full weeks in the interval
businessDays -= fullWeekCount + fullWeekCount;
// subtract the number of bank holidays during the time interval
foreach (DateTime bankHoliday in bankHolidays)
{
DateTime bh = bankHoliday.Date;
if (firstDay <= bh && bh <= lastDay)
--businessDays;
}
return businessDays;
}
Slauma द्वारा संपादित, अगस्त 2011
बहुत बढ़िया जवाब! हालांकि थोड़ा बग है। मैं इस उत्तर को संपादित करने की स्वतंत्रता लेता हूं क्योंकि 2009 के बाद से उत्तरदाता अनुपस्थित है।
ऊपर DayOfWeek.Sunday
दिया गया कोड मानता है कि ऐसा मूल्य है 7
जो मामला नहीं है। मूल्य वास्तव में है 0
। यह गलत गणना की ओर जाता है यदि उदाहरण के लिए firstDay
और lastDay
दोनों एक ही रविवार हैं। 1
इस मामले में विधि वापस आती है लेकिन यह होनी चाहिए 0
।
इस बग के लिए सबसे आसान निर्धारण: लाइनों के ऊपर कोड में बदलें, जहां firstDayOfWeek
और lastDayOfWeek
निम्नलिखित द्वारा घोषित किए गए हैं:
int firstDayOfWeek = firstDay.DayOfWeek == DayOfWeek.Sunday
? 7 : (int)firstDay.DayOfWeek;
int lastDayOfWeek = lastDay.DayOfWeek == DayOfWeek.Sunday
? 7 : (int)lastDay.DayOfWeek;
अब परिणाम है:
&& !(bh.DayOfWeek == DayOfWeek.Sunday || bh.DayOfWeek == DayOfWeek.Saturday)
, अन्यथा यह एक ही दिन में दो बार घटित होगा, अगर एक सप्ताह के अंत में छुट्टी आती है।
ठीक। मुझे लगता है कि यह सही उत्तर पोस्ट करने का समय है:
public static double GetBusinessDays(DateTime startD, DateTime endD)
{
double calcBusinessDays =
1 + ((endD - startD).TotalDays * 5 -
(startD.DayOfWeek - endD.DayOfWeek) * 2) / 7;
if (endD.DayOfWeek == DayOfWeek.Saturday) calcBusinessDays--;
if (startD.DayOfWeek == DayOfWeek.Sunday) calcBusinessDays--;
return calcBusinessDays;
}
मूल स्रोत:
http://alecpojidaev.wordpress.com/2009/10/29/work-days-calculation-with-c/
PS समाधान ऊपर किसी कारण के लिए मुझे बनाने के लिए तैनात हैं।
मुझे पता है कि यह प्रश्न पहले से ही हल है, लेकिन मुझे लगा कि मैं एक और अधिक सरल-सटीक उत्तर प्रदान कर सकता हूं जो भविष्य में अन्य आगंतुकों की मदद कर सकता है।
यहाँ मेरा यह ले रहा है:
public int GetWorkingDays(DateTime from, DateTime to)
{
var dayDifference = (int)to.Subtract(from).TotalDays;
return Enumerable
.Range(1, dayDifference)
.Select(x => from.AddDays(x))
.Count(x => x.DayOfWeek != DayOfWeek.Saturday && x.DayOfWeek != DayOfWeek.Sunday);
}
यह मेरा मूल सबमिशन था:
public int GetWorkingDays(DateTime from, DateTime to)
{
var totalDays = 0;
for (var date = from; date < to; date = date.AddDays(1))
{
if (date.DayOfWeek != DayOfWeek.Saturday
&& date.DayOfWeek != DayOfWeek.Sunday)
totalDays++;
}
return totalDays;
}
to > from
। शायद यही समस्या है?
डेटटाइम पर एक्सटेंशन विधि को इस तरह परिभाषित करें:
public static class DateTimeExtensions
{
public static bool IsWorkingDay(this DateTime date)
{
return date.DayOfWeek != DayOfWeek.Saturday
&& date.DayOfWeek != DayOfWeek.Sunday;
}
}
फिर, तारीखों की एक विस्तृत सूची को फ़िल्टर करने के लिए एक क्लॉज़ का उपयोग कहाँ होता है:
var allDates = GetDates(); // method which returns a list of dates
// filter dates by working day's
var countOfWorkDays = allDates
.Where(day => day.IsWorkingDay())
.Count() ;
मैंने बैंक की छुट्टियों को ध्यान में रखते हुए निम्नलिखित कोड का उपयोग किया:
public class WorkingDays
{
public List<DateTime> GetHolidays()
{
var client = new WebClient();
var json = client.DownloadString("https://www.gov.uk/bank-holidays.json");
var js = new JavaScriptSerializer();
var holidays = js.Deserialize <Dictionary<string, Holidays>>(json);
return holidays["england-and-wales"].events.Select(d => d.date).ToList();
}
public int GetWorkingDays(DateTime from, DateTime to)
{
var totalDays = 0;
var holidays = GetHolidays();
for (var date = from.AddDays(1); date <= to; date = date.AddDays(1))
{
if (date.DayOfWeek != DayOfWeek.Saturday
&& date.DayOfWeek != DayOfWeek.Sunday
&& !holidays.Contains(date))
totalDays++;
}
return totalDays;
}
}
public class Holidays
{
public string division { get; set; }
public List<Event> events { get; set; }
}
public class Event
{
public DateTime date { get; set; }
public string notes { get; set; }
public string title { get; set; }
}
और यूनिट टेस्ट:
[TestClass]
public class WorkingDays
{
[TestMethod]
public void SameDayIsZero()
{
var service = new WorkingDays();
var from = new DateTime(2013, 8, 12);
Assert.AreEqual(0, service.GetWorkingDays(from, from));
}
[TestMethod]
public void CalculateDaysInWorkingWeek()
{
var service = new WorkingDays();
var from = new DateTime(2013, 8, 12);
var to = new DateTime(2013, 8, 16);
Assert.AreEqual(4, service.GetWorkingDays(from, to), "Mon - Fri = 4");
Assert.AreEqual(1, service.GetWorkingDays(from, new DateTime(2013, 8, 13)), "Mon - Tues = 1");
}
[TestMethod]
public void NotIncludeWeekends()
{
var service = new WorkingDays();
var from = new DateTime(2013, 8, 9);
var to = new DateTime(2013, 8, 16);
Assert.AreEqual(5, service.GetWorkingDays(from, to), "Fri - Fri = 5");
Assert.AreEqual(2, service.GetWorkingDays(from, new DateTime(2013, 8, 13)), "Fri - Tues = 2");
Assert.AreEqual(1, service.GetWorkingDays(from, new DateTime(2013, 8, 12)), "Fri - Mon = 1");
}
[TestMethod]
public void AccountForHolidays()
{
var service = new WorkingDays();
var from = new DateTime(2013, 8, 23);
Assert.AreEqual(0, service.GetWorkingDays(from, new DateTime(2013, 8, 26)), "Fri - Mon = 0");
Assert.AreEqual(1, service.GetWorkingDays(from, new DateTime(2013, 8, 27)), "Fri - Tues = 1");
}
}
खैर इसको पीट-पीटकर मार डाला गया है। :) हालाँकि मैं अभी भी एक और उत्तर देने जा रहा हूँ क्योंकि मुझे कुछ अलग चाहिए था। यह समाधान इस मायने में अलग है कि यह एक बिजनेस टाइमस्पैन लौटाता है शुरुआत और अंत के बीच , और आप दिन के व्यापार घंटे निर्धारित कर सकते हैं, और छुट्टियां जोड़ सकते हैं। तो आप यह गणना करने के लिए उपयोग कर सकते हैं कि क्या यह एक दिन के भीतर, दिन भर में, सप्ताहांत में और यहाँ तक कि छुट्टियों के दौरान भी होता है। और आप केवल व्यावसायिक दिनों को प्राप्त कर सकते हैं या केवल प्राप्त किए गए टाइमफ़ैन ऑब्जेक्ट से आपको ज़रूरत नहीं है। और जिस तरह से यह दिनों की सूचियों का उपयोग करता है, आप देख सकते हैं कि गैर-कार्य दिवसों की सूची को जोड़ना कितना आसान होगा यदि यह विशिष्ट सत और सूर्य नहीं है। और मैंने एक साल तक परीक्षण किया, और यह सुपर फास्ट लगता है।
मुझे उम्मीद है कि कोड चिपकाना सटीक होगा। लेकिन मुझे पता है कि यह काम करता है।
public static TimeSpan GetBusinessTimespanBetween(
DateTime start, DateTime end,
TimeSpan workdayStartTime, TimeSpan workdayEndTime,
List<DateTime> holidays = null)
{
if (end < start)
throw new ArgumentException("start datetime must be before end datetime.");
// Just create an empty list for easier coding.
if (holidays == null) holidays = new List<DateTime>();
if (holidays.Where(x => x.TimeOfDay.Ticks > 0).Any())
throw new ArgumentException("holidays can not have a TimeOfDay, only the Date.");
var nonWorkDays = new List<DayOfWeek>() { DayOfWeek.Saturday, DayOfWeek.Sunday };
var startTime = start.TimeOfDay;
// If the start time is before the starting hours, set it to the starting hour.
if (startTime < workdayStartTime) startTime = workdayStartTime;
var timeBeforeEndOfWorkDay = workdayEndTime - startTime;
// If it's after the end of the day, then this time lapse doesn't count.
if (timeBeforeEndOfWorkDay.TotalSeconds < 0) timeBeforeEndOfWorkDay = new TimeSpan();
// If start is during a non work day, it doesn't count.
if (nonWorkDays.Contains(start.DayOfWeek)) timeBeforeEndOfWorkDay = new TimeSpan();
else if (holidays.Contains(start.Date)) timeBeforeEndOfWorkDay = new TimeSpan();
var endTime = end.TimeOfDay;
// If the end time is after the ending hours, set it to the ending hour.
if (endTime > workdayEndTime) endTime = workdayEndTime;
var timeAfterStartOfWorkDay = endTime - workdayStartTime;
// If it's before the start of the day, then this time lapse doesn't count.
if (timeAfterStartOfWorkDay.TotalSeconds < 0) timeAfterStartOfWorkDay = new TimeSpan();
// If end is during a non work day, it doesn't count.
if (nonWorkDays.Contains(end.DayOfWeek)) timeAfterStartOfWorkDay = new TimeSpan();
else if (holidays.Contains(end.Date)) timeAfterStartOfWorkDay = new TimeSpan();
// Easy scenario if the times are during the day day.
if (start.Date.CompareTo(end.Date) == 0)
{
if (nonWorkDays.Contains(start.DayOfWeek)) return new TimeSpan();
else if (holidays.Contains(start.Date)) return new TimeSpan();
return endTime - startTime;
}
else
{
var timeBetween = end - start;
var daysBetween = (int)Math.Floor(timeBetween.TotalDays);
var dailyWorkSeconds = (int)Math.Floor((workdayEndTime - workdayStartTime).TotalSeconds);
var businessDaysBetween = 0;
// Now the fun begins with calculating the actual Business days.
if (daysBetween > 0)
{
var nextStartDay = start.AddDays(1).Date;
var dayBeforeEnd = end.AddDays(-1).Date;
for (DateTime d = nextStartDay; d <= dayBeforeEnd; d = d.AddDays(1))
{
if (nonWorkDays.Contains(d.DayOfWeek)) continue;
else if (holidays.Contains(d.Date)) continue;
businessDaysBetween++;
}
}
var dailyWorkSecondsToAdd = dailyWorkSeconds * businessDaysBetween;
var output = timeBeforeEndOfWorkDay + timeAfterStartOfWorkDay;
output = output + new TimeSpan(0, 0, dailyWorkSecondsToAdd);
return output;
}
}
और यहाँ परीक्षण कोड है: ध्यान दें कि आपको इस फ़ंक्शन को काम करने के लिए टेस्ट कोड के लिए डेटहेल्पर नामक कक्षा में रखना होगा ।
[TestMethod]
public void TestGetBusinessTimespanBetween()
{
var workdayStart = new TimeSpan(8, 0, 0);
var workdayEnd = new TimeSpan(17, 0, 0);
var holidays = new List<DateTime>()
{
new DateTime(2018, 1, 15), // a Monday
new DateTime(2018, 2, 15) // a Thursday
};
var testdata = new[]
{
new
{
expectedMinutes = 0,
start = new DateTime(2016, 10, 19, 9, 50, 0),
end = new DateTime(2016, 10, 19, 9, 50, 0)
},
new
{
expectedMinutes = 10,
start = new DateTime(2016, 10, 19, 9, 50, 0),
end = new DateTime(2016, 10, 19, 10, 0, 0)
},
new
{
expectedMinutes = 5,
start = new DateTime(2016, 10, 19, 7, 50, 0),
end = new DateTime(2016, 10, 19, 8, 5, 0)
},
new
{
expectedMinutes = 5,
start = new DateTime(2016, 10, 19, 16, 55, 0),
end = new DateTime(2016, 10, 19, 17, 5, 0)
},
new
{
expectedMinutes = 15,
start = new DateTime(2016, 10, 19, 16, 50, 0),
end = new DateTime(2016, 10, 20, 8, 5, 0)
},
new
{
expectedMinutes = 10,
start = new DateTime(2016, 10, 19, 16, 50, 0),
end = new DateTime(2016, 10, 20, 7, 55, 0)
},
new
{
expectedMinutes = 5,
start = new DateTime(2016, 10, 19, 17, 10, 0),
end = new DateTime(2016, 10, 20, 8, 5, 0)
},
new
{
expectedMinutes = 0,
start = new DateTime(2016, 10, 19, 17, 10, 0),
end = new DateTime(2016, 10, 20, 7, 5, 0)
},
new
{
expectedMinutes = 545,
start = new DateTime(2016, 10, 19, 12, 10, 0),
end = new DateTime(2016, 10, 20, 12, 15, 0)
},
// Spanning multiple weekdays
new
{
expectedMinutes = 835,
start = new DateTime(2016, 10, 19, 12, 10, 0),
end = new DateTime(2016, 10, 21, 8, 5, 0)
},
// Spanning multiple weekdays
new
{
expectedMinutes = 1375,
start = new DateTime(2016, 10, 18, 12, 10, 0),
end = new DateTime(2016, 10, 21, 8, 5, 0)
},
// Spanning from a Thursday to a Tuesday, 5 mins short of complete day.
new
{
expectedMinutes = 1615,
start = new DateTime(2016, 10, 20, 12, 10, 0),
end = new DateTime(2016, 10, 25, 12, 5, 0)
},
// Spanning from a Thursday to a Tuesday, 5 mins beyond complete day.
new
{
expectedMinutes = 1625,
start = new DateTime(2016, 10, 20, 12, 10, 0),
end = new DateTime(2016, 10, 25, 12, 15, 0)
},
// Spanning from a Friday to a Monday, 5 mins beyond complete day.
new
{
expectedMinutes = 545,
start = new DateTime(2016, 10, 21, 12, 10, 0),
end = new DateTime(2016, 10, 24, 12, 15, 0)
},
// Spanning from a Friday to a Monday, 5 mins short complete day.
new
{
expectedMinutes = 535,
start = new DateTime(2016, 10, 21, 12, 10, 0),
end = new DateTime(2016, 10, 24, 12, 5, 0)
},
// Spanning from a Saturday to a Monday, 5 mins short complete day.
new
{
expectedMinutes = 245,
start = new DateTime(2016, 10, 22, 12, 10, 0),
end = new DateTime(2016, 10, 24, 12, 5, 0)
},
// Spanning from a Saturday to a Sunday, 5 mins beyond complete day.
new
{
expectedMinutes = 0,
start = new DateTime(2016, 10, 22, 12, 10, 0),
end = new DateTime(2016, 10, 23, 12, 15, 0)
},
// Times within the same Saturday.
new
{
expectedMinutes = 0,
start = new DateTime(2016, 10, 22, 12, 10, 0),
end = new DateTime(2016, 10, 23, 12, 15, 0)
},
// Spanning from a Saturday to the Sunday next week.
new
{
expectedMinutes = 2700,
start = new DateTime(2016, 10, 22, 12, 10, 0),
end = new DateTime(2016, 10, 30, 12, 15, 0)
},
// Spanning a year.
new
{
expectedMinutes = 143355,
start = new DateTime(2016, 10, 22, 12, 10, 0),
end = new DateTime(2017, 10, 30, 12, 15, 0)
},
// Spanning a year with 2 holidays.
new
{
expectedMinutes = 142815,
start = new DateTime(2017, 10, 22, 12, 10, 0),
end = new DateTime(2018, 10, 30, 12, 15, 0)
},
};
foreach (var item in testdata)
{
Assert.AreEqual(item.expectedMinutes,
DateHelper.GetBusinessTimespanBetween(
item.start, item.end,
workdayStart, workdayEnd,
holidays)
.TotalMinutes);
}
}
यह समाधान पुनरावृत्ति से बचा जाता है, दोनों + ve और -ve कार्यदिवसों के अंतर के लिए काम करता है और सप्ताह के दिनों की गिनती की धीमी विधि के खिलाफ प्रतिगमन के लिए एक इकाई परीक्षण सूट शामिल है। मैंने कार्यदिवस को जोड़ने के लिए एक संक्षिप्त विधि भी शामिल की है जो एक ही गैर-पुनरावृत्त तरीके से काम करता है।
यूनिट परीक्षण कुछ हजार तिथि संयोजनों को कवर करते हैं ताकि छोटे और बड़े दोनों तिथि सीमाओं के साथ सभी प्रारंभ / अंत कार्यदिवसों के संयोजन का परीक्षण किया जा सके।
महत्वपूर्ण : हम यह धारणा बनाते हैं कि हम शुरुआत की तारीख को छोड़कर और अंतिम तिथि सहित दिनों की गिनती कर रहे हैं। यह महत्वपूर्ण है जब कार्यदिवस की गिनती विशिष्ट शुरुआत / अंत दिनों के रूप में हो जिसमें आप शामिल हों / परिणाम को प्रभावित करें। यह भी सुनिश्चित करता है कि दो बराबर दिनों के बीच का अंतर हमेशा शून्य हो और हम केवल पूर्ण कार्य दिवसों को शामिल करें क्योंकि आमतौर पर आप चाहते हैं कि उत्तर चालू तिथि (किसी भी समय) पर किसी भी समय के लिए सही हो और पूर्ण समाप्ति तिथि शामिल करें (जैसे एक नियत तारीख)।
नोट: इस कोड को छुट्टियों के लिए एक अतिरिक्त समायोजन की आवश्यकता है लेकिन उपरोक्त धारणा को ध्यान में रखते हुए, इस कोड को प्रारंभ तिथि पर छुट्टियों को बाहर करना होगा।
कार्यदिवस जोड़ें:
private static readonly int[,] _addOffset =
{
// 0 1 2 3 4
{0, 1, 2, 3, 4}, // Su 0
{0, 1, 2, 3, 4}, // M 1
{0, 1, 2, 3, 6}, // Tu 2
{0, 1, 4, 5, 6}, // W 3
{0, 1, 4, 5, 6}, // Th 4
{0, 3, 4, 5, 6}, // F 5
{0, 2, 3, 4, 5}, // Sa 6
};
public static DateTime AddWeekdays(this DateTime date, int weekdays)
{
int extraDays = weekdays % 5;
int addDays = weekdays >= 0
? (weekdays / 5) * 7 + _addOffset[(int)date.DayOfWeek, extraDays]
: (weekdays / 5) * 7 - _addOffset[6 - (int)date.DayOfWeek, -extraDays];
return date.AddDays(addDays);
}
कार्यदिवस अंतर की गणना करें:
static readonly int[,] _diffOffset =
{
// Su M Tu W Th F Sa
{0, 1, 2, 3, 4, 5, 5}, // Su
{4, 0, 1, 2, 3, 4, 4}, // M
{3, 4, 0, 1, 2, 3, 3}, // Tu
{2, 3, 4, 0, 1, 2, 2}, // W
{1, 2, 3, 4, 0, 1, 1}, // Th
{0, 1, 2, 3, 4, 0, 0}, // F
{0, 1, 2, 3, 4, 5, 0}, // Sa
};
public static int GetWeekdaysDiff(this DateTime dtStart, DateTime dtEnd)
{
int daysDiff = (int)(dtEnd - dtStart).TotalDays;
return daysDiff >= 0
? 5 * (daysDiff / 7) + _diffOffset[(int) dtStart.DayOfWeek, (int) dtEnd.DayOfWeek]
: 5 * (daysDiff / 7) - _diffOffset[6 - (int) dtStart.DayOfWeek, 6 - (int) dtEnd.DayOfWeek];
}
मैंने पाया कि स्टैक ओवरफ्लो पर अधिकांश अन्य समाधान या तो धीमे (पुनरावृत्त) या अत्यधिक जटिल थे और कई सीधे सादे गलत थे। नैतिक कहानी है ... जब तक उस पर भरोसा न करें आपने इसे पूरी तरह से जांच नहीं लिया है !!
यूनिट परीक्षण NUnit Combinatorial परीक्षण और ShouldBe NUnit एक्सटेंशन पर आधारित है ।
[TestFixture]
public class DateTimeExtensionsTests
{
/// <summary>
/// Exclude start date, Include end date
/// </summary>
/// <param name="dtStart"></param>
/// <param name="dtEnd"></param>
/// <returns></returns>
private IEnumerable<DateTime> GetDateRange(DateTime dtStart, DateTime dtEnd)
{
Console.WriteLine(@"dtStart={0:yy-MMM-dd ddd}, dtEnd={1:yy-MMM-dd ddd}", dtStart, dtEnd);
TimeSpan diff = dtEnd - dtStart;
Console.WriteLine(diff);
if (dtStart <= dtEnd)
{
for (DateTime dt = dtStart.AddDays(1); dt <= dtEnd; dt = dt.AddDays(1))
{
Console.WriteLine(@"dt={0:yy-MMM-dd ddd}", dt);
yield return dt;
}
}
else
{
for (DateTime dt = dtStart.AddDays(-1); dt >= dtEnd; dt = dt.AddDays(-1))
{
Console.WriteLine(@"dt={0:yy-MMM-dd ddd}", dt);
yield return dt;
}
}
}
[Test, Combinatorial]
public void TestGetWeekdaysDiff(
[Values(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 20, 30)]
int startDay,
[Values(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 20, 30)]
int endDay,
[Values(7)]
int startMonth,
[Values(7)]
int endMonth)
{
// Arrange
DateTime dtStart = new DateTime(2016, startMonth, startDay);
DateTime dtEnd = new DateTime(2016, endMonth, endDay);
int nDays = GetDateRange(dtStart, dtEnd)
.Count(dt => dt.DayOfWeek != DayOfWeek.Saturday && dt.DayOfWeek != DayOfWeek.Sunday);
if (dtEnd < dtStart) nDays = -nDays;
Console.WriteLine(@"countBusDays={0}", nDays);
// Act / Assert
dtStart.GetWeekdaysDiff(dtEnd).ShouldBe(nDays);
}
[Test, Combinatorial]
public void TestAddWeekdays(
[Values(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 20, 30)]
int startDay,
[Values(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 20, 30)]
int weekdays)
{
DateTime dtStart = new DateTime(2016, 7, startDay);
DateTime dtEnd1 = dtStart.AddWeekdays(weekdays); // ADD
dtStart.GetWeekdaysDiff(dtEnd1).ShouldBe(weekdays);
DateTime dtEnd2 = dtStart.AddWeekdays(-weekdays); // SUBTRACT
dtStart.GetWeekdaysDiff(dtEnd2).ShouldBe(-weekdays);
}
}
उस उद्देश्य के लिए कुछ कोड यहां है, जिसमें सनी छुट्टियां हैं लेकिन आप गिन सकते हैं कि किन छुट्टियों को गिनना है। ध्यान दें कि मैंने एक सीमा जोड़ी है जिसे आप हटाना चाहते हैं, लेकिन यह एक वेब-आधारित प्रणाली के लिए था और मैं नहीं चाहता था कि कोई भी इस प्रक्रिया को हॉग करने के लिए किसी बड़ी तारीख में प्रवेश करे
public static int GetWorkdays(DateTime from ,DateTime to)
{
int limit = 9999;
int counter = 0;
DateTime current = from;
int result = 0;
if (from > to)
{
DateTime temp = from;
from = to;
to = temp;
}
if (from >= to)
{
return 0;
}
while (current <= to && counter < limit)
{
if (IsSwedishWorkday(current))
{
result++;
}
current = current.AddDays(1);
counter++;
}
return result;
}
public static bool IsSwedishWorkday(DateTime date)
{
return (!IsSwedishHoliday(date) && date.DayOfWeek != DayOfWeek.Saturday && date.DayOfWeek != DayOfWeek.Sunday);
}
public static bool IsSwedishHoliday(DateTime date)
{
return (
IsSameDay(GetEpiphanyDay(date.Year), date) ||
IsSameDay(GetMayDay(date.Year), date) ||
IsSameDay(GetSwedishNationalDay(date.Year), date) ||
IsSameDay(GetChristmasDay(date.Year), date) ||
IsSameDay(GetBoxingDay(date.Year), date) ||
IsSameDay(GetGoodFriday(date.Year), date) ||
IsSameDay(GetAscensionDay(date.Year), date) ||
IsSameDay(GetAllSaintsDay(date.Year), date) ||
IsSameDay(GetMidsummersDay(date.Year), date) ||
IsSameDay(GetPentecostDay(date.Year), date) ||
IsSameDay(GetEasterMonday(date.Year), date) ||
IsSameDay(GetNewYearsDay(date.Year), date) ||
IsSameDay(GetEasterDay(date.Year), date)
);
}
// Trettondagen
public static DateTime GetEpiphanyDay(int year)
{
return new DateTime(year, 1, 6);
}
// Första maj
public static DateTime GetMayDay(int year)
{
return new DateTime(year,5,1);
}
// Juldagen
public static DateTime GetSwedishNationalDay(int year)
{
return new DateTime(year, 6, 6);
}
// Juldagen
public static DateTime GetNewYearsDay(int year)
{
return new DateTime(year,1,1);
}
// Juldagen
public static DateTime GetChristmasDay(int year)
{
return new DateTime(year,12,25);
}
// Annandag jul
public static DateTime GetBoxingDay(int year)
{
return new DateTime(year, 12, 26);
}
// Långfredagen
public static DateTime GetGoodFriday(int year)
{
return GetEasterDay(year).AddDays(-3);
}
// Kristi himmelsfärdsdag
public static DateTime GetAscensionDay(int year)
{
return GetEasterDay(year).AddDays(5*7+4);
}
// Midsommar
public static DateTime GetAllSaintsDay(int year)
{
DateTime result = new DateTime(year,10,31);
while (result.DayOfWeek != DayOfWeek.Saturday)
{
result = result.AddDays(1);
}
return result;
}
// Midsommar
public static DateTime GetMidsummersDay(int year)
{
DateTime result = new DateTime(year, 6, 20);
while (result.DayOfWeek != DayOfWeek.Saturday)
{
result = result.AddDays(1);
}
return result;
}
// Pingstdagen
public static DateTime GetPentecostDay(int year)
{
return GetEasterDay(year).AddDays(7 * 7);
}
// Annandag påsk
public static DateTime GetEasterMonday(int year)
{
return GetEasterDay(year).AddDays(1);
}
public static DateTime GetEasterDay(int y)
{
double c;
double n;
double k;
double i;
double j;
double l;
double m;
double d;
c = System.Math.Floor(y / 100.0);
n = y - 19 * System.Math.Floor(y / 19.0);
k = System.Math.Floor((c - 17) / 25.0);
i = c - System.Math.Floor(c / 4) - System.Math.Floor((c - k) / 3) + 19 * n + 15;
i = i - 30 * System.Math.Floor(i / 30);
i = i - System.Math.Floor(i / 28) * (1 - System.Math.Floor(i / 28) * System.Math.Floor(29 / (i + 1)) * System.Math.Floor((21 - n) / 11));
j = y + System.Math.Floor(y / 4.0) + i + 2 - c + System.Math.Floor(c / 4);
j = j - 7 * System.Math.Floor(j / 7);
l = i - j;
m = 3 + System.Math.Floor((l + 40) / 44);// month
d = l + 28 - 31 * System.Math.Floor(m / 4);// day
double days = ((m == 3) ? d : d + 31);
DateTime result = new DateTime(y, 3, 1).AddDays(days-1);
return result;
}
यहाँ एक त्वरित नमूना कोड है। यह एक वर्ग विधि है, इसलिए केवल आपकी कक्षा के अंदर ही काम करेगी। यदि आप यह चाहते हैं static
, तो हस्ताक्षर को private static
(या public static
) में बदल दें।
private IEnumerable<DateTime> GetWorkingDays(DateTime sd, DateTime ed)
{
for (var d = sd; d <= ed; d = d.AddDays(1))
if (d.DayOfWeek != DayOfWeek.Saturday && d.DayOfWeek != DayOfWeek.Sunday)
yield return d;
}
यह विधि एक लूप वैरिएबल बनाता है d
, इसे शुरुआती दिन के लिए प्रारंभ करता है sd
, फिर एक दिन प्रत्येक वृद्धि ( d = d.AddDays(1)
) द्वारा बढ़ाता है ।
यह उपयोग करके वांछित मान लौटाता है yield
, जो ए बनाता है iterator
। पुनरावृत्तियों के बारे में अच्छी बात यह है कि वे IEnumerable
स्मृति के सभी मूल्यों को नहीं पकड़ते हैं , केवल प्रत्येक को क्रमिक रूप से बुलाते हैं। इसका मतलब यह है कि आप इस विधि को समय-समय पर याददाश्त से बाहर चलने की चिंता किए बिना कह सकते हैं।
मैंने 2 तारीखों के बीच काम के दिनों की गणना करने के लिए एक आसान, पचाने में आसान एल्गोरिथ्म, और राष्ट्रीय छुट्टियों को बाहर करने के लिए बहुत कुछ खोजा, और आखिरकार मैं इस दृष्टिकोण के साथ जाने का फैसला करता हूं:
public static int NumberOfWorkingDaysBetween2Dates(DateTime start,DateTime due,IEnumerable<DateTime> holidays)
{
var dic = new Dictionary<DateTime, DayOfWeek>();
var totalDays = (due - start).Days;
for (int i = 0; i < totalDays + 1; i++)
{
if (!holidays.Any(x => x == start.AddDays(i)))
dic.Add(start.AddDays(i), start.AddDays(i).DayOfWeek);
}
return dic.Where(x => x.Value != DayOfWeek.Saturday && x.Value != DayOfWeek.Sunday).Count();
}
मूल रूप से मैं प्रत्येक तिथि के साथ जाना चाहता था और अपनी स्थितियों का मूल्यांकन करना चाहता था:
लेकिन इसके अलावा मैं इसे तारीखों से बचना चाहता था।
1 पूर्ण वर्ष का मूल्यांकन करने के लिए समय को चलाने और मापने के लिए, मुझे निम्नलिखित परिणाम चाहिए:
static void Main(string[] args)
{
var start = new DateTime(2017, 1, 1);
var due = new DateTime(2017, 12, 31);
var sw = Stopwatch.StartNew();
var days = NumberOfWorkingDaysBetween2Dates(start, due,NationalHolidays());
sw.Stop();
Console.WriteLine($"Total working days = {days} --- time: {sw.Elapsed}");
Console.ReadLine();
// result is:
// Total working days = 249-- - time: 00:00:00.0269087
}
संपादित करें: एक नई विधि और अधिक सरल:
public static int ToBusinessWorkingDays(this DateTime start, DateTime due, DateTime[] holidays)
{
return Enumerable.Range(0, (due - start).Days)
.Select(a => start.AddDays(a))
.Where(a => a.DayOfWeek != DayOfWeek.Sunday)
.Where(a => a.DayOfWeek != DayOfWeek.Saturday)
.Count(a => !holidays.Any(x => x == a));
}
मुझे लगता है कि उपरोक्त उत्तरों में से कोई भी वास्तव में सही नहीं है। उनमें से कोई भी सभी विशेष मामलों को हल नहीं करता है जैसे कि तिथियां शुरू होती हैं और सप्ताहांत के मध्य में समाप्त होती हैं, जब तारीख शुक्रवार को शुरू होती है और अगले सोमवार को समाप्त होती है, आदि। इसके बाद, वे सभी गणनाओं को पूरे दौर में पूरा करते हैं। दिन, इसलिए यदि प्रारंभ की तारीख उदाहरण के लिए एक शनिवार के मध्य में है, तो यह गलत परिणाम देते हुए, कार्य दिवसों से पूरे दिन का स्थान ले लेगा ...
वैसे भी, यहां मेरा समाधान है जो काफी कुशल और सरल है और सभी मामलों के लिए काम करता है। शुरुआत और समाप्ति तिथियों के लिए चाल केवल पिछले सोमवार को खोजने के लिए है, और फिर सप्ताहांत के दौरान शुरू होने और समाप्त होने पर एक छोटा सा मुआवजा दें:
public double WorkDays(DateTime startDate, DateTime endDate){
double weekendDays;
double days = endDate.Subtract(startDate).TotalDays;
if(days<0) return 0;
DateTime startMonday = startDate.AddDays(DayOfWeek.Monday - startDate.DayOfWeek).Date;
DateTime endMonday = endDate.AddDays(DayOfWeek.Monday - endDate.DayOfWeek).Date;
weekendDays = ((endMonday.Subtract(startMonday).TotalDays) / 7) * 2;
// compute fractionary part of weekend days
double diffStart = startDate.Subtract(startMonday).TotalDays - 5;
double diffEnd = endDate.Subtract(endMonday).TotalDays - 5;
// compensate weekenddays
if(diffStart>0) weekendDays -= diffStart;
if(diffEnd>0) weekendDays += diffEnd;
return days - weekendDays;
}
यह विधि किसी भी लूप का उपयोग नहीं करती है और वास्तव में काफी सरल है। यह तिथि सीमा से पूरे सप्ताह तक फैलता है क्योंकि हम जानते हैं कि प्रत्येक सप्ताह में 5 व्यावसायिक दिन हैं। इसके बाद सही परिणाम प्राप्त करने के लिए प्रारंभ और समाप्ति से घटने के लिए व्यावसायिक दिनों की संख्या खोजने के लिए एक लुकअप तालिका का उपयोग करता है। मैंने यह दिखाने के लिए कि क्या चल रहा है, मदद करने के लिए गणना का विस्तार किया है, लेकिन यदि आवश्यक हो तो पूरी चीज को एक पंक्ति में संघनित किया जा सकता है।
वैसे भी, यह मेरे लिए काम करता है और इसलिए मैंने सोचा कि मैं इसे यहाँ पोस्ट करूँगा अगर यह दूसरों की मदद कर सकता है। खुश कोडिंग।
गणना
संस्कृति
कोड सोमवार से शुक्रवार कार्य सप्ताह मानता है। अन्य संस्कृतियों के लिए, जैसे कि रविवार से गुरुवार, आपको गणना से पहले की तारीखों की भरपाई करनी होगी।
तरीका
public int Weekdays(DateTime min, DateTime max)
{
if (min.Date > max.Date) throw new Exception("Invalid date span");
var t = (max.AddDays(1).Date - min.Date).TotalDays;
var a = (int) min.DayOfWeek;
var b = 6 - (int) max.DayOfWeek;
var k = 1.4;
var m = new int[]{0, 0, 1, 2, 3, 4, 5};
var c = m[a] + m[b];
return (int)((t + a + b) / k) - c;
}
मैं सिर्फ अपना समाधान साझा करूंगा। यह मेरे लिए काम करता है, शायद मैं अभी नोटिस नहीं करता / जानता हूं कि यह एक बग है। यदि कोई हो तो मैंने पहला अधूरा सप्ताह प्राप्त करके शुरू किया। एक पूरा सप्ताह रविवार से शनिवार तक का था, इसलिए यदि (int) _now.DayOfWeek 0 (रविवार) नहीं था, तो पहला सप्ताह अधूरा था।
मैं पहले सप्ताह के शनिवार के लिए 1 से पहले सप्ताह की गिनती को घटाता हूं और फिर नई गणना में जोड़ता हूं;
फिर मुझे आखिरी अधूरा हफ्ता मिलता है, फिर रविवार के लिए 1 घटाएं और फिर नई गिनती में जोड़ें।
फिर अंत में, पूरे सप्ताह की संख्या 5 (सप्ताह के दिनों) से गुणा करके नई गणना में जोड़ा गया।
public int RemoveNonWorkingDays(int numberOfDays){
int workingDays = 0;
int firstWeek = 7 - (int)_now.DayOfWeek;
if(firstWeek < 7){
if(firstWeek > numberOfDays)
return numberOfDays;
workingDays += firstWeek-1;
numberOfDays -= firstWeek;
}
int lastWeek = numberOfDays % 7;
if(lastWeek > 0){
numberOfDays -= lastWeek;
workingDays += lastWeek - 1;
}
workingDays += (numberOfDays/7)*5;
return workingDays;
}
मुझे इस कोड का एक ठोस TSQL संस्करण खोजने में समस्या हो रही थी। नीचे अनिवार्य रूप से हॉलिडे टेबल के अतिरिक्त सी # कोड का रूपांतरण है जिसका उपयोग छुट्टियों की पूर्व-गणना के लिए किया जाना चाहिए।
CREATE TABLE dbo.Holiday
(
HolidayDt DATE NOT NULL,
Name NVARCHAR(50) NOT NULL,
IsWeekday BIT NOT NULL,
CONSTRAINT PK_Holiday PRIMARY KEY (HolidayDt)
)
GO
CREATE INDEX IDX_Holiday ON Holiday (HolidayDt, IsWeekday)
GO
CREATE function dbo.GetBusinessDays
(
@FirstDay datetime,
@LastDay datetime
)
RETURNS INT
AS
BEGIN
DECLARE @BusinessDays INT, @FullWeekCount INT
SELECT @FirstDay = CONVERT(DATETIME,CONVERT(DATE,@FirstDay))
, @LastDay = CONVERT(DATETIME,CONVERT(DATE,@LastDay))
IF @FirstDay > @LastDay
RETURN NULL;
SELECT @BusinessDays = DATEDIFF(DAY, @FirstDay, @LastDay) + 1
SELECT @FullWeekCount = @BusinessDays / 7;
-- find out if there are weekends during the time exceedng the full weeks
IF @BusinessDays > (@FullWeekCount * 7)
BEGIN
-- we are here to find out if there is a 1-day or 2-days weekend
-- in the time interval remaining after subtracting the complete weeks
DECLARE @firstDayOfWeek INT, @lastDayOfWeek INT;
SELECT @firstDayOfWeek = DATEPART(DW, @FirstDay), @lastDayOfWeek = DATEPART(DW, @LastDay);
IF @lastDayOfWeek < @firstDayOfWeek
SELECT @lastDayOfWeek = @lastDayOfWeek + 7;
IF @firstDayOfWeek <= 6
BEGIN
IF (@lastDayOfWeek >= 7) --Both Saturday and Sunday are in the remaining time interval
BEGIN
SELECT @BusinessDays = @BusinessDays - 2
END
ELSE IF @lastDayOfWeek>=6 --Only Saturday is in the remaining time interval
BEGIN
SELECT @BusinessDays = @BusinessDays - 1
END
END
ELSE IF @firstDayOfWeek <= 7 AND @lastDayOfWeek >=7 -- Only Sunday is in the remaining time interval
BEGIN
SELECT @BusinessDays = @BusinessDays - 1
END
END
-- subtract the weekends during the full weeks in the interval
DECLARE @Holidays INT;
SELECT @Holidays = COUNT(*)
FROM Holiday
WHERE HolidayDt BETWEEN @FirstDay AND @LastDay
AND IsWeekday = CAST(1 AS BIT)
SELECT @BusinessDays = @BusinessDays - (@FullWeekCount + @FullWeekCount) -- - @Holidays
RETURN @BusinessDays
END
int BusinessDayDifference(DateTime Date1, DateTime Date2)
{
int Sign = 1;
if (Date2 > Date1)
{
Sign = -1;
DateTime TempDate = Date1;
Date1 = Date2;
Date2 = TempDate;
}
int BusDayDiff = (int)(Date1.Date - Date2.Date).TotalDays;
if (Date1.DayOfWeek == DayOfWeek.Saturday)
BusDayDiff -= 1;
if (Date2.DayOfWeek == DayOfWeek.Sunday)
BusDayDiff -= 1;
int Week1 = GetWeekNum(Date1);
int Week2 = GetWeekNum(Date2);
int WeekDiff = Week1 - Week2;
BusDayDiff -= WeekDiff * 2;
foreach (DateTime Holiday in Holidays)
if (Date1 >= Holiday && Date2 <= Holiday)
BusDayDiff--;
BusDayDiff *= Sign;
return BusDayDiff;
}
private int GetWeekNum(DateTime Date)
{
return (int)(Date.AddDays(-(int)Date.DayOfWeek).Ticks / TimeSpan.TicksPerDay / 7);
}
यहाँ इस समस्या का एक बहुत ही सरल समाधान है। हम दिन को बढ़ाने के लिए तारीख, अंतिम तिथि और "लूप के लिए" शुरू करते हैं और यह देखने के लिए गणना करते हैं कि क्या यह एक कार्यदिवस या एक सप्ताह के अंत में स्ट्रिंग DayOfWeek में कनवर्ट करके है।
class Program
{
static void Main(string[] args)
{
DateTime day = new DateTime();
Console.Write("Inser your end date (example: 01/30/2015): ");
DateTime endDate = DateTime.Parse(Console.ReadLine());
int numberOfDays = 0;
for (day = DateTime.Now.Date; day.Date < endDate.Date; day = day.Date.AddDays(1))
{
string dayToString = Convert.ToString(day.DayOfWeek);
if (dayToString != "Saturday" && dayToString != "Sunday") numberOfDays++;
}
Console.WriteLine("Number of working days (not including local holidays) between two dates is "+numberOfDays);
}
}
उत्तर और पैच के रूप में अनुशंसित टिप्पणी के आधार पर, साथ ही -> यह संस्करण डेज़ टू बिज़नेस-आवर्स में परिवर्तित करना चाहता है ... कंसाइडर्स उसी दिन घंटे भी।
/// <summary>
/// Calculates number of business days, taking into account:
/// - weekends (Saturdays and Sundays)
/// - bank holidays in the middle of the week
/// </summary>
/// <param name="firstDay">First day in the time interval</param>
/// <param name="lastDay">Last day in the time interval</param>
/// <param name="bankHolidays">List of bank holidays excluding weekends</param>
/// <returns>Number of business hours during the 'span'</returns>
public static int BusinessHoursUntil(DateTime firstDay, DateTime lastDay, params DateTime[] bankHolidays)
{
var original_firstDay = firstDay;
var original_lastDay = lastDay;
firstDay = firstDay.Date;
lastDay = lastDay.Date;
if (firstDay > lastDay)
return -1; //// throw new ArgumentException("Incorrect last day " + lastDay);
TimeSpan span = lastDay - firstDay;
int businessDays = span.Days + 1;
int fullWeekCount = businessDays / 7;
// find out if there are weekends during the time exceedng the full weeks
if (businessDays > fullWeekCount * 7)
{
// we are here to find out if there is a 1-day or 2-days weekend
// in the time interval remaining after subtracting the complete weeks
int firstDayOfWeek = firstDay.DayOfWeek == DayOfWeek.Sunday ? 7 : (int)firstDay.DayOfWeek;
int lastDayOfWeek = lastDay.DayOfWeek == DayOfWeek.Sunday ? 7 : (int)lastDay.DayOfWeek;
if (lastDayOfWeek < firstDayOfWeek)
lastDayOfWeek += 7;
if (firstDayOfWeek <= 6)
{
if (lastDayOfWeek >= 7)// Both Saturday and Sunday are in the remaining time interval
businessDays -= 2;
else if (lastDayOfWeek >= 6)// Only Saturday is in the remaining time interval
businessDays -= 1;
}
else if (firstDayOfWeek <= 7 && lastDayOfWeek >= 7)// Only Sunday is in the remaining time interval
businessDays -= 1;
}
// subtract the weekends during the full weeks in the interval
businessDays -= fullWeekCount + fullWeekCount;
if (bankHolidays != null && bankHolidays.Any())
{
// subtract the number of bank holidays during the time interval
foreach (DateTime bankHoliday in bankHolidays)
{
DateTime bh = bankHoliday.Date;
if (firstDay <= bh && bh <= lastDay)
--businessDays;
}
}
int total_business_hours = 0;
if (firstDay.Date == lastDay.Date)
{//If on the same day, go granular with Hours from the Orginial_*Day values
total_business_hours = (int)(original_lastDay - original_firstDay).TotalHours;
}
else
{//Convert Business-Days to TotalHours
total_business_hours = (int)(firstDay.AddDays(businessDays).AddHours(firstDay.Hour) - firstDay).TotalHours;
}
return total_business_hours;
}
using System;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
DateTime start = new DateTime(2014, 1, 1);
DateTime stop = new DateTime(2014, 12, 31);
int totalWorkingDays = GetNumberOfWorkingDays(start, stop);
Console.WriteLine("There are {0} working days.", totalWorkingDays);
}
private static int GetNumberOfWorkingDays(DateTime start, DateTime stop)
{
TimeSpan interval = stop - start;
int totalWeek = interval.Days / 7;
int totalWorkingDays = 5 * totalWeek;
int remainingDays = interval.Days % 7;
for (int i = 0; i <= remainingDays; i++)
{
DayOfWeek test = (DayOfWeek)(((int)start.DayOfWeek + i) % 7);
if (test >= DayOfWeek.Monday && test <= DayOfWeek.Friday)
totalWorkingDays++;
}
return totalWorkingDays;
}
}
}
मैंने एक व्यवसायिक सप्ताह को एक पैरामीटर के रूप में समर्थन करने के लिए @Alexander और @Slauma उत्तर में सुधार किया है, उन मामलों के लिए जहां शनिवार का दिन एक व्यावसायिक दिन है, या यहां तक कि ऐसे मामले भी हैं जहां सप्ताह के कुछ दिन हैं जिन्हें व्यावसायिक दिन माना जाता है:
/// <summary>
/// Calculate the number of business days between two dates, considering:
/// - Days of the week that are not considered business days.
/// - Holidays between these two dates.
/// </summary>
/// <param name="fDay">First day of the desired 'span'.</param>
/// <param name="lDay">Last day of the desired 'span'.</param>
/// <param name="BusinessDaysOfWeek">Days of the week that are considered to be business days, if NULL considers monday, tuesday, wednesday, thursday and friday as business days of the week.</param>
/// <param name="Holidays">Holidays, if NULL, considers no holiday.</param>
/// <returns>Number of business days during the 'span'</returns>
public static int BusinessDaysUntil(this DateTime fDay, DateTime lDay, DayOfWeek[] BusinessDaysOfWeek = null, DateTime[] Holidays = null)
{
if (BusinessDaysOfWeek == null)
BusinessDaysOfWeek = new DayOfWeek[] { DayOfWeek.Monday, DayOfWeek.Tuesday, DayOfWeek.Wednesday, DayOfWeek.Thursday, DayOfWeek.Friday };
if (Holidays == null)
Holidays = new DateTime[] { };
fDay = fDay.Date;
lDay = lDay.Date;
if (fDay > lDay)
throw new ArgumentException("Incorrect last day " + lDay);
int bDays = (lDay - fDay).Days + 1;
int fullWeekCount = bDays / 7;
int fullWeekCountMult = 7 - WeekDays.Length;
// Find out if there are weekends during the time exceedng the full weeks
if (bDays > (fullWeekCount * 7))
{
int fDayOfWeek = (int)fDay.DayOfWeek;
int lDayOfWeek = (int)lDay.DayOfWeek;
if (fDayOfWeek > lDayOfWeek)
lDayOfWeek += 7;
// If they are the same, we already covered it right before the Holiday subtraction
if (lDayOfWeek != fDayOfWeek)
{
// Here we need to see if any of the days between are considered business days
for (int i = fDayOfWeek; i <= lDayOfWeek; i++)
if (!WeekDays.Contains((DayOfWeek)(i > 6 ? i - 7 : i)))
bDays -= 1;
}
}
// Subtract the days that are not in WeekDays[] during the full weeks in the interval
bDays -= (fullWeekCount * fullWeekCountMult);
// Subtract the number of bank holidays during the time interval
bDays = bDays - Holidays.Select(x => x.Date).Count(x => fDay <= x && x <= lDay);
return bDays;
}
यहां वह फ़ंक्शन है जो हम दो दिनों के बीच व्यावसायिक दिनों की गणना करने के लिए उपयोग कर सकते हैं। मैं अवकाश सूची का उपयोग नहीं कर रहा हूं क्योंकि यह देश / क्षेत्र को अलग-अलग कर सकता है।
अगर हम इसे वैसे भी उपयोग करना चाहते हैं तो हम तीसरे तर्क को छुट्टी की सूची के रूप में ले सकते हैं और गिनती बढ़ाने से पहले हमें यह जांचना चाहिए कि सूची में क्या नहीं है
public static int GetBussinessDaysBetweenTwoDates(DateTime StartDate, DateTime EndDate)
{
if (StartDate > EndDate)
return -1;
int bd = 0;
for (DateTime d = StartDate; d < EndDate; d = d.AddDays(1))
{
if (d.DayOfWeek != DayOfWeek.Saturday && d.DayOfWeek != DayOfWeek.Sunday)
bd++;
}
return bd;
}
मेरा मानना है कि यह एक सरल तरीका हो सकता है:
public int BusinessDaysUntil(DateTime start, DateTime end, params DateTime[] bankHolidays)
{
int tld = (int)((end - start).TotalDays) + 1; //including end day
int not_buss_day = 2 * (tld / 7); //Saturday and Sunday
int rest = tld % 7; //rest.
if (rest > 0)
{
int tmp = (int)start.DayOfWeek - 1 + rest;
if (tmp == 6 || start.DayOfWeek == DayOfWeek.Sunday) not_buss_day++; else if (tmp > 6) not_buss_day += 2;
}
foreach (DateTime bankHoliday in bankHolidays)
{
DateTime bh = bankHoliday.Date;
if (!(bh.DayOfWeek == DayOfWeek.Saturday || bh.DayOfWeek == DayOfWeek.Sunday) && (start <= bh && bh <= end))
{
not_buss_day++;
}
}
return tld - not_buss_day;
}
यहां अभी तक एक और विचार है - यह विधि किसी भी कार्य सप्ताह और छुट्टियों को निर्दिष्ट करने की अनुमति देती है।
यहाँ विचार यह है कि हम सप्ताह के पहले पहले कार्य दिवस से लेकर सप्ताह के अंतिम सप्ताह के अंत तक की तारीख का मूल पाते हैं। यह हमें पूरे सप्ताह की आसानी से गणना करने में सक्षम बनाता है ( सभी तिथियों पर पुनरावृत्ति के बिना )। इसके बाद हमें बस इतना करना होगा कि इस कोर रेंज के शुरू होने और खत्म होने से पहले काम के दिनों को जोड़ा जाए।
public static int CalculateWorkingDays(
DateTime startDate,
DateTime endDate,
IList<DateTime> holidays,
DayOfWeek firstDayOfWeek,
DayOfWeek lastDayOfWeek)
{
// Make sure the defined working days run contiguously
if (lastDayOfWeek < firstDayOfWeek)
{
throw new Exception("Last day of week cannot fall before first day of week!");
}
// Create a list of the days of the week that make-up the weekend by working back
// from the firstDayOfWeek and forward from lastDayOfWeek to get the start and end
// the weekend
var weekendStart = lastDayOfWeek == DayOfWeek.Saturday ? DayOfWeek.Sunday : lastDayOfWeek + 1;
var weekendEnd = firstDayOfWeek == DayOfWeek.Sunday ? DayOfWeek.Saturday : firstDayOfWeek - 1;
var weekendDays = new List<DayOfWeek>();
var w = weekendStart;
do {
weekendDays.Add(w);
if (w == weekendEnd) break;
w = (w == DayOfWeek.Saturday) ? DayOfWeek.Sunday : w + 1;
} while (true);
// Force simple dates - no time
startDate = startDate.Date;
endDate = endDate.Date;
// Ensure a progessive date range
if (endDate < startDate)
{
var t = startDate;
startDate = endDate;
endDate = t;
}
// setup some working variables and constants
const int daysInWeek = 7; // yeah - really!
var actualStartDate = startDate; // this will end up on startOfWeek boundary
var actualEndDate = endDate; // this will end up on weekendEnd boundary
int workingDaysInWeek = daysInWeek - weekendDays.Count;
int workingDays = 0; // the result we are trying to find
int leadingDays = 0; // the number of working days leading up to the firstDayOfWeek boundary
int trailingDays = 0; // the number of working days counting back to the weekendEnd boundary
// Calculate leading working days
// if we aren't on the firstDayOfWeek we need to step forward to the nearest
if (startDate.DayOfWeek != firstDayOfWeek)
{
var d = startDate;
do {
if (d.DayOfWeek == firstDayOfWeek || d >= endDate)
{
actualStartDate = d;
break;
}
if (!weekendDays.Contains(d.DayOfWeek))
{
leadingDays++;
}
d = d.AddDays(1);
} while(true);
}
// Calculate trailing working days
// if we aren't on the weekendEnd we step back to the nearest
if (endDate >= actualStartDate && endDate.DayOfWeek != weekendEnd)
{
var d = endDate;
do {
if (d.DayOfWeek == weekendEnd || d < actualStartDate)
{
actualEndDate = d;
break;
}
if (!weekendDays.Contains(d.DayOfWeek))
{
trailingDays++;
}
d = d.AddDays(-1);
} while(true);
}
// Calculate the inclusive number of days between the actualStartDate and the actualEndDate
var coreDays = (actualEndDate - actualStartDate).Days + 1;
var noWeeks = coreDays / daysInWeek;
// add together leading, core and trailing days
workingDays += noWeeks * workingDaysInWeek;
workingDays += leadingDays;
workingDays += trailingDays;
// Finally remove any holidays that fall within the range.
if (holidays != null)
{
workingDays -= holidays.Count(h => h >= startDate && (h <= endDate));
}
return workingDays;
}
चूंकि मैं टिप्पणी नहीं कर सकता। स्वीकृत समाधान के साथ एक और मुद्दा है जहां बैंक की छुट्टियां सप्ताहांत में स्थित होने पर भी घटा दी जाती हैं। यह देखते हुए कि कैसे अन्य इनपुट की जाँच की जाती है, यह केवल फिटिंग है कि यह भी है।
इसलिए, इस प्रकार होना चाहिए:
// subtract the number of bank holidays during the time interval
foreach (DateTime bankHoliday in bankHolidays)
{
DateTime bh = bankHoliday.Date;
// Do not subtract bank holidays when they fall in the weekend to avoid double subtraction
if (bh.DayOfWeek == DayOfWeek.Saturday || bh.DayOfWeek == DayOfWeek.Sunday)
continue;
if (firstDay <= bh && bh <= lastDay)
--businessDays;
}
यहां एक दृष्टिकोण है यदि आप एमवीसी का उपयोग कर रहे हैं। मैंने राष्ट्रीय छुट्टियों या किसी भी उत्सव के दिनों की गणना की है ताकि इसे छुट्टियों से बाहर लाने से रोका जा सके जिसे आपको एक बनाने की आवश्यकता होगी।
foreach (DateTime day in EachDay(model))
{
bool key = false;
foreach (LeaveModel ln in holidaycalendar)
{
if (day.Date == ln.Date && day.DayOfWeek != DayOfWeek.Saturday && day.DayOfWeek != DayOfWeek.Sunday)
{
key = true; break;
}
}
if (day.DayOfWeek == DayOfWeek.Saturday || day.DayOfWeek == DayOfWeek.Sunday)
{
key = true;
}
if (key != true)
{
leavecount++;
}
}
लीमोडेल यहां एक सूची है
यहाँ एक सहायक कार्य है जो मैंने उस कार्य के लिए लिखा था।
यह out
पैरामीटर के माध्यम से सप्ताहांत की गिनती भी लौटाता है ।
यदि आप चाहें तो अलग-अलग सप्ताहांत दिनों का उपयोग करने वाले देशों के लिए "सप्ताहांत" दिनों को अनुकूलित कर सकते हैं या छुट्टियों को weekendDays[]
वैकल्पिक पैरामीटर को शामिल कर सकते हैं :
public static int GetNetworkDays(DateTime startDate, DateTime endDate,out int totalWeekenDays, DayOfWeek[] weekendDays = null)
{
if (startDate >= endDate)
{
throw new Exception("start date can not be greater then or equel to end date");
}
DayOfWeek[] weekends = new DayOfWeek[] { DayOfWeek.Sunday, DayOfWeek.Saturday };
if (weekendDays != null)
{
weekends = weekendDays;
}
var totaldays = (endDate - startDate).TotalDays + 1; // add one to include the first day to
var counter = 0;
var workdaysCounter = 0;
var weekendsCounter = 0;
for (int i = 0; i < totaldays; i++)
{
if (weekends.Contains(startDate.AddDays(counter).DayOfWeek))
{
weekendsCounter++;
}
else
{
workdaysCounter++;
}
counter++;
}
totalWeekenDays = weekendsCounter;
return workdaysCounter;
}
मैं निम्नलिखित समाधान के साथ आया था
var dateStart = new DateTime(2019,01,10);
var dateEnd = new DateTime(2019,01,31);
var timeBetween = (dateEnd - dateStart).TotalDays + 1;
int numberOf7DayWeeks = (int)(timeBetween / 7);
int numberOfWeekendDays = numberOf7DayWeeks * 2;
int workingDays =(int)( timeBetween - numberOfWeekendDays);
if(dateStart.DayOfWeek == DayOfWeek.Saturday || dateEnd.DayOfWeek == DayOfWeek.Sunday){
workingDays -=2;
}
if(dateStart.DayOfWeek == DayOfWeek.Sunday || dateEnd.DayOfWeek == DayOfWeek.Saturday){
workingDays -=1;
}
आपको बस समय सीमा में प्रत्येक दिन के माध्यम से पुनरावृत्त करना होगा और काउंटर से एक दिन घटाना होगा अगर इसका शनिवार या रविवार हो।
private float SubtractWeekend(DateTime start, DateTime end) {
float totaldays = (end.Date - start.Date).Days;
var iterationVal = totalDays;
for (int i = 0; i <= iterationVal; i++) {
int dayVal = (int)start.Date.AddDays(i).DayOfWeek;
if(dayVal == 6 || dayVal == 0) {
// saturday or sunday
totalDays--;
}
}
return totalDays;
}
public static int CalculateBusinessDaysInRange(this DateTime startDate, DateTime endDate, params DateTime[] holidayDates)
{
endDate = endDate.Date;
if(startDate > endDate)
throw new ArgumentException("The end date can not be before the start date!", nameof(endDate));
int accumulator = 0;
DateTime itterator = startDate.Date;
do
{
if(itterator.DayOfWeek != DayOfWeek.Saturday && itterator.DayOfWeek != DayOfWeek.Sunday && !holidayDates.Any(hol => hol.Date == itterator))
{ accumulator++; }
}
while((itterator = itterator.AddDays(1)).Date <= endDate);
return accumulator
}
मैं केवल यह पोस्ट कर रहा हूं क्योंकि सभी उत्कृष्ट उत्तरों के बावजूद, गणित में से कोई भी मेरे लिए समझ में नहीं आया। यह निश्चित रूप से एक KISS विधि है कि काम करते हैं और काफी पोषणीय होना चाहिए। यदि आप 2-3 महीने से अधिक की सीमा की गणना कर रहे हैं तो यह सबसे प्रभावी तरीका नहीं होगा। हम बस यह निर्धारित करते हैं कि यह शनिवार या रविवार है या तारीख किसी छुट्टी की तारीख है। यदि यह नहीं है, तो हम एक व्यावसायिक दिन जोड़ते हैं। अगर है तो सब ठीक है।
मुझे यकीन है कि यह LINQ के साथ और भी सरल हो सकता है, लेकिन इस तरह से समझना बहुत आसान है।
व्यावसायिक दिनों की गणना के लिए एक और दृष्टिकोण, छुट्टियों पर विचार नहीं करना, लेकिन दिन के समय को ध्यान में रखते हुए दिन की एक आंशिक राशि लौटाना:
public static double GetBusinessDays(DateTime startD, DateTime endD)
{
while (IsWeekend(startD))
startD = startD.Date.AddDays(1);
while (IsWeekend(endD))
endD = endD.Date.AddDays(-1);
var bussDays = (endD - startD).TotalDays -
(2 * ((int)(endD - startD).TotalDays / 7)) -
(startD.DayOfWeek > endD.DayOfWeek ? 2 : 0);
return bussDays;
}
public static bool IsWeekend(DateTime d)
{
return d.DayOfWeek == DayOfWeek.Saturday || d.DayOfWeek == DayOfWeek.Sunday;
}
आप इसे यहां देख सकते हैं: https://rextester.com/ASHRS53997
यह एक सामान्य समाधान है।
startdayvalue प्रारंभ दिनांक की दिन संख्या है।
सप्ताहांत का दिन सप्ताह के अंत का दिन अंक है।
दिन संख्या - MON - 1, TUE - 2, ... SAT - 6, SUN -7।
अंतर दो तिथियों के बीच अंतर है ।।
उदाहरण: प्रारंभ तिथि: 4 अप्रैल, 2013, अंतिम तिथि: 14 अप्रैल, 2013
अंतर: १०, दिन का आरंभ: ४, सप्ताहांत का दिन: is: (अगर सूरते आपके लिए सप्ताहांत है।)
यह आपको छुट्टियों की संख्या देगा।
कार्य दिवस नहीं = (अंतर + 1) - Holiday1
if (startdayvalue > weekendday_1)
{
if (difference > ((7 - startdayvalue) + weekendday_1))
{
holiday1 = (difference - ((7 - startdayvalue) + weekendday_1)) / 7;
holiday1 = holiday1 + 1;
}
else
{
holiday1 = 0;
}
}
else if (startdayvalue < weekendday_1)
{
if (difference > (weekendday_1 - startdayvalue))
{
holiday1 = (difference - (weekendday_1 - startdayvalue)) / 7;
holiday1 = holiday1 + 1;
}
else if (difference == (weekendday_1 - startdayvalue))
{
holiday1 = 1;
}
else
{
holiday1 = 0;
}
}
else
{
holiday1 = difference / 7;
holiday1 = holiday1 + 1;
}