Exclude Holidays Between two days - c#

Hi everybody i'm working a project about calculate specific working days.
My conditions are : Saturday is not holiday, it is working day.
I wrote this code everyting is okey skipped Sundays only , but i want to skip if contains a holiday date.
Problem : skipping Sunday but not skipping passing holiday list values.
Future Date Calculate function :
public DateTime CalculateFutureDate(DateTime fromDate, int numberofWorkDays,
List<DateTime> holidays)
{
var futureDate = fromDate;
for (var i = 0; i < numberofWorkDays; i++)
{
if (
futureDate.DayOfWeek == DayOfWeek.Sunday
|| (holidays != null && holidays.Contains(futureDate)))
{
futureDate = futureDate.AddDays(1);
numberofWorkDays++;
}
else
{
futureDate = futureDate.AddDays(1);
}
}
while (
futureDate.DayOfWeek == DayOfWeek.Sunday
|| (holidays != null && holidays.Contains(futureDate)))
{
futureDate = futureDate.AddDays(1);
}
return futureDate;
}
Main function:
List<DateTime> holidayslist = new List<DateTime>();
holidayslist.Add(new DateTime(2016, 09, 7));
holidayslist.Add(new DateTime(2016, 09, 8));
holidayslist.Add(new DateTime(2016, 09, 9));
DateTime izinbaslangic = Convert.ToDateTime(dtpİzinBaslangicTarihi.Value, System.Globalization.CultureInfo.CreateSpecificCulture("tr-TR").DateTimeFormat);
dtpİzinBitisTarihi.Value = CalculateFutureDate(izinbaslangic, Int32.Parse(tbİzinGunu.Text), holidayslist);
Inputs : izinbaslangic -> datetimepicker value and workingdays -> tbizingunu value
Expecting Outputs : exclude holiday and weekends show in another datetimepicker new date.
Output : Only skipping Weekends.Not skipping holidays.
Expecting Output Image : enter image description here

I would rewrite your code in the following way
public DateTime CalculateFutureDate(DateTime fromDate, int numberofWorkDays,
List<DateTime> holidays)
{
var futureDate = fromDate;
while (numberofWorkDays != 0)
{
if (!isHoliday(futureDate, holidays))
numberofWorkDays--;
futureDate = futureDate.AddDays(1);
}
while (isHoliday(futureDate, holidays))
futureDate = futureDate.AddDays(1);
return futureDate;
}
bool isHoliday(DateTime testDate, List<DateTime>holidays)
{
return (testDate.DayOfWeek == DayOfWeek.Sunday
|| (holidays != null && holidays.Contains(testDate.Date)));
}
The idea is simply to create a loop until the number of working days required is reduced to zero. Also isolating the logic to test for an holiday will help a lot in a better understanding of the code and avoid a dangerous duplication of the same logic
List<DateTime> holidayslist = new List<DateTime>();
holidayslist.Add(new DateTime(2016, 09, 7));
holidayslist.Add(new DateTime(2016, 09, 8));
holidayslist.Add(new DateTime(2016, 09, 9));
DateTime start = new DateTime(2016,9,7);
DateTime ending = CalculateFutureDate(start, 1, holidayslist);
Console.WriteLine(ending.ToString()); // 12/09/2016 00:00:00

Related

iterating between dates, hours and minutes

I am trying to iterate between 2 dates received as inputs and print every 5 minutes (during working hours)
Seems like I am getting to an endless and can get my app stop at endTime
DateTime startDate = new DateTime(2018, 1, 1);
DateTime endDate = new DateTime(2018, 3, 1);
// day in month
for (DateTime date = startDate; date < endDate; date = date.AddDays(1))
{
if (date.DayOfWeek == DayOfWeek.Friday || date.DayOfWeek == DayOfWeek.Saturday)
continue;
//iterate every hour
for (var hour = date; hour < hour.AddDays(1); hour = hour.AddHours(1))
{
if (hour.Hour < 8 || hour.Hour > 17)
continue;
//iterate every minute
for (var min = date; min <= min.AddDays(1); min = min.AddMinutes(5))
{
Console.WriteLine(min);
}
}
}
Maybe you're overcomplicating; take a look into this:
var startDate = new DateTime(2018, 1, 1);
var endDate = new DateTime(2018, 3, 1);
while ((startDate = startDate.AddMinutes(5)) < endDate)
{
if (startDate.Hour < 8 || startDate.Hour > 17 ||
startDate.DayOfWeek == DayOfWeek.Saturday ||
startDate.DayOfWeek == DayOfWeek.Sunday)
continue;
Console.WriteLine("{0:ddd, MMM dd, yyyy HH:mm}", startDate);
}
You just need a loop, incrementing by 5 minutes until the endDate is met; inside the loop you skip all values you don't want (weekends and non-business hours).
In this code I'm reusing the startDate as work variable, but you definitely could create a new one and make things clearer.

