平々毎々(アーカイブ)

はてなダイアリーのアーカイブです。

時間帯重複チェックをC#で

お題:時間帯重複チェック - No Programming, No Life

ちょっと息抜きにコードを書いてみた。
こういうのをC#で書くときには、短く書いてドヤ顔をするより、わかりやすいコードを心がけるべきだと思ってはいるのだけど、ついFromTo型をおかしな感じにしてしまった。
FromTo型は、構造体じゃなくクラスにして、パブリックフィールドをプロパティにしたり、IsValidなんて変なメンバーをやめてコンストラクタで例外を出したり、GetIntersectingTimeSpanメソッドの引数がnullかどうかをチェックした方がいいと思う。たぶん。

IdeOneで表示する

using System;
 
static class Prob1
{
    static bool CheckTimeDuplication(Tuple<int, int, int, int> arg0, Tuple<int, int, int, int> arg1)
    {
        if (arg0 == null) throw new ArgumentNullException("arg0");
        if (arg1 == null) throw new ArgumentNullException("arg1");
        FromTo ft0 = new FromTo(arg0.Item1, arg0.Item2, arg0.Item3, arg0.Item4);
        if (!ft0.IsValid) throw new ArgumentOutOfRangeException("arg0");
        FromTo ft1 = new FromTo(arg1.Item1, arg1.Item2, arg1.Item3, arg1.Item4);
        if (!ft1.IsValid) throw new ArgumentOutOfRangeException("arg1");
        return (TimeSpan.Zero < ft0.GetIntersectingTimeSpan(ft1));
    }
}
 
struct FromTo
{
    public readonly TimeSpan From;
    public readonly TimeSpan To;
    public readonly bool IsValid;
 
    public FromTo(int fromHours, int fromMinutes, int toHours, int toMinutes)
    {
        this.IsValid
            = (TryConvert(fromHours, fromMinutes, out this.From) & TryConvert(toHours, toMinutes, out this.To))
            && Validate(this.From, this.To);
    }
 
    private static bool TryConvert(int hours, int minutes, out TimeSpan result)
    {
        result = new TimeSpan(hours, minutes, 0);
        return (result.Hours == hours && result.Minutes == minutes);
    }
 
    private static bool Validate(TimeSpan from, TimeSpan to)
    {
        return (TimeSpan.Zero <= from && from <= to && to <= new TimeSpan(24, 0, 0));
    }
 
    public TimeSpan GetIntersectingTimeSpan(FromTo other)
    {
        return (this.To < other.To ? this.To : other.To)
            - (this.From < other.From ? other.From : this.From);
    }
}