使用NodaTime正确处理打开时间

Jos*_*h P 16 .net c# datetime nodatime

我目前正在编写一个相当简单的应用程序来处理企业的开放/关闭时间,并在试图弄清楚如何正确存储信息时遇到严重困难.

我们的大多数关键功能在很大程度上取决于获得绝对完美的时间,所以显然我希望以最好的方式完成工作!

另外,数据将由用户输入,因此如果底层表示稍微复杂一些(例如,使用TimeSpans来考虑在午夜之后开放),则这对于用户来说是不可见的.

我需要首先存储业务的开放时间,按星期几,与它们相关的时区,例如:

- M:  1000 - 2330
- T:  1000 - 0030
- W:  1900 - 0300
- Th: 2000 - 0300
- F:  2000 - 0800
- Sa: 1000 - 0500
- Su: 1000 - 2300
Run Code Online (Sandbox Code Playgroud)

我目前正在考虑存储它的最佳方法是使用这样的类:

public class OpeningHours
{
    ZonedDateTime OpeningTime { get; set; }
    Period durationOpen { get; set; }

    // TODO: add a method to calculate ClosingTime as a ZonedDateTime
}
Run Code Online (Sandbox Code Playgroud)

但是,这里有两个主要的复杂因素:

  • 我不想存储ZonedDateTime的Year,Month或Date部分 - 我只关心DayOfWeek.

    当然,我可以只存储每个值作为第一个周一/周二等1970年1月1日,但这似乎哈克和非常简单的错误之后-作为NodaTime的作者,非常正确,说明这里谈论的BCL日期时间的限制时,实现.我也有一种感觉,如果稍后我们尝试用日期做任何算术,这可能最终会产生奇怪的古怪错误.

  • 无论如何,用户将不得不输入ClosingTime.客户端我想我可以做一些简单的事情,比如总是假设ClosingTime是第二天,如果它在OpeningTime之前,但同样,它不是完美的,也没有考虑可能开放超过24小时的地方(例如超级市场)

我考虑过的另一件事是使用一个有小时/天的表,并让人们突出显示一周中的小时数来选择开放时间,但是你仍然遇到同样的问题而只想存储OpeningTime的DayOfWeek部分.

任何建议都会受到赞赏,花了最近6个小时阅读我们人类代表时间的搞笑愚蠢的方式让我有点沮丧!

Jon*_*eet 19

由于以下几个原因,我强烈考虑使用LocalTime而不是ZonedDateTime:

  • 你不是想及时代表一个瞬间 ; 这些是自然反复出现的模式(没有相关日期)
  • 你不是要应对商店在不同时区的不同开放时间的情况; 您可能希望将时区与每个商店关联一次,然后您可以随时应用该时区

所以我会有这样的东西(仅显示数据成员;如何理清行为是另一回事):

public class StoreOpeningPeriod
{
    IsoDayOfWeek openingDayOfWeek;
    LocalTime openingTime;
    LocalTime closingTime;
}
Run Code Online (Sandbox Code Playgroud)

请注意,这完全遵循您显示的原始数据,这始终是一个好兆头 - 您既不会添加也不会丢失信息,而且它可能是一种方便的形式.

如果关闭时间早于开放时间,则假设这已经过了午夜 - 如果这种情况相对不常见,您可能希望为用户添加一个确认框,但在代码中查找和处理肯定很容易.

  • 这基本上就是我们在英国铁路行业中的表现,它运作得非常好:像你一样,我们每周都会运行,并且有很多活动都在午夜.唯一要注意的是时钟变化的情况.在你的情况下这可能无关紧要,但它可能是至关重要的(例如,火车司机必须合法地在完成换班和开始下一班之间至少有12小时的间隙,即使时钟已经向前推进). (4认同)
  • ......最后一件事:如果你使用Jon的方法,请确保非常彻底地封装交叉午夜逻辑.(这称为'时间倒置').如果你不这样做,它到处都是*! (3认同)
  • ... contd:替代表示是将所有内容表示为从一周开始的午夜(例如星期日)开始的周期.这对于表示不会自然分裂成几天的活动更有利,并且具有可以代表持续超过24小时的事物的优势.节省日光也是一种痛苦,如果时钟在星期天早上的任何时间都没有变化,它可能会导致一个问题. (2认同)