Week difference between 2 dates in C#

I'm trying to make a function in C# that returns the week difference between two dates. Its goal is to provide the same result of:
select datediff(ww,'2018-04-13','2018-04-16') as diff
In the example above there is only 3 days between these dates, but they are in different weeks, so the result should be 1.
I've tried to use .TotalDays but it's not working properly. I also tried .GetWeekOfYear but it won't return correctly when the year of the dates are different. I've seem many questions here on StackOverflow and on other forums and so far none of them match my case. This is the function I'm trying to far:
public static int GetWeekDiff(DateTime dtStart, DateTime dtEnd) {
// Doesn't work
var val = ((dtEnd - dtStart).TotalDays / 7);
val = Math.Ceiling(val);
return Convert.ToInt32(val);
// Doesn't work well between years
DateTimeFormatInfo dinfo = DateTimeFormatInfo.CurrentInfo;
var x = dinfo.Calendar.GetWeekOfYear(dtStart, CalendarWeekRule.FirstFullWeek, DayOfWeek.Monday);
var y = dinfo.Calendar.GetWeekOfYear(dtEnd, CalendarWeekRule.FirstFullWeek, DayOfWeek.Monday);
return y - x;
}
In the first part of my function, I tried what is described in this post. It didn't work
Can you help me?
Thanks in advance.
First figure how many days there are between the two dates. Divide the number of days by 7 to get full weeks.
Now figure out if there's an extra week to be counted by finding taking the number of days modulus 7 to get any remaining days. If the first date plus remaining days falls in a different week, add an extra week on to the count.
void Main()
{
var first = new DateTime(2018, 04, 13);
var second = new DateTime(2018, 04, 16);
Console.WriteLine(weekDiff(first, second));
}
public int weekDiff(DateTime d1, DateTime d2, DayOfWeek startOfWeek = DayOfWeek.Monday)
{
var diff = d2.Subtract(d1);
var weeks = (int)diff.Days / 7;
// need to check if there's an extra week to count
var remainingDays = diff.Days % 7;
var cal = CultureInfo.InvariantCulture.Calendar;
var d1WeekNo = cal.GetWeekOfYear(d1, CalendarWeekRule.FirstFullWeek, startOfWeek);
var d1PlusRemainingWeekNo = cal.GetWeekOfYear(d1.AddDays(remainingDays), CalendarWeekRule.FirstFullWeek, startOfWeek);
if (d1WeekNo != d1PlusRemainingWeekNo)
weeks++;
return weeks;
}
static void Main(string[] args)
{
DateTime date1 = new DateTime(2018, 04, 18);
DateTime date2 = new DateTime(2018, 04, 19);
System.Console.WriteLine((GetDiff(new DateTime(2018, 04, 18), new DateTime(2018, 04, 18)))); // 0
System.Console.WriteLine((GetDiff(new DateTime(2018, 04, 22), new DateTime(2018, 04, 23)))); // 1
System.Console.WriteLine((GetDiff(new DateTime(2018, 04, 16), new DateTime(2018, 04, 22)))); // 0
System.Console.WriteLine((GetDiff(new DateTime(2018, 04, 18), new DateTime(2018, 05, 03)))); // 2
}
private static int GetDiff(DateTime date1, DateTime date2)
{
date1 = SetDayToMonday(date1);
date2 = SetDayToMonday(date2);
return (int)((date2 - date1).TotalDays / 7);
}
private static DateTime SetDayToMonday(DateTime date)
{
var weekDay = date.DayOfWeek;
if (weekDay == DayOfWeek.Sunday)
return date.AddDays(-6);
else
return date.AddDays(-((int)weekDay-1));
}
First, set the day to the monday of the current week. Then count all full weeks(= /7 days as int). Easy as it is, it works probably across weeks and years.
See if this works. There could be more use cases that this doesn't cover, and the solution depends on how you define a week boundary (this assumes Sunday-Monday based on a comment above).
// Output:
// Weeks between 12/28/2017 and 1/10/2018: 2
// Weeks between 4/13/2018 and 4/16/2018: 1
// Weeks between 4/21/2018 and 4/22/2018: 0
// Weeks between 4/22/2018 and 4/23/2018: 1
void Main()
{
var datePairs = new List<KeyValuePair<DateTime, DateTime>>();
datePairs.Add(new KeyValuePair<DateTime, DateTime>(new DateTime(2017, 12, 28), new DateTime(2018, 1, 10)));
datePairs.Add(new KeyValuePair<DateTime, DateTime>(new DateTime(2018, 4, 13), new DateTime(2018, 4, 16)));
datePairs.Add(new KeyValuePair<DateTime, DateTime>(new DateTime(2018, 4, 21), new DateTime(2018, 4, 22)));
datePairs.Add(new KeyValuePair<DateTime, DateTime>(new DateTime(2018, 4, 22), new DateTime(2018, 4, 23)));
foreach (var datePair in datePairs)
{
var string1 = datePair.Key.ToShortDateString();
var string2 = datePair.Value.ToShortDateString();
Console.WriteLine($"Weeks between {string1} and {string2}: {GetWeekDiff(datePair.Key, datePair.Value)}");
}
}
public static int GetWeekDiff(DateTime dtStart, DateTime dtEnd)
{
var totalDays = (dtEnd - dtStart).TotalDays;
var weeks = (int)totalDays / 7;
var hasRemainder = totalDays % 7 > 0;
if (hasRemainder)
{
if (!(dtStart.DayOfWeek.Equals(DayOfWeek.Saturday) && dtEnd.DayOfWeek.Equals(DayOfWeek.Sunday)))
{
weeks++;
}
}
return weeks;
}
Maybe it can help
public static int GetIso8601WeekOfYear(DateTime time)
{
// Seriously cheat. If its Monday, Tuesday or Wednesday, then it'll
// be the same week# as whatever Thursday, Friday or Saturday are,
// and we always get those right
DayOfWeek day = CultureInfo.InvariantCulture.Calendar.GetDayOfWeek(time);
if (day >= DayOfWeek.Monday && day <= DayOfWeek.Wednesday)
{
time = time.AddDays(3);
}
// Return the week of our adjusted day
return CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(time, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
}
Get the correct week number of a given date
Can't comment yet and already used a flag on this post on something I believed to be similar. Here is another post I found that appears to align with the solution you are trying to create:
Get the number of calendar weeks between 2 dates in C#
This is my implementation to solve a similar problem, I haven't tested in thoroughly but it seems to work.
var dt1 = DateTime.Today.AddDays(-30);
var dt2 = DateTime.Today;
var noOfDays =(int) (dt2 - dt1).TotalDays;
int reminder;
var weeks = Math.DivRem(noOfDays, 7, out reminder);
weeks = reminder > 0 ? weeks + 1 : weeks;
It returns 1 week for 6 days or less gap, which is exactly what I needed.

Lambda between two dates explicit

I am in need of some wizards.
I have a table
Start End PersonID
-----------------------------------------------------
10/07/2017 00:00:00 18/07/2017 00:00:00 1
27/07/2017 00:00:00 27/07/2017 00:00:00 1
28/07/2017 00:00:00 28/07/2017 00:00:00 1
29/07/2017 00:00:00 29/07/2017 00:00:00 1
30/07/2017 00:00:00 30/07/2017 00:00:00 1
If I search for
Date Start = 11/07/2017
Date End = 12/07/2017
Using this query:
DateTime start = new DateTime(2017,07,11,0,0,0,0,0);
DateTime end = start.AddDays(1);
DateTime[] days = new DateTime[end.Subtract(start).Days];
for (int i = 0; i < end.Subtract(start).Days; i++)
{
var d = start.AddDays(i);
days[i] = d;
}
IQueryable block = tmOpen1.Calendar.Where(x => days.All(y => y >= x.start && y <= x.end)).Select(x => new { ID = x.PersonID });`
I get a positive result for ROW 1 (10/07/2017 - 18/07/2017)
However If I apply it against the remaining rows e.g. Filter
Date Start = 28/07/2017
Date End = 29/07/2017
Then obviously this will fail. How Can I get this side of the search to work.
E.g. Either
Take the first row and make it split out into individual rows
Make the Individual rows return true if a Person has several true conditions.
I hope one of the geniuses here can help.
Seems like all you really need is something like this:
DateTime start = new DateTime(2017,07,11,0,0,0,0,0);
DateTime end = start.AddDays(1);
var results = tmOpen1.Calendar
.Where(c => start <= c.end && end >= c.start)
.Select(x => new { ID = x.PersonID });
If your interval starts or ends somewhere between a start and end date from the table, than it means it is overlapping and you should included in your result.
tmOpen1.Calendar.Where(x => (startDate >= x.start && startDate <= x.end) || (endDate >= x.start && endDate <= x.end)).Select(x => new { ID = x.PersonID });
So an interval 10.07 - 27.07 should give you the first 2 rows, right?
Or is the interval supposed to be fully enclosed between 2 dates in the table?
From understanding of your question you want to know when the Date Start or Date End is within a range of dates.
You can check Date Start is within the date range or the Date End is within the date range
Example:
List<DateRange> dates = new List<DateRange>();
dates.Add(new DateRange()
{
StartDate = new DateTime(2017, 07, 10),
EndDate = new DateTime(2017, 07, 18)
});
dates.Add(new DateRange()
{
StartDate = new DateTime(2017, 07, 28),
EndDate = new DateTime(2017, 07, 28)
});
DateRange search1 = new DateRange()
{
StartDate = new DateTime(2017, 07, 11),
EndDate = new DateTime(2017, 07, 12)
};
DateRange search2 = new DateRange()
{
StartDate = new DateTime(2017, 07, 28),
EndDate = new DateTime(2017, 07, 29)
};
var result1 = dates.Where(x => search1.StartDate >= x.StartDate && search1.StartDate <= x.EndDate ||
search1.EndDate <= x.StartDate && search1.EndDate >= x.EndDate);
var result2 = dates.Where(x => search2.StartDate >= x.StartDate && search2.StartDate <= x.EndDate ||
search2.EndDate <= x.StartDate && search2.EndDate >= x.EndDate);
Simplier with the not valid time frame:
DateTime start = new DateTime(2017, 07, 11, 0, 0, 0, 0, 0);
DateTime end = start.AddDays(1);
var results = tmOpen1.Calendar.
.Where( c => ! ( c.Start > end || c.End < start) )
.Select(x => new { ID = x.PersonID } );
For DateTime start = new DateTime(2017, 07, 11, 0, 0, 0, 0, 0);
The result are:
TEST 1: 11/07/2017 00:00:00
Start:10/07/2017 00:00:00 End:18/07/2017 00:00:00 ID:1
For DateTime start = new DateTime(2017, 07, 28, 0, 0, 0, 0, 0);
The result are:
TEST 2: 28/07/2017 00:00:00
Start:28/07/2017 00:00:00 End:28/07/2017 00:00:00 ID:1
Start:29/07/2017 00:00:00 End:29/07/2017 00:00:00 ID:1
modelclassList= modelclassList.Where(x => x.gf_expdate>DateTime.Now).ToList();
to check expiry date and save back list of model class

How to find exact date range from list of date ranges by entering single date

I want to find the date range which falls in input date, following is structure
public class Duration
{
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
}
var durations = new List<Duration>();
var duration1 = new Duration()
{
StartDate = new DateTime(2017, 08, 1),
EndDate = new DateTime(2017, 08, 10)
};
durations.Add(duration1);
var duration2 = new Duration()
{
StartDate = new DateTime(2017, 08, 5),
EndDate = new DateTime(2017, 08, 10)
};
durations.Add(duration2);
var duration3 = new Duration()
{
StartDate = new DateTime(2017, 08, 5),
EndDate = new DateTime(2017, 08, 6)
};
durations.Add(duration3);
Now I want to find duration which is closest to the entered date for list of <Durations> with LINQ or for-loop
My expected result for currentDate=new DateTime(2017, 08, 7); is duration2
You first need to check if the currentDate is within the start and end dates of each range. For the ones that meet that condition, you calculate the "closeness" adding both distances. When you find one lapse(gap) smaller tan the previous, you save its index... and voilá
int lapse = Integer.MaxValue;
int counter = 0;
int index = 0;
foreach (d in durations) {
if (((d.StartDate <= currentDate) && (d.EndDate >= currentDate))) {
int newlapse = ((currentDate - d.StartDate).TotalDays + (d.EndDate - currentDate).TotalDays);
if ((newlapse < lapse)) {
lapse = newlapse;
index = counter;
}
}
counter +=1;
}
return durations(index);
If you need the middle of interval to be closest:
durations.OrderBy((d) => Math.Abs(d.EndDate.Ticks + d.StartDate.Ticks) / 2 - currentDate.Ticks).FirstOrDefault();
If you need the start of interval to be closest:
durations.OrderBy((d) => Math.Abs(d.EndDate.Ticks - currentDate.Ticks)).FirstOrDefault();
As D le mentioned above
First check if currentDate is within the start and end dates
Second select the duration with the minimal difference between start end end date
I used a nuget package called morelinq which gives nice extensions methods like MinBy:
var result = (from d in durations
where (d.StartDate <= currentDate && d.EndDate >= currentDate)
select d).MinBy(d => d.EndDate - d.StartDate);

Select Only Fourth Sunday of each month

I am stuck for sometime now, now need your help.
I want to display in a dropdown only fourth Sunday of each month, say from 1-Sep-2010 to 31-Aug-2011
I only want fourth Sunday in dropdown list, how to do it using asp.net C#
Regards
Here is an approach that uses a little LINQ and the knowledge that the fourth Sunday will occur between the 22nd and 28th of a month, inclusive.
DateTime startDate = new DateTime(2010, 9, 1);
DateTime endDate = startDate.AddYears(1).AddDays(-1);
List<DateTime> fourthSundays = new List<DateTime>();
DateTime currentDate = startDate;
while (currentDate < endDate)
{
// we know the fourth sunday will be the 22-28
DateTime fourthSunday = Enumerable.Range(22, 7).Select(day => new DateTime(currentDate.Year, currentDate.Month, day)).Single(date => date.DayOfWeek == DayOfWeek.Sunday);
fourthSundays.Add(fourthSunday);
currentDate = currentDate.AddMonths(1);
}
You can then bind that List<DateTime> to the dropdown or skip the list itself in favor of adding the items as you generate them to the dropdown, like below.
yourDropdown.Items.Add(new ListItem(fourthSunday.ToString()));
For giggles, you can do the whole thing in a LINQ statement and skip (most of) the variables.
DateTime startDate = new DateTime(2010, 9, 1);
IEnumerable<DateTime> fourthSundays =
Enumerable.Range(0, 12)
.Select(item => startDate.AddMonths(item))
.Select(currentMonth =>
Enumerable.Range(22, 7)
.Select(day => new DateTime(currentMonth.Year, currentMonth.Month, day))
.Single(date => date.DayOfWeek == DayOfWeek.Sunday)
);
Got bored so here you go. Two helper methods one retrieves the Week if it exist, and the other iterates through the months
class Program
{
static void Main(string[] args)
{
DateTime startDate = new DateTime(2010, 09, 1);
foreach(DateTime dt in EachMonth( new DateTime(2010, 09, 1), new DateTime(2011, 09, 1))){
DateTime? result = GetDayByWeekOffset(DayOfWeek.Sunday, dt, 4);
Console.WriteLine("Sunday:" + (result.HasValue?result.Value.ToString("MM-dd-yyyy"):"null"));
}
Console.ReadKey();
}
public static DateTime? GetDayByWeekOffset(DayOfWeek day, DateTime month, int weekOffSet)
{
//First day of month
DateTime firstDayOfMonth = month.AddDays((-1 * month.Day) + 1);
//
int daysOffSet;
daysOffSet= ((int)day + 7 - (int)firstDayOfMonth.DayOfWeek) % 7;
DateTime firstDay = month.AddDays(daysOffSet);
// Add the number of weeks specified
DateTime resultDate = firstDay.AddDays((weekOffSet - 1) * 7);
if (resultDate.Month != firstDayOfMonth.Month){
return null;
}else{
return resultDate;
}
}
public static IEnumerable<DateTime> EachMonth(DateTime from, DateTime thru)
{
for (var month = from.Date; month.Date <= thru.Date; month = month.AddMonths(1))
yield return month;
}
}
Anthony's answer above is nice, I like it a lot. As an alternate, here is a method which is parameterized for the day of the week and the week number (i.e. if you need other combinations, like 4th Sunday, 3rd Friday, etc.) with some comments.
Call it like this for your case:
List<DateTime> sundays = DateInstances(new DateTime(2010, 9, 1), new DateTime(2011, 8, 31), DayOfWeek.Sunday, 4);
And the method itself:
public List<DateTime> DateInstances(DateTime start, DateTime end, DayOfWeek day, int weeks)
{
if (start > end)
throw new ArgumentOutOfRangeException("end", "The start date must occur before the end date");
List<DateTime> results = new List<DateTime>();
DateTime temp = start;
while (temp < end)
{
DateTime firstWeekday = new DateTime(temp.Year, temp.Month, 1);
//increment to the given day (i.e. if we want the 4th sunday, we must find the first sunday of the month)
while (firstWeekday.DayOfWeek != day)
firstWeekday = firstWeekday.AddDays(1);
//add the number of weeks (note: we already have the first instance, so subtract 1)
firstWeekday = firstWeekday.AddDays(7 * (weeks - 1));
//make sure we haven't gone over to the next month
if (firstWeekday.Month == temp.Month)
results.Add(firstWeekday);
//let's not loop forever ;)
temp = temp.AddMonths(1);
}
return results;
}

Categories