Reputation: 5600
I am trying to add hours to a date but want the new date to exclude weekends and only be between 9.00 to 17.00.
example:
first scenario:
if my date is 23/02/2012 16:00:00.
if I add 4 hours to that my new date should be 24/02/2012 12:00:00 (which will be within working hours)
second scenario:
if my date is 24/02/2012 09:00:00 (which is a friday)
if I add 24 hours then the new date should be 27/02/2012 09:00:00 (which would be monday next week at 9am)
so far I got this but am stuck as this will not count for any date that is in past say date passed was 10/02/2012(Friday last week) :
private static void ExcludeWeekend(Datetime dt)
{
DateTime todaysDate = DateTime.Today;
DateTime dueDate = null;
if (dueDate.DayOfWeek == DayOfWeek.Friday)
{
dueDate.AddHours(48);
}
else if (dueDate.DayOfWeek == DayOfWeek.Saturday)
{
dueDate.AddHours(72);
}
}
Upvotes: 6
Views: 9305
Reputation: 327
@BlueMonkMN 's answer is great. However, I rectified a couple of issues there and now it worked perfectly for me.
Function SLARespondBy(start As DateTime, SLA As Integer) As String
Const hoursPerDay As Integer = 12
Const startHour As Integer = 7
Dim isWholeDayNeeded As Boolean = True
If start.AddMinutes(SLA).TimeOfDay = TimeSpan.FromHours(19) Then
isWholeDayNeeded = False
End If
Dim offset As TimeSpan = TimeSpan.FromMinutes(SLA)
' Don't start counting hours until start time is during working hours
If start.TimeOfDay.TotalHours > startHour + hoursPerDay Then
start = start.Date.AddDays(1).AddHours(startHour)
End If
If start.TimeOfDay.TotalHours < startHour Then
start = start.Date.AddHours(startHour)
End If
If start.DayOfWeek = DayOfWeek.Saturday Then
start = start.AddDays(2) ' Move to Monday
start = New DateTime(start.Year, start.Month, start.Day, 7, 0, 0) ' Set time to 7:00 AM
ElseIf start.DayOfWeek = DayOfWeek.Sunday Then
start = start.AddDays(1) ' Move to Monday
start = New DateTime(start.Year, start.Month, start.Day, 7, 0, 0) ' Set time to 7:00 AM
End If
' Calculate how much working time already passed on the first day
Dim firstDayOffset As TimeSpan = start.TimeOfDay.Subtract(TimeSpan.FromHours(startHour))
' Calculate number of whole days to add
Dim wholeDays As Integer = 0
If isWholeDayNeeded Then
wholeDays = CInt(Math.Truncate(offset.Add(firstDayOffset).TotalHours / hoursPerDay))
End If
' How many hours off the specified offset does this many whole days consume?
Dim wholeDaysHours As TimeSpan = TimeSpan.FromHours(wholeDays * hoursPerDay)
' Calculate the final time of day based on the number of whole days spanned and the specified offset
Dim remainder As TimeSpan = offset - wholeDaysHours
' How far into the week is the starting date?
Dim weekOffset As Integer = ((CInt(start.DayOfWeek) + 7) - CInt(DayOfWeek.Monday)) Mod 7
' How many weekends are spanned?
Dim weekends As Integer = CInt(Math.Truncate((wholeDays + weekOffset) / 5))
' Calculate the final result using all the above calculated values
Dim finalDateTime As DateTime = start.AddDays(wholeDays + weekends * 2).Add(remainder)
'
Return finalDateTime.ToString("MM/dd/yyyy h:mm tt")
End Function
Upvotes: 0
Reputation: 193
Not an elegant solution but it seems to work.
DateTime AddHoursIgnoreWeekend(DateTime startDate, int hours)
{
DateTime endDate = startDate;
for (int i = 0; i < hours; i++) {
endDate = endDate.AddHours(1);
if (endDate.DayOfWeek == DayOfWeek.Saturday || endDate.DayOfWeek == DayOfWeek.Sunday)
{
i--;
}
}
return endDate;
}
Upvotes: 0
Reputation: 25601
static DateTime AddWithinWorkingHours(DateTime start, TimeSpan offset)
{
const int hoursPerDay = 8;
const int startHour = 9;
// Don't start counting hours until start time is during working hours
if (start.TimeOfDay.TotalHours > startHour + hoursPerDay)
start = start.Date.AddDays(1).AddHours(startHour);
if (start.TimeOfDay.TotalHours < startHour)
start = start.Date.AddHours(startHour);
if (start.DayOfWeek == DayOfWeek.Saturday)
start.AddDays(2);
else if (start.DayOfWeek == DayOfWeek.Sunday)
start.AddDays(1);
// Calculate how much working time already passed on the first day
TimeSpan firstDayOffset = start.TimeOfDay.Subtract(TimeSpan.FromHours(startHour));
// Calculate number of whole days to add
int wholeDays = (int)(offset.Add(firstDayOffset).TotalHours / hoursPerDay);
// How many hours off the specified offset does this many whole days consume?
TimeSpan wholeDaysHours = TimeSpan.FromHours(wholeDays * hoursPerDay);
// Calculate the final time of day based on the number of whole days spanned and the specified offset
TimeSpan remainder = offset - wholeDaysHours;
// How far into the week is the starting date?
int weekOffset = ((int)(start.DayOfWeek + 7) - (int)DayOfWeek.Monday) % 7;
// How many weekends are spanned?
int weekends = (int)((wholeDays + weekOffset) / 5);
// Calculate the final result using all the above calculated values
return start.AddDays(wholeDays + weekends * 2).Add(remainder);
}
Upvotes: 9
Reputation:
You can use the class CalendarDateAdd from the Time Period Library for .NET:
// ----------------------------------------------------------------------
public void CalendarDateAddSample()
{
CalendarDateAdd calendarDateAdd = new CalendarDateAdd();
// use only weekdays
calendarDateAdd.AddWorkingWeekDays();
// setup working hours
calendarDateAdd.WorkingHours.Add( new HourRange( new Time( 09 ), new Time( 17 ) ) );
DateTime start = new DateTime( 2012, 2, 23 ); // start date
TimeSpan offset = new TimeSpan( 4, 0, 0 ); // 4 hours
DateTime? end = calendarDateAdd.Add( start, offset ); // end date
Console.WriteLine( "start: {0}", start );
Console.WriteLine( "offset: {0}", offset );
Console.WriteLine( "end: {0}", end );
} // CalendarDateAddSample
Upvotes: 9
Reputation: 460288
var d1 = DateTime.Now;
var ts = TimeSpan.FromHours(40);
var d2 = d1 + ts;
if(d2.DayOfWeek == DayOfWeek.Saturday) {
d2 = d2.AddDays(2);
}else if(d2.DayOfWeek == DayOfWeek.Sunday){
d2 = d2.AddDays(1);
}
If you really want to make it an extension:
var d2 = DateTime.Now.AddSkipWeekend(TimeSpan.FromHours(40));
static class DateExtensions {
public static DateTime AddSkipWeekend(this DateTime date1, TimeSpan ts){
DateTime d2 = date1 + ts;
if(d2.DayOfWeek == DayOfWeek.Saturday) {
d2 = d2.AddDays(2);
} else if(d2.DayOfWeek == DayOfWeek.Sunday) {
d2 = d2.AddDays(1);
}
return d2;
}
}
Edit: Just realized your non-working-hours requirement:
var d2 = DateTime.Now.AddSkipWeekend(TimeSpan.FromHours(50),TimeSpan.FromHours(9),TimeSpan.FromHours(17));
public static DateTime AddSkipWeekend(this DateTime date1, TimeSpan addTime, TimeSpan workStart, TimeSpan workEnd)
{
DateTime d2 = date1 + addTime;
if(d2.TimeOfDay < workStart) {
d2 = d2.Add(workStart - d2.TimeOfDay);
} else if(d2.TimeOfDay > workEnd) {
d2 = d2.Add(TimeSpan.FromHours(12) - d2.TimeOfDay);
}
if(d2.DayOfWeek == DayOfWeek.Saturday) {
d2 = d2.AddDays(2);
} else if(d2.DayOfWeek == DayOfWeek.Sunday) {
d2 = d2.AddDays(1);
}
return d2;
}
Upvotes: 2
Reputation: 217401
Try this:
public static DateTime Add(DateTime dt, TimeSpan t)
{
while (true)
{
dt = Max(dt, dt.Date.AddHours(9));
DateTime x = Min(dt + t, dt.Date.AddHours(17));
// Console.WriteLine("{0} -> {1} ({2})", dt, x, x - dt);
t -= x - dt;
dt = x;
if (t == TimeSpan.Zero) { return dt; }
do { dt = dt.Date.AddDays(1); } while (dt.IsWeekendDay());
}
}
Helper methods from here.
Example 1:
var result = Add(DateTime.Parse("23/02/2012 16:00:00"), TimeSpan.FromHours(4));
// result == {24/02/2012 12:00:00}
23/02/2012 16:00:00 -> 23/02/2012 17:00:00 (01:00:00)
24/02/2012 09:00:00 -> 24/02/2012 12:00:00 (03:00:00)
Example 2:
var result = Add(DateTime.Parse("24/02/2012 09:00:00"), TimeSpan.FromHours(24));
// result == {28/02/2012 17:00:00}
24/02/2012 09:00:00 -> 24/02/2012 17:00:00 (08:00:00)
27/02/2012 09:00:00 -> 27/02/2012 17:00:00 (08:00:00)
28/02/2012 09:00:00 -> 28/02/2012 17:00:00 (08:00:00)
Upvotes: 2