I'm struggeling a bit with an algorithm implementation.
I am having a start date and an end date and I want to list all possible timespans within that timespan with a special condition as start and end dates.
For example:
My start date is 01-01-2020 and my end date is 31-01-2020. My condition is to list all possible timespans that have at least 7 days and maximum 10 days.
So the result set would be like:
01-01-2020 -> 08-01-2020
01-01-2020 -> 09-01-2020
...
02-01-2020 -> 09-01-2020
...
24-01-2020 -> 31-01-2020
Preferable as Linq so I can enumerate.
Here's a simple implementation. It's not the most efficient, but it's easy to understand:
public static IEnumerable<(DateTime start, DateTime end)> ListTimespans(DateTime startDate, DateTime endDate, int minDays, int maxDays)
{
// Loop through all of the possible starts. The first day we can start on is startDate,
// and the last day we can start on is endDate - minDays (which gives us a span
// minDays long ending on endDate)
for (var start = startDate; start <= endDate.AddDays(-minDays); start = start.AddDays(1))
{
// For each of these starts, loop through the possible end dates. There are two
// limits to the end date: either hit the maximum number of days for a span
// (start.AddDays(maxDays)), or we hit the end date.
// Loop until whichever one comes first.
for (var end = start.AddDays(minDays); end <= Min(start.AddDays(maxDays), endDate); end = end.AddDays(1))
{
yield return (start, end);
}
}
DateTime Min(DateTime x, DateTime y) => x < y ? x : y;
}
See it in action here.
Related
I'm accepting time range from user in a 24 hr clock format.My code below works if the start time is less than End time. The following code divides the given time range with the interval.
How should I deal with a situation where Start Time is less than End Time. E.g. If Start Time is say 21:00 (9 PM) and End time is 03:00 (3 AM). Any idea how should I divide the time range where Start time is MORE than End Time?
DateTime start = DateTime.ParseExact(txtStartTime.Text.Trim(),"HH:mm", null);
DateTime end = DateTime.ParseExact(txtEndTime.Text.Trim(), "HH:mm", null);
int interval = Convert.ToInt32(txtSessionDuration.Text.Trim());
for (DateTime i = start; i < end; i = i.AddMinutes(interval))
{
//some code goes here...
}
Assuming that there is no user error and user want to get intervals, when end time is less than start time.
As DateTime contains not only time component, but date component, so we can simply add one day if end time is less than start time. You should modify you code as follows:
DateTime start = DateTime.ParseExact(txtStartTime.Text.Trim(),"HH:mm", null);
DateTime end = DateTime.ParseExact(txtEndTime.Text.Trim(), "HH:mm", null);
if (end < start)
{
end = end.AddDays(1);
}
int interval = Convert.ToInt32(txtSessionDuration.Text.Trim());
for (DateTime i = start; i < end; i = i.AddMinutes(interval))
{
//some code goes here...
}
After you have parsed DateTime from string - both start and end contains equals date component. This mean that end time is earlier than start time. But if you passing end time, that is less than start time, you actually mean, that end time is time of next day.
So, if time component of end is less than it of start you can simply add 1 day to end and you will have ability to iterate from start to end.
How should I deal with a situation where Start Time is less than End
Time?
Don't you can compare theirs .TimeOfDay properties? Like;
if(start.TimeOfDay < end.TimeOfDay)
Or instead of that, you can parse them to TimeSpan and compare directly.
You can do by
DateTime start = DateTime.ParseExact(DateTime.Now().ToString("dd/MM/yyyy") + txtStartTime.Text.Trim(),"dd/MM/yyyy HH:mm", null);
DateTime end = DateTime.ParseExact(DateTime.Now().ToString("dd/MM/yyyy") + txtEndTime.Text.Trim(), "dd/MM/yyyy HH:mm", null);
if(start.TimeOfDay < end.TimeOfDay)
{
// do stuff here
}
Use timespan:
DateTime departure = new DateTime(2010, 6, 12, 18, 32, 0);
DateTime arrival = new DateTime(2010, 6, 13, 22, 47, 0);
TimeSpan travelTime = arrival - departure;
Console.WriteLine("{0} - {1} = {2}", arrival, departure, travelTime);
// The example displays the following output:
// 6/13/2010 10:47:00 PM - 6/12/2010 6:32:00 PM = 1.04:15:00
reference: https://msdn.microsoft.com/en-us/library/system.timespan(v=vs.110).aspx
I have been trying to use an ajax CalenderExtender for my application.
I have many small operations in my app like adding duration to start date of a task to find the finish date, change duration of a task if its end date is changed (depending on its start date),etc.
But while I do all these operations I want to skip all the holidays and saturday , sundays from the calculations for eg. a task starting on 01/23/2014 with a duration of 5 days should finish on 01/29/2014 (adding 2 days for sat n sun in duration) instead of 01/27/2014. Same should be performed on other operations as well.
Is there a way to do this?
For Sundays and Saturdays, it's easy. Just check the DateTime.DayOfWeek property of your dates.
If you have an operation that will start on date start and will end on date end, you can see what dates are Saturdays or Sundays like this:
List<DateTime> satsAndSundays;
for (DateTime temp = start; temp <= end; temp.AddDays(1))
{
if (temp.DayOfWeek == DayOfWeek.Sunday ||
temp.DayOfWeek == DayOfWeek.Saturday)
{
satsAndSundays.add(temp);
}
}
And since you can know how many days there are between start and end by doing something like:
TimeSpan span = end - start;
int totalDays = (int)span.TotalDays;
// TotalDays is actually a double, I'm just discarding the non integer part.
You may fid out how many work days you have there by doing totalDays - satsAndSundays.Count.
Edit: I just read the question again. If you want a task to start on a given date, and take x work days, you can do it like this:
DateTime end = start;
for (int i = x; i >= 0;) // the third parameter of the for is empty on purpose
{
end = end.AddDays(1);
if (end.DayOfWeek != DayOfWeek.Saturday &&
end.DayOfWeek != DayOfWeek.Sunday)
{
i--;
}
}
Afther the loop, end will be x workdays after start (provided there are no holidays in between).
For holidays, though, there is no alghoritm for that in the framework. You need to fetch them from some source (a file, a database, a web service etc.). Or you could write your own program to figure them out - most holidays that are not on a fixed date do follow formulas when it comes to when they happen. Do take into account, however, that holidays may vary by culture and region. If your application is to be used throughout a country, for example, it may be quite the effort to implement city-wide holidays. Depending on your needs, it might even be better to either let the users input which days are holidays, or making your own database your app can access and use.
Try this one..
private string GetDatesOfSundays(DateTime DatMonth)
{
string sReturn = "";
int iDayOffset = DatMonth.Day - 1;
DatMonth = DatMonth.AddDays(System.Convert.ToDouble(-DatMonth.Day + 1));
DateTime DatMonth2 = DatMonth.AddMonths(1).AddDays(System.Convert.ToDouble(-1));
while (DatMonth < DatMonth2)
{
if (DatMonth.DayOfWeek == System.DayOfWeek.Sunday)
{
if (sReturn.Length > 0) sReturn += ",";
sReturn += DatMonth.ToShortDateString();
}
DatMonth = DatMonth.AddDays(1.0);
}
return sReturn;
}
These are the variables I'm using:
var start = new DateTime();
var End = new DateTime();
Help me out by validating with if condition.
If I am understanding correctly you will have to try something like
if (start.AddDays(5) == End)
DateTime.AddDays Method
You can calculate a TimeSpan between the two dates and use properties of TimeSpan to determine how far apart they are, e.g.
TimeSpan diff = new TimeSpan(End.Ticks - start.Ticks);
double daysApart = diff.TotalDays;
if (daysApart >= 5.0) // Do stuff (assumes you want at least 5 days)
if(end.Subtract(start).Days > 5)
You should familiarize yourself with the DateTime structure. For this in particular the AddDays method or depending on how you end up doing things the Subtract method.
// Setting end date to start date plus 5 days
var start = new DateTime();
var end = start.AddDays(5)
// Testing if end date is the same as start date plus 5 days
if (start.AddDays(5) == end)
{
// It true!
}
/// or like so...
if (end.subtract(start).Days >= 5)
{
// It true!
}
Try this:
TimeSpan elapsed;
elapsed = end.Subtract(start);
if (elapsed.Days > 5)
//Do stuff
http://www.dotnetperls.com/datetime
i am doing a project on cab services.in this rate is different for day and night.
in the form only journey start date and end date is selected.based on this i have to calculate the no of days and nights.
here i am confused how to calculate the no of days and night.
thanks in advance.
private List<DateTime> GetDateRange(DateTime StartingDate, DateTime EndingDate)
{
if (StartingDate > EndingDate)
{
return null;
}
List<DateTime> rv = new List<DateTime>();
DateTime tmpDate = StartingDate;
do
{
rv.Add(tmpDate);
tmpDate = tmpDate.AddDays(1);
} while (tmpDate <= EndingDate);
return rv;
}
To view this code in action, copy and paste the following code into SnippetCompiler:
DateTime StartingDate = DateTime.Parse("02/25/2007");
DateTime EndingDate = DateTime.Parse("03/06/2007");
foreach (DateTime date in GetDateRange(StartingDate,EndingDate))
{
WL(date.ToShortDateString());
}
Sample output :
2/25/2007
2/26/2007
2/27/2007
2/28/2007
3/1/2007
3/2/2007
3/3/2007
3/4/2007
3/5/2007
3/6/2007
Use the Subtract method to get the difference, which is a TimeSpan value. Example:
TimeSpan diff = SecondDate.Subtract(FirstDate);
You can get the length of the time span for example in hours:
double hours = diff.TotalHours;
I'm not sure which time unit "days and nights" could be interpreted as, though. Perhaps days?
double days = diff.TotalDays;
DateTime dt1,dt2;
//...
TimeSpan period = dt1 - dt2;
int days = period.Days;
It sounds like a very long Cab journey that takes days and nights!
I think you need to define what a day and a night is more clearly in order to get your perfect answer. You also need to think about what impact Daylight Saving Time has on your calculations.
If say:
a day was the period from 6am to 6pm
the night was the rest - from 6pm to 6am
and you wanted to really count hours rather than days
In this case then a calculation would require you to:
iterate a currentDateTime from the startDateTime to the endDateTime
choose the increment in the currentDateTime so that it jumps to the next time barrier (6am, 6pm or the endDateTime)
within each loop, then add to your cumulative calculation of numDayHours or numNightHours so far.
Note that:
you could make this calculation quicker by counting whole days along the way
you need to be very careful about the time zone you are calculating in (I just hope that your taxi doesn't cross time zone boundaries!)
you need to be very careful about local time changes - especially "daylight savings time" type changes - the duration from 6pm to 6am is not always 12 hours!
Some pseudo code:
var numDayHours = 0.0;
var numNightHours = 0.0;
var current = startDateTime;
while (current < endDateTime)
{
next_hop = calculate_next_hop (current, endDateTime);
// select next date time
switch (next_hop.hop_type)
{
case HopType.night_time_hop:
numNightHours += next_hop.num_hours;
break;
case HopType.day_time_hop:
numDayHours += next_hop.num_hours;
break;
}
current = next_hop.EndDateTime;
}
// and here is the result
double numDays = numDayHours / 12.0;
double numHours = numNightHours / 12.0;
I have a calendar which passes selected dates as strings into a method. Inside this method, I want to generate a list of all the dates starting from the selected start date and ending with the selected end date, obviously including all of the dates inbetween, regardless of how many days are inbetween the selected start and end dates.
Below I have the beginning of the method which takes the date strings and converts them into DateTime variables so that I can make use of the DateTime calculation functions. However, I cannot seem to work out how to calculate all of the dates inbetween the start and end date?
Obviously the first stage is to subtract the start date from the end date, but I cannot calculate the rest of the steps.
Help appreciated greatly,
kind regards.
public void DTCalculations()
{
List<string> calculatedDates = new List<string>();
string startDate = "2009-07-27";
string endDate = "2009-07-29";
//Convert to DateTime variables
DateTime start = DateTime.Parse(startDate);
DateTime end = DateTime.Parse(endDate);
//Calculate difference between start and end date.
TimeSpan difference = end.Subtract(start);
//Generate list of dates beginning at start date and ending at end date.
//ToDo:
}
static IEnumerable<DateTime> AllDatesBetween(DateTime start, DateTime end)
{
for(var day = start.Date; day <= end; day = day.AddDays(1))
yield return day;
}
Edit: Added code to solve your particular example and to demonstrate usage:
var calculatedDates =
new List<string>
(
AllDatesBetween
(
DateTime.Parse("2009-07-27"),
DateTime.Parse("2009-07-29")
).Select(d => d.ToString("yyyy-MM-dd"))
);
You just need to iterate from start to end, you can do this in a for loop
DateTime start = DateTime.Parse(startDate);
DateTime end = DateTime.Parse(endDate);
for(DateTime counter = start; counter <= end; counter = counter.AddDays(1))
{
calculatedDates.Add(counter);
}
The easiest thing to do would be take the start date, and add 1 day to it (using AddDays) until you reach the end date. Something like this:
DateTime calcDate = start.Date;
while (calcDate <= end)
{
calcDate = calcDate.AddDays(1);
calculatedDates.Add(calcDate.ToString());
}
Obviously, you would adjust the while conditional and the position of the AddDays call depending on if you wanted to include the start and end dates in the collection or not.
[Edit: By the way, you should consider using TryParse() instead of Parse() in case the passed in strings don't convert to dates nicely]
for( DateTime i = start; i <= end; i = i.AddDays( 1 ) )
{
Console.WriteLine(i.ToShortDateString());
}
An alternative method
public static class MyExtensions
{
public static IEnumerable EachDay(this DateTime start, DateTime end)
{
// Remove time info from start date (we only care about day).
DateTime currentDay = new DateTime(start.Year, start.Month, start.Day);
while (currentDay <= end)
{
yield return currentDay;
currentDay = currentDay.AddDays(1);
}
}
}
Now in the calling code you can do the following:
DateTime start = DateTime.Now;
DateTime end = start.AddDays(20);
foreach (var day in start.EachDay(end))
{
...
}
Another advantage to this approach is that it makes it trivial to add EachWeek, EachMonth etc. These will then all be accessible on DateTime.