在C#中表示时间(而不是日期和时间)

4

我正在开发一个应用程序,需要表示营业时间的概念(有点像商店)

如何最好地表示这些时间?它们将稍后被保存在数据库中...

到目前为止,我有以下类:

public class OpeningTime
{
    public DayOfWeek DayOfWeek { get; set; }
    public DateTime OpeningTime { get; set; }
    public DateTime ClosingTime { get; set; }
}

那么,我的虚构“商店”课程可能是这样的:

public class Shop
{
    public string Name { get; set; }
    public string Address { get; set; }
    public List<OpeningTime> OpeningTimes { get; set; }
}

DateTime对于表示类似于“周一 - 9:00 - 17:30”这样的内容仍然是正确的吗?


4
建议将类名“OpeningTime”改为类似于“OperationHours”的名称。 - Kirk Woll
1
在 .Net 中,您比在 SQL 中拥有更多的灵活性。首先考虑如何将其持久化到表中,然后在 .Net 中模仿它(假设您只针对一个 RDBMS,并且这种情况会持续一段时间)。您希望这个时间有多精确? - Hamish Grubijan
4个回答

4

坚持使用DateTime

我建议直接使用DateTime,因为它与SQL映射得很好(SQL也使用DateTime),而且我发现相比于使用TimeSpan,DateTime更易读。你还可以使用同一对象并添加日期来获取今天的开放时间。

为什么不使用TimeSpan?

主要是因为它的名称以及这意味着什么。 TimeSpan表示一段时间而不是一个时间点。虽然在框架中用于表示确切的时间(在TimeOfDay中),但该属性在文档中定义为:

表示自午夜以来经过的一天的时间间隔的TimeSpan。

但是...其实没什么区别

最终这没有多大差别,您可以使用TimeSpan,DateTime或自己的结构。 两者之间几乎没有太多开销,只是取决于您发现哪个更易读、更易于维护。


3

个人而言,我更倾向于使用TimeSpan而不是DateTime,但我听到其他人持相反的观点。

[Serializable()]
public class OpeningTime
{
    protected OpeningTime()
    {
    }

    public OpeningTime(DayOfWeek dayOfWeek, TimeSpan fromTime, TimeSpan toTime) 
        : this(dayOfWeek, fromTime.Hours, fromTime.Minutes, toTime.Hours, toTime.Minutes) { }

    public OpeningTime(DayOfWeek dayOfWeek, int fromHours, int fromMinutes, int toHours, int toMinutes)
    {
        if (fromHours < 0 || fromHours > 23)
        {
            throw new ArgumentOutOfRangeException("fromHours", "fromHours must be in the range 0 to 23 inclusive");
        }

        if (toHours < 0 || toHours > 23)
        {
            throw new ArgumentOutOfRangeException("toHours", "toHours must be in the range 0 to 23 inclusive");
        }

        if (fromMinutes < 0 || fromMinutes > 59)
        {
            throw new ArgumentOutOfRangeException("fromMinutes", "fromMinutes must be in the range 0 to 59 inclusive");
        }

        if (toMinutes < 0 || toMinutes > 59)
        {
            throw new ArgumentOutOfRangeException("toMinutes", "toMinutes must be in the range 0 to 59 inclusive");
        }

        this.FromTime = new TimeSpan(fromHours, fromMinutes, 0);
        this.ToTime = new TimeSpan(toHours, toMinutes, 0);

        if (this.FromTime >= this.ToTime)
        {
            throw new ArgumentException("From Time must be before To Time");
        }

        this.DayOfWeek = dayOfWeek;
    }

    public virtual DayOfWeek DayOfWeek { get; private set; }

    public virtual TimeSpan FromTime { get; private set; }

    public virtual TimeSpan ToTime { get; private set; }
}

2
我认为你可以内部表示此为开始的DateTime(这将为您提供DayOfWeek),然后使用TimeSpan作为结束,但将它们作为三个属性公开,这些属性可以是DateTime或TimeSpan。
现在考虑更多的DDD问题...你“可以”使用TimeSpan对象来表示一天中的时间,但如果我按照DDD的思路来考虑,我会想要考虑商店何时开门。TimeSpans可以表示更多的信息,您必须特别验证每次处理它们时它们的长度不超过一天。
因此,一种方法是创建一个简单的类来表示您要表示的内容(您可以仅包装TimeSpan对象而不使用几个int)。
public struct Time 
{
    private readonly int _hour;
    private readonly int _minute;
    private readonly int _second;

    public Time(int hour, int minute, int second)
    {
        if (hour < 0 || hour >= 24)
            throw new ArgumentOutOfRangeException("hour", "Hours must be between 0 and 23 inclusive");
        if (minute < 0 || minute > 59)
            throw new ArgumentOutOfRangeException("minute", "Minutes must be between 0 and 23 inclusive");
        if (second < 0 || second > 59)
            throw new ArgumentOutOfRangeException("second", "Seconds must be between 0 and 23 inclusive");
        _hour = hour;
        _minute = minute;
        _second = second;
    }

    public Time(Time time)
        : this(time.Hour, time.Minute, time.Second)
    {

    }

    public int Hour { get { return _hour; } }
    public int Minute { get { return _minute; } }
    public int Second { get { return _second; } }

    public override string ToString()
    {
        return ToString(true);
    }

    public string ToString(bool showSeconds)
    {
        if (showSeconds)
            return string.Format("{0:00}:{1:00}:{2:00}", Hour, Minute, Second);
        return string.Format("{0:00}:{1:00}:{2:00}", Hour, Minute);
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj)) return false;
        if (obj.GetType() != typeof (Time)) return false;
        return Equals((Time) obj);
    }

    public bool Equals(Time other)
    {
        return other._hour == _hour && other._minute == _minute && other._second == _second;
    }

    public override int GetHashCode()
    {
        unchecked
        {
            int result = _hour;
            result = (result*397) ^ _minute;
            result = (result*397) ^ _second;
            return result;
        }
    }

}

public class OpeningHours
{
    public DayOfWeek DayOfWeek { get; set; }
    public Time OpeningTime { get; set; }
    public Time ClosingTime { get; set; }
    public OpeningHours(DayOfWeek dayOfWeek, Time openingTime, Time closingTime)
    {
        DayOfWeek = dayOfWeek;
        OpeningTime = openingTime;
        ClosingTime = closingTime;
    }
}

1
重新发明日期时间,太棒了! - John Buchanan
你是否应该在你的领域中暴露嵌入类型?DateTime和TimeSpan都不实际代表一般的时间,虽然它们可以用来表示,但这并不是正确的做法。你可以将所有东西都存储为字符串,为什么不这样做呢?这没有概念上的意义。 - Ian Johnson

2
您可以使用TimeSpan来表示一天中的时间。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接