鉴于你所说的:
“…但是考虑到业务背景,我是否真的需要在数据库中保存UTC的表预订时间并担心在Web客户端上进行本地时间转换呢?”
“…这不是一个在线事件,而是一家餐厅的线下活动。”
对于此用例,您不应使用UTC。您记录的不是某事发生的绝对时间点(现在或过去),而是捕获未来事件的何时何地的“意图”。
当输入预订日期和时间时,顾客提供了“何时”的部分,他们使用餐厅所在地的本地时区提供它。将其转换为UTC或其他时区可能会丢失该意图。
假设这是单个预订(而不是重复规则),则在.NET中,可以使用
DateTime
类型,并将其
Kind
属性设置为
DateTimeKind.Unspecified
(在许多情况下是默认值)。
提供“何地”的部分由您提供,当您设置系统或添加新的餐厅位置时。最好保留每个餐厅的时区标识符或在您的系统中记录,而不是隐式地进行。在.NET中,应使用与
TimeZoneInfo
对象的
Id
属性相对应的字符串值。这是IANA时区ID(例如“Europe/London”)或Windows时区ID(例如“GMT Standard Time”)之一。根据实现方法和.NET版本,您可以在任何平台上支持其中任何一个。强烈建议使用IANA时区ID。
在此场景中只有一种边缘情况需要考虑。自问,您的餐厅是否可能在回退转换可能发生的那天接近预订时间?
当本地与UTC的偏移量减少时(例如伦敦从英国夏令时转为格林威治标准时间),或者政府修改某个时区的标准偏移量时,就会发生这种情况。
如果回答是“不需要”,那么你就不需要再做其他事情了。由于在这些转换发生时,大多数餐厅都不会在非常晚的时间预订桌子,我怀疑这很可能是你的情况。
如果回答是“是”,那么你需要一些方法来澄清预订的时间。例如,如果有人在2021-10-31
的01:00
预订了一张桌子,你可以询问他们的意图是01:00 BST
(第一次发生)还是01:00 GMT
(第二次发生)——因为那是夏令时结束时钟回拨的那一天。一个简单的布尔值可以存储这个意图。
如果你正在考虑使用基于UTC的DateTime
或DateTimeOffset
,我会建议你考虑一下我的看法,即要捕捉意图。例如,你可能认为一个餐厅(在伦敦)记录2021-10-30T18:00:00+01:00
的预订时间在DateTimeOffset
中没有问题,或者在DateTime
中使用其相应的UTC值2021-10-30T17:00:00Z
。问题在于,如果规则在事件预订时与事件发生时之间改变了呢?也许政府提前一周结束夏令时,或者彻底停止使用它。这种不规则的更改已经多次发生在世界各地的各种时区,而且任何地方都有可能再次发生。通常情况下,事件发生的时间越靠未来,我们就越难以预测该时间偏离UTC的偏移量。(对于给定的示例,应捕捉:2021-10-30T18:00:00
和"Europe/London"
。)
如果你正在处理重复事件,这个问题会更加严重,因为偏移量可能会定期地发生变化,只要开始或停止夏令时。尽管我不确定餐厅是否会预订重复的桌子,但这种情况确实会在重复的会议、每日闹钟和其他周期性事件中发生。
最后,我想说的是总有人会说“始终使用UTC”,但这种建议是短视的。总会有UTC不适用的情况,未来的调度肯定是其中之一。