Interesting issue I'm facing and I just can't come up with an algorim to calculate.
Basically, what I want is to calculate a DateTime based on DateTime.Now.AddMinutes() but the Adding of minutes should take into consideration Working Hours and weekends.
In other words, if the time is currently 16:50 and i add 20 minutes, the method should return a DateTime for tomorrow morning at 08:10 (if tomorrow is not a weekend day).
I've started with some logic, but it's not complete. Does anyone have a sample which can save me a few hours of coding? This is what i've got so far:
public DateTime CalculateSLAFromNow(int minutes)
{
DateTime now = DateTime.Now;
TimeSpan slatimeaddedon = CalculateToNextWeekDay(DateTime.Now);
TimeSpan finalMinutesAddedon = slatimeaddedon.Add(new TimeSpan(0, minutes, 0));
DateTime SLATime = DateTime.Now.AddMinutes(slatimeaddedon.TotalMinutes);
return SLATime;
}
private TimeSpan CalculateToNextWeekDay(DateTime dt)
{
//Calculate.
}
public static DateTime CalculateSLAFromNow(int minutes)
{
double days = (double)minutes / 540;
DateTime now = DateTime.Now;
DateTime later = now;
while (days >= 1)
{
later = later.AddDays(1);
if (later.DayOfWeek == DayOfWeek.Saturday)
{
later = later.AddDays(2);
}
days--;
}
days = days * 540;
later = later.AddMinutes(days);
if (later.Hour > 17)
{
later = later.AddHours(15);
}
if (later.DayOfWeek == DayOfWeek.Saturday)
{
later = later.AddDays(2);
}
else if(later.DayOfWeek == DayOfWeek.Sunday)
{
later = later.AddDays(1);
}
return later;
}
There now it accounts for any number of minutes added (not the prettiest code, but it works)
Ok. Friend of mine wrote the following which works 100%. Thanks J for this. Herewith the complete solution:
private static DateTime DoCalculation(DateTime startDate, int minutes)
{
if (startDate.DayOfWeek == DayOfWeek.Sunday)
{
// if the input date is a sunday, set the actual SLA start date to the following monday morning 7:00AM
startDate = startDate.AddHours(24);
startDate = new DateTime(startDate.Year, startDate.Month, startDate.Day, 7, 0, 0);
}
else if (startDate.DayOfWeek == DayOfWeek.Saturday)
{
// if the input date is a saturday, set the actual SLA start date to the following monday morning 7:00AM
startDate = startDate.AddHours(48);
startDate = new DateTime(startDate.Year, startDate.Month, startDate.Day, 7, 0, 0);
}
DateTime resultDate = startDate;
for (int i = 0; i < minutes; i++)
{
resultDate = resultDate.AddMinutes(1);
// it is 5PM and time to go home
if (resultDate.Hour >= 17)
{
// if tomorrow is saturday
if (resultDate.AddDays(1).DayOfWeek == DayOfWeek.Saturday)
{
//add 48 hours to get us through the whole weekend
resultDate = resultDate.AddHours(48);
}
// add 14 hours to get us to next morning
resultDate = resultDate.AddHours(14);
}
}
return resultDate;
}
Related
I have been looking at Microsoft's documents and many stack overflow posts but none seem to answer my question. I want to know the simplest and easiest way to get an accurate week number for the current date in c#. I am pretty new to c# so please try and keep it simple. I have tried using:
int week = DateTime.Now.DayOfYear/7;
Console.WriteLine(week)
but on Monday (when I would like it to move onto the next week) it would show as the previous week.
Eg: If the date was 21/12/2020 it would say the current week is the 50th, which is 2 weeks off. Then on 22/12/2020 it would say it is the 51st week, which is 1 week off.
Please Help & Thanks in advance.
This is probably what you are looking for:
DateTime dt = new DateTime(2020, 12, 21);
Calendar cal = new CultureInfo("en-US").Calendar;
int week = cal.GetWeekOfYear(dt, CalendarWeekRule.FirstDay, DayOfWeek.Monday);
Console.WriteLine(week);
You can change the CalendarWeekRule parameter to change the definition of the first week of the year:
FirstDay means that first week of the year can have any length. For example if the first day of the year was Sunday, it will be counted as week and the following Monday will be counted as part of second week.
FirstFourDayWeek means that the first week will be counted only if it mainly in this year. For example if the first day of the year will be Thursday the week will be counted, but if the year starts with Friday, the first week won't be counted.
FirstFullWeek means that the first week that will be counted will be the first full week of the year.
I have looked at this as well when I was writing an application in LotusNotes. From what I have found, the first week of the year must contain a Thursday. If you assume that Sunday is the last day of the week, then the lowest date for Sunday has to be the 4th. With this is mind (and I am very new to C# and all the intricacies) I wrote this code which will give you the week number of any given date and also the number of weeks for this year and the previous. #
public class DateCalculations
{
private readonly DateTime _weekDate;
private DateTime ThisSunday => GetSundayDate(_weekDate);
private DateTime FirstDay_ThisYear => DateTime.Parse($"01/01/{ ThisSunday.Year }");
private DateTime FirstDay_LastYear => DateTime.Parse($"01/01/{ ThisSunday.Year - 1 }");
private DateTime FirstDay_NextYear => DateTime.Parse($"01/01/{ ThisSunday.Year + 1 }");
private DateTime FirstSunday_ThisYear => GetSundayDate_WeekOne(FirstDay_ThisYear);
private DateTime FirstSunday_LastYear => GetSundayDate_WeekOne(FirstDay_LastYear);
private DateTime FirstSunday_NextYear => GetSundayDate_WeekOne(FirstDay_NextYear);
public DateCalculations(string weekDate)
{
if (DateTime.TryParse(weekDate, out _weekDate))
{
return;
}
else
{
throw new Exception("Incorrect date has been supplied");
}
}
private bool IsDateInFirstWeek(DateTime suppliedDate)
{
var output = false;
// First week must contain a Thursday, so lowest Sunday date possible is the 4th
if (suppliedDate.Day >= 4)
{
output = true;
}
return output;
}
private DateTime GetSundayDate(DateTime suppliedDate)
{
var checkDay = suppliedDate;
//Check if the day of the supplied date is a Sunday
while (checkDay.DayOfWeek != DayOfWeek.Sunday)
{
checkDay = checkDay.AddDays(1);
}
return checkDay;
}
private DateTime GetSundayDate_WeekOne(DateTime suppliedDate)
{
var checkDay = GetSundayDate(suppliedDate);
if (IsDateInFirstWeek(checkDay) == false)
{
checkDay = checkDay.AddDays(7);
}
return checkDay;
}
public int WeekNumber()
{
var output = 0;
if (ThisSunday == FirstSunday_ThisYear)
{
output = 1;
}
else if(ThisSunday > FirstSunday_ThisYear)
{
TimeSpan daysBetween = ThisSunday - FirstSunday_ThisYear;
output = (daysBetween.Days/7) + 1;
}
else
{
TimeSpan daysBetween = ThisSunday - FirstSunday_LastYear;
output = (daysBetween.Days / 7) + 1;
}
return output;
}
public int TotalWeeksThisYear()
{
TimeSpan daysBetween = FirstSunday_NextYear - FirstSunday_ThisYear;
return (daysBetween.Days / 7);
}
public int TotalWeeksLastYear()
{
TimeSpan daysBetween = FirstSunday_ThisYear - FirstSunday_LastYear;
return (daysBetween.Days / 7);
}
}
My console was used to test
class Program
{
static void Main()
{
var test = new DateCalculations("2021-01-03");
var weekNumber = test.WeekNumber();
var totalWeeks = test.TotalWeeksThisYear();
var pastWeeks = test.TotalWeeksLastYear();
Console.ReadLine();
}
}
The date format can be any string representation of a date (English or American)
Hope this helps. It may need refactoring though :)
Built on top of this answer: by #bunny4
But not everyone is located in the US or might have to support several cultures.
Use this solution to support a cultural defined week rule and first-Day rule.. e.g. Denmark has "FirstFourDayWeek" rule for weeks and "Monday" as first day of the week.
//for now, take the the current executing thread's Culture
var cultureInfo = Thread.CurrentThread.CurrentCulture;
//let's pick a date
DateTime dt = new DateTime(2020, 12, 21);
DayOfWeek firstDay = cultureInfo.DateTimeFormat.FirstDayOfWeek;
CalendarWeekRule weekRule = cultureInfo.DateTimeFormat.CalendarWeekRule;
Calendar cal = cultureInfo.Calendar;
int week = cal.GetWeekOfYear(dt, weekRule, firstDay);
This question already has answers here:
AddBusinessDays and GetBusinessDays
(17 answers)
Closed 3 years ago.
I am trying to calculate a finishing date when adding a duration to a start date, but skipping weekends and holidays:
DateTime start = DateTime.Now;
TimeSpan duration = TimeSpan.FromHours(100);
List<DateTime> = //List of holidays
DateTime end = ?
For example if it is 11pm on a Friday and I add 2 hours, it would end on 1am Monday morning.
Is there a neat way of doing this?
I have a temporary fix which increments the time by an hour and checks the day of the week, but it is very inefficient.
Original Idea (untested):
public static DateTime calEndDate(DateTime start, TimeSpan duration, List<DateTime> holidays)
{
var startDay = start.Day;
var i = 0;
var t = 0;
while (TimeSpan.FromHours(t) < duration)
{
var date = start.Add(TimeSpan.FromHours(i));
if (date.DayOfWeek.ToString() != "Saturday" && date.DayOfWeek.ToString() != "Sunday") //and something like !holidays.contains(start)
{
t++;
}
i++;
}
return start.Add(TimeSpan.FromHours(t));
}
}
However is needs to run over 100 times for different start dates/durations on one asp.net page load. I don't know how to benchmark it, but it doesn't seem like an elegant solution?
Here's an algorithm I'd try.
I'm on my phone, and I'll get it wrong, but you should see the logic...
var end = start;
var timeToMidnight = start.Date.AddDays(1) -start;
if ( duration < timeToMidnight ) return start + duration;
end = endMoment + timeToMidnight;
duration = duration - timeToMidnight;
//Helper method
bool IsLeisure(Datetime dt) => (dt.DayOfWeek == DayOfWeek.Saturday) || (dt.DayOfWeek == DayOfWeek.Sunday) || holidays.Any( h => h.Date == dt.Date);
//We're at the first tick of the new day. Let's move to a work day, if needed.
while(IsLeisure(end)) { end = end.AddDays(1); };
//Now let's process full days of 'duration'
while(duration >= TimeSpan.FromDays(1) ) {
end = end.AddDays(1);
if(!IsLeisure(end)) duration = duration - TimeSpan.FromDays(1);
}
//Finally, add the reminder
end = end + duration;
Note: you haven't specified the logic for when start moment is a weekend or a holiday.
Yes there is :
DateTime currentT = DateTime.Now;
DateTime _time_ = currentTime.AddHours(10);
Simple and neat.
I have to add 15 minutes to the current time and set it to a DateTime object in C#. If my current time is say 11:50 PM, and 15 minutes is added, the hour part becomes 24 and is causing the following error: "Hour, Minute, and Second parameters describe an un-representable DateTime."
public static DateTime NewTime(this DateTime dateTime)
{
int hour = dateTime.Hour;
int minute = dateTime.Minute;
if (minute > 0)
{
minute = dateTime.Minute + (15);
if (minute >= 60)
{
hour = hour + 1;
minute = 0;
}
}
return new DateTime(dateTime.Year, dateTime.Month,
dateTime.Day, hour, minute, 0);
}
Thanks
Your logic does not make sense, you are only adding minutes if the minutes are greater than 0 so what happens if they are 0?
To add time use the methods built into the type definition, no need to reinvent the wheel. Example:
public static DateTime Add15Minutes(this DateTime dateTime)
{
return dateTime.AddMinutes(15);
}
You are checking for an overflow on the minute attribute, but not the hour attribute. You could check for an overflow on the hour attribute like this:
public static DateTime NewTime(this DateTime dateTime)
{
int hour = dateTime.Hour;
int minute = dateTime.Minute;
var day = dateTime.Day;
if (minute > 0)
{
minute = dateTime.Minute + (15);
if (minute >= 60)
{
hour = hour + 1;
minute = 0;
}
}
if (hour > 24) {
day += 1;
}
return new DateTime(dateTime.Year, dateTime.Month,
day, hour, minute, 0);
}
However, you will also run into problems with the overflow of days in a month, which is even more complicated to handle. Instead, just use the built in Add function:
public static DateTime NewTime(this DateTime dateTime)
{
return new dateTime.AddMinutes(15);
}
I think you are overthinking this maybe? DateTime already provides many support methods and this will probably do what you need without the need to create an extension method:
var myValue = new DateTime(2017,3,14,23,50,0);
var result = myValue.AddMinutes(15);
I am trying to create an if statement based on the dropdown created below. That determines whether the Time from is before or after Time To. According to the results, show validation.
For Example: Time From 4:00 and Time To 4:30. Should be acceptable.
However if Time From 4:00 and Time To 3:30. This should not be acceptable.
Any ideas?
private void BindTime()
{
// Set the start time (00:00 means 12:00 AM)
DateTime StartTime = DateTime.ParseExact("00:00", "HH:mm", null);
// Set the end time (23:55 means 11:55 PM)
DateTime EndTime = DateTime.ParseExact("23:55", "HH:mm", null);
//Set 15 minutes interval
TimeSpan Interval = new TimeSpan(0, 15, 0);
//To set 1 hour interval
//TimeSpan Interval = new TimeSpan(1, 0, 0);
ddlTimeFrom.Items.Clear();
ddlTimeTo.Items.Clear();
while (StartTime <= EndTime)
{
ddlTimeFrom.Items.Add(StartTime.ToShortTimeString());
ddlTimeTo.Items.Add(StartTime.ToShortTimeString());
StartTime = StartTime.Add(Interval);
}
ddlTimeFrom.Items.Insert(0, new ListItem(" Select ", "0"));
ddlTimeTo.Items.Insert(0, new ListItem(" Select ", "0"));
}
When you want to validate, use this function:
private bool IsSelectionValid()
{
DateTime fromTime;
DateTime toTime;
if(!DateTime.TryParse(ddlTimeFrom.SelectedValue, out fromTime) ||
!DateTime.TryParse(ddlTimeTo.SelectedValue, out toTime))
{
return false;
}
return fromTime < toTime;
}
IsSelectionValid would give return false if fromTime is not less than toTime.
I need to find the difference between two dates and show the results
in year,month, day and hour format for e.g 1 year 2 months 6 days and 4 hour.
How can i do this. Day and hour is very simple. but year and month is giving me a hard time.
I need the result to be 100% accurate...we can't assume 30 days per month or 356 per year.
please help Thanks.
The best way to get accurate number of Years, Months and actually also days (because Timespan Days and TotalDays are number of days from between two dates) is to use the AddYears, AddMonths and AddDays method respectively.
I'll create a Class here named DateDiff that will compute the number of Years, Months and Days between two dates. However, I will give you only the code (and algo) for computing Years difference because if you know the Years you will know also how to do the Months and the Days. And of course so that you yourself has something to work on also ;-)
Here's the code:
DateDiff Class:
class DateDiff
{
public DateDiff(DateTime startDate, DateTime endDate)
{
GetYears(startDate, endDate); // Get the Number of Years Difference between two dates
GetMonths(startDate.AddYears(YearsDiff), endDate); // Getting the Number of Months Difference but using the Years difference earlier
GetDays(startDate.AddYears(YearsDiff).AddMonths(MonthsDiff), endDate); // Getting the Number of Days Difference but using Years and Months difference earlier
}
void GetYears(DateTime startDate, DateTime endDate)
{
int Years = 0;
// Traverse until start date parameter is beyond the end date parameter
while (endDate.CompareTo(startDate.AddYears(++Years))>=0) {}
YearsDiff = --Years; // Deduct the extra 1 Year and save to YearsDiff property
}
void GetMonths(DateTime startDate, DateTime endDate)
{
// Provide your own code here
}
void GetDays(DateTime startDate, DateTime endDate)
{
// Provided your own code here
}
public int YearsDiff { get; set; }
public int MonthsDiff { get; set; }
public int DaysDiff { get; set; }
}
You could test the code from the Main like this:
Test the Code:
DateTime date1 = new DateTime(2012, 3, 1, 8, 0, 0);
DateTime date2 = new DateTime(2013, 11, 4, 8, 0, 0);
DateDiff dateDifference = new DateDiff(date1, date2);
Console.WriteLine("Years = {0}, Months = {1}, Days = {2}", dateDifference.DiffYears, dateDifference.DiffMonths, dateDifference.DiffDays);
Look into DateTime: http://msdn.microsoft.com/en-us/library/system.datetime(v=vs.110).aspx
You can do things like
new DateTime(10,14,2012) - new DateTime(10,12,2012) ect..
var timeSpan = dateTime2 - dateTime1;
var years = timeSpan.Days / 365;
var months = (timeSpan.Days - years * 365)/30;
var days = timeSpan.Days - years * 365 - months * 30;
// and so on
class Program
{
static void Main()
{
DateTime oldDate = new DateTime(2014,1,1);
DateTime newDate = DateTime.Now;
TimeSpan dif = newDate - oldDate;
int leapdays = GetLeapDays(oldDate, newDate);
var years = (dif.Days-leapdays) / 365;
int otherdays = GetAnOtherDays(oldDate, newDate , years);
int months = (int)((dif.Days - (leapdays + otherdays)- (years * 365)) / 30);
int days = (int)(dif.Days - years * 365 - months * 30) - (leapdays + otherdays);
Console.WriteLine("Edad es {0} años, {1} meses, {2} días", years, months, days) ;
Console.ReadLine();
}
public static int GetAnOtherDays(DateTime oldDate, DateTime newDate, int years) {
int days = 0;
oldDate = oldDate.AddYears(years);
DateTime oldDate1 = oldDate.AddMonths(1);
while ((oldDate1.Month <= newDate.Month && oldDate1.Year<=newDate.Year) ||
(oldDate1.Month>newDate.Month && oldDate1.Year<newDate.Year)) {
days += ((TimeSpan)(oldDate1 - oldDate)).Days - 30;
oldDate = oldDate.AddMonths(1);
oldDate1 = oldDate.AddMonths(1);
}
return days;
}
public static int GetLeapDays(DateTime oldDate, DateTime newDate)
{
int days = 0;
while (oldDate.Year < newDate.Year) {
if (DateTime.IsLeapYear(oldDate.Year)) days += 1;
oldDate = oldDate.AddYears(1);
}
return days;
}
}