Get the between time range from list of dates

I am currently want to get the date range (between time range) from the list of dates.

For example:

The time now is

2017-04-08 18:00

And I got these from and to dates:

public static string[] fromDates = new string[] { "2017-04-07 07:00", "2017-04-07 10:00", "2017-04-07 12:00", "2017-04-07 14:00", "2017-04-07 16:00" };
public static string[] toDates = new string[] { "2017-04-07 08:00", "2017-04-07 11:00", "2017-04-07 13:00", "2017-04-07 15:00", "2017-04-07 17:00" };

I am using this code:

public static bool IsInRange(this DateTime dateToCheck, string[] startDates, string[] endDates, out string StartDate, out string EndDate)
    {
        DateTime startDate = new DateTime();
        DateTime endDate = new DateTime();

        bool isWithinRange = false;

        for (int i = 0; i < startDates.Length; i++)
        {
            startDate = Convert.ToDateTime(startDates[i]);

            isWithinRange = dateToCheck >= startDate;

            if (isWithinRange)
                break;
        }

        for (int y = 0; y < endDates.Length; y++)
        {
            endDate = Convert.ToDateTime(endDates[y]);

            isWithinRange = dateToCheck < endDate;

            if (isWithinRange)
                break;
        }

        StartDate = startDate;
        EndDate = endDate;

        return isWithinRange;
    }

And I call it like this:

var isBetween = Convert.ToDateTime("2017-04-08 18:00").IsInRange(fromDates, toDates, out StartDate, out EndDate)

But I couldn't make it working, the StartDate in IsInRange method is always return true and it will return the first index from fromDates variable, which is wrong.

How can I make it like the time between?

I know I can do it like this:

var isBetween = dateToCheck >= startDate && dateToCheck < endDate

But it is only one date need to check, what about if it is like my situation?

Your answer much appreciated.

Thanks

Jon Skeet
people
quotationmark

I would start by converting everything into a more useful object model:

  • Get rid of all the strings (i.e. convert from strings to something more useful early on)
  • Instead of having two collections, create a new type indicating "a date/time range". You're being somewhat foiled by relating the wrong items together: the start values aren't related to each other, they're related to their corresponding end dates.

You could do this within the method if you really need to, but it would be better to move to a richer object model for as much of your code as you can. For example, suppose you have:

public sealed class DateTimeRange
{
    public DateTime Start { get; }
    public DateTime End { get; }

    public DateTimeRange(DateTime start, DateTime end)
    {
        // TODO: Validate that start <= end
        Start = start;
        End = end;
    }

    public bool Contains(DateTime value) => Start <= value && value < End;
}

Then your method can look like this:

public DateTimeRange FindRange(IEnumerable<DateTimeRange> ranges, DateTime value) =>
    ranges.FirstOrDefault(range => range.Contains(value));

That will return null if no ranges contain the value, or the first one that does contain a value otherwise.

(As an aside, I'd do all of this in Noda Time instead as a better date/time API, but I'm biased.)

people

See more on this question at Stackoverflow