Andrei
Andrei

Reputation: 119

Validate time against time interval

I have three rules:

Currently I represented them as TimeSpans

public class Rule
{
    public string Name {get; set;}
    public TimeSpan From {get; set;}
}

List<Rule> rules = new List<Rule>()
{
   new Rule() {From = new TimeSpan(9, 0, 0), Name = "A"},
   new Rule() {From = new TimeSpan(15, 0, 0), Name = "B"},
   new Rule() {From = new TimeSpan(19, 0, 0), Name = "C"}
};

My question is how to validate the time input let's say 9.10pm against that rules?

It should pick third rule.

Upvotes: 2

Views: 1050

Answers (4)

Nkosi
Nkosi

Reputation: 247601

With a slight modification by adding an end time to the Rule object

public class Rule {
    public string Name { get; set; }
    public TimeSpan From { get; set; }
    public TimeSpan To { get; set; }
}

this extension method was used to check if a provided input is within the time range of the rule.

public static class RuleExtension {
    public static bool Contains(this Rule rule, TimeSpan input) {
        var value = TimeSpan.Parse(input.ToString());
        var start = rule.From;
        var end = rule.To;

        if (end < start) {
            //loopback
            end += TimeSpan.FromHours(24);
            if (value < start)
                value += TimeSpan.FromHours(24);
        }

        return start.CompareTo(value) <= 0 && value.CompareTo(end) < 0;
    }
}

The following unit test was used to validate the extension method and extraxt a rule from a collection. (Note: used FluentAssertions to assert results.)

[TestClass]
public class MyTestClass {
    [TestMethod]
    public void _ValidateTime() {
        var rules = new List<Rule>()
        {
           new Rule() {From = new TimeSpan(9, 0, 0), To = new TimeSpan(15, 0, 0), Name = "A"},
           new Rule() {From = new TimeSpan(15, 0, 0), To = new TimeSpan(19, 0, 0), Name = "B"},
           new Rule() {From = new TimeSpan(19, 0, 0), To= new TimeSpan(5, 0, 0), Name = "C"}
        };

        var input = TimeSpan.Parse("21:10");
        rules.FirstOrDefault(r => r.Contains(input))
            .Should()
            .NotBeNull()
            .And
            .Match((Rule r) => r.Name == "C");

        input = TimeSpan.Parse("08:10");
        rules.FirstOrDefault(r => r.Contains(input))
            .Should()
            .BeNull();

        input = TimeSpan.Parse("18:10");
        rules.FirstOrDefault(r => r.Contains(input))
            .Should()
            .NotBeNull()
            .And
            .Match((Rule r) => r.Name == "B");

        input = TimeSpan.Parse("10:10");
        rules.FirstOrDefault(r => r.Contains(input))
            .Should()
            .NotBeNull()
            .And
            .Match((Rule r) => r.Name == "A");
    }

Upvotes: 1

Felix Castor
Felix Castor

Reputation: 1675

There are only 24 hours in a day. Could you just make a map array with an enum for assignments:

public enum Category
{
 A,
 B,
 C
}

Then the array. So from your categories above 00:00 - 09:00 would be C.

Category[] values = new Category[24];
for(int i = 0;i<9;i++)
{
 values[i] = Category.C;
}

So you could assign each hour similarly.

Now given an hour (say 6am) as an input you can use a switch:

switch(values[6]) // gets the appropriate category.
{
  case Category.A:
   // handle
   break;
  case Category.B:
   // Handle
   break;
  case Category.C:
   // handle
   break;
  default:
   break;

}

Upvotes: 0

Andrii Litvinov
Andrii Litvinov

Reputation: 13192

Something like below might do the trick:

var currentSpan = DateTime.Now - DateTime.Now.Date;
int ruleIndex = -1;

for (int i = 0; i < rules.Count - 1; i++)
{
    if (currentSpan >= rules[i].From && currentSpan < rules[i + 1].From)
    {
        ruleIndex = i;
        break;
    }
}

if (ruleIndex == -1 && (currentSpan >= rules.Last().From || currentSpan < rules.First().From))
{
    ruleIndex = rules.Count - 1;
}

var rule = rules[ruleIndex];

Upvotes: 1

msitt
msitt

Reputation: 1237

You can use the following:

DateTime input = DateTime.Now;

TimeSpan span = input.TimeOfDay;
for (int i = 0; i < rules.Count - 1; i++) {
    if (span >= rules[i].From && span < rules[i + 1].From) {
        return rules[i];
    }
}
return rules[rules.Count - 1];

Upvotes: 1

Related Questions