Reputation: 92
I got a StartDateTime
and EndDateTime
that I have to validate.
For them to be valid they have to be within allowed hours which are fully customizable.
// allowed hours
allowedStart = new TimeSpan(08, 00, 0);
allowedEnd = new TimeSpan(20, 00, 0);
Now the two dates (StartDateTime
and EndDateTime
) are coming in (some example test cases)
// Valid date
obj1.StartDateTime = new DateTime(2020, 1, 30, 19, 10, 0);
obj1.EndDateTime = new DateTime(2020, 1, 30, 19, 20, 0);
// End date exceeding
obj2.StartDateTime = new DateTime(2020, 1, 30, 19, 50, 0);
obj2.EndDateTime = new DateTime(2020, 1, 30, 20, 15, 0);
// Start and end date exceeding
obj3.StartDateTime = new DateTime(2020, 1, 30, 20, 10, 0);
obj3.EndDateTime = new DateTime(2020, 1, 30, 20, 35, 0);
// Invalid (overnight) both exceeding
obj4.StartDateTime = new DateTime(2020, 1, 30, 23, 50, 0);
obj4.EndDateTime = new DateTime(2020, 1, 31, 0, 35, 0);
// Start to early
obj5.StartDateTime = new DateTime(2020, 1, 31, 7, 50, 0);
obj5.EndDateTime = new DateTime(2020, 1, 31, 8, 15, 0);
I was wondering if there isn't some already implemented function I haven't found since my brain is dying right now. I've been trying to implement this myself like this but the obj4
testcase still kills it:
if ((obj.StartDateTime.Date.Add(allowedStart) <= obj.StartDateTime) &&
(allowedEnd < allowedStart
? obj.EndDateTime <= obj.EndDateTime.Date.AddDays(1).Add(allowedEnd)
: obj.EndDateTime <= obj.EndDateTime.Date.Add(allowedEnd))))
{
// valid
}
else
{
// invalid
}
Upvotes: 1
Views: 943
Reputation: 186833
Let's start from single value
private static bool WithinSpan(DateTime value, TimeSpan from, TimeSpan to) =>
value >= value.Date.Add(from) && value <= value.Date.Add(to);
Now we can implement the same with two value
s:
private static bool WithinSpan(DateTime startDate, DateTime endDate,
TimeSpan from, TimeSpan to) =>
// startDate <= endDate && // you may want to add this condition as well
startDate >= startDate.Date.Add(from) && startDate <= startDate.Date.Add(to) &&
endDate >= startDate.Date.Add(from) && endDate <= startDate.Date.Add(to);
Demo:
TimeSpan allowedStart = new TimeSpan(08, 00, 0);
TimeSpan allowedEnd = new TimeSpan(20, 00, 0);
(DateTime, DateTime)[] tests = new (DateTime, DateTime)[] {
(new DateTime(2020, 1, 30, 19, 10, 0), new DateTime(2020, 1, 30, 19, 20, 0)),
(new DateTime(2020, 1, 30, 19, 50, 0), new DateTime(2020, 1, 30, 20, 15, 0)),
(new DateTime(2020, 1, 30, 20, 10, 0), new DateTime(2020, 1, 30, 20, 35, 0)),
(new DateTime(2020, 1, 30, 23, 50, 0), new DateTime(2020, 1, 31, 0, 35, 0)),
(new DateTime(2020, 1, 31, 7, 50, 0), new DateTime(2020, 1, 31, 8, 15, 0)),
};
Func<DateTime, DateTime, string> within =
(t1, t2) => $"{(WithinSpan(t1, t2, allowedStart, allowedEnd) ? "Yes" : "No")}";
string report = string.Join(Environment.NewLine, tests
.Select(test => $"{test.Item1:yyyy-MM-dd HH:mm:ss} .. {test.Item2:yyyy-MM-dd HH:mm:ss} : {within(test.Item1, test.Item2)}"));
Console.Write(report);
Outcome:
2020-01-30 19:10:00 .. 2020-01-30 19:20:00 : Yes
2020-01-30 19:50:00 .. 2020-01-30 20:15:00 : No
2020-01-30 20:10:00 .. 2020-01-30 20:35:00 : No
2020-01-30 23:50:00 .. 2020-01-31 00:35:00 : No
2020-01-31 07:50:00 .. 2020-01-31 08:15:00 : No
Edit:
Elaborated version is
private static bool WithinSpan(DateTime startDate, DateTime endDate,
TimeSpan from, TimeSpan to) {
// Empty Period
if (startDate > endDate)
return false;
// [from..to] within single day
if (to >= from)
return startDate >= startDate.Date.Add(from) && startDate <= startDate.Date.Add(to) &&
endDate >= startDate.Date.Add(from) && endDate <= startDate.Date.Add(to);
// [from..midnight..to]
if (startDate.Day == endDate.Day)
return startDate >= startDate.Date.Add(from) || endDate <= endDate.Date.Add(to);
else {
to = to.Add(TimeSpan.FromDays(1));
return startDate >= startDate.Date.Add(from) && startDate <= startDate.Date.Add(to) &&
endDate >= startDate.Date.Add(from) && endDate <= startDate.Date.Add(to);
}
}
which removes empty periods, and treats from > to
TimeSpan
as containing midnight.
Demo:
// from 22:00 to midnight and then up to 06:00
TimeSpan allowedStart = new TimeSpan(22, 00, 00);
TimeSpan allowedEnd = new TimeSpan(06, 00, 00);
(DateTime, DateTime)[] tests = new (DateTime, DateTime)[] {
(new DateTime(2020, 1, 30, 19, 10, 0), new DateTime(2020, 1, 30, 19, 20, 0)),
(new DateTime(2020, 1, 30, 19, 50, 0), new DateTime(2020, 1, 30, 20, 15, 0)),
(new DateTime(2020, 1, 30, 20, 10, 0), new DateTime(2020, 1, 30, 20, 35, 0)),
(new DateTime(2020, 1, 30, 23, 50, 0), new DateTime(2020, 1, 31, 0, 35, 0)),
(new DateTime(2020, 1, 30, 23, 00, 0), new DateTime(2020, 1, 30, 23, 35, 0)),
(new DateTime(2020, 1, 30, 3, 00, 0), new DateTime(2020, 1, 30, 4, 00, 0)),
(new DateTime(2020, 1, 31, 4, 50, 0), new DateTime(2020, 1, 31, 8, 15, 0)),
};
Func<DateTime, DateTime, string> within =
(t1, t2) => $"{(WithinSpan(t1, t2, allowedStart, allowedEnd) ? "Yes" : "No")}";
string report = string.Join(Environment.NewLine, tests
.Select(test => $"{test.Item1:yyyy-MM-dd HH:mm:ss} .. {test.Item2:yyyy-MM-dd HH:mm:ss} : {within(test.Item1, test.Item2)}"));
Console.Write(report);
Outcome:
2020-01-30 19:10:00 .. 2020-01-30 19:20:00 : No
2020-01-30 19:50:00 .. 2020-01-30 20:15:00 : No
2020-01-30 20:10:00 .. 2020-01-30 20:35:00 : No
2020-01-30 23:50:00 .. 2020-01-31 00:35:00 : Yes
2020-01-30 23:00:00 .. 2020-01-30 23:35:00 : Yes
2020-01-30 03:00:00 .. 2020-01-30 04:00:00 : Yes
2020-01-31 04:50:00 .. 2020-01-31 08:15:00 : No
Next Edit:
Shortened verison that magically works:
if (startDate > endDate) {
return false;
}
if (startDate.Day == endDate.Day && to < from) {
return startDate >= startDate.Date.Add(from) || endDate <= endDate.Date.Add(to);
}
if (to < from) {
to = to.Add(TimeSpan.FromDays(1));
}
return startDate >= startDate.Date.Add(from) && endDate <= startDate.Date.Add(to);
Upvotes: 2
Reputation: 438
Following, is the exact piece of code I use, for this not exact goal, in my program:
public bool IsInsideTimeframe(DateTime firstStart, DateTime firstEnd, DateTime secondStart, DateTime secondEnd)
{
bool isInside;
if (firstStart.Ticks >= secondStart.Ticks && firstEnd.Ticks <= secondEnd.Ticks)
isInside = true;
else
isInside = false;
return isInside;
}
Let's say you have two time frames, one between 11:00-14:00, the second is 10:00-15:00. In order to check whether the first timespan is inside the second, you use the function in following way: IsInsideTimeframe(11:00, 14:00, 10:00, 15:00)
You can simply run this function on both of the dates you wish to validate, with the "allowed time span" as the "second" date given.
Upvotes: 0