以 UTC 格式存储时间总是一个好主意吗? 还是以本地时间存储更好?

一般来说,以 UTC 格式以及 给你给你中提到的格式存储时间是最佳实践。

假设有一个重复发生的事件,比如说结束时间总是在同一个本地时间,比如说17:00,不管这个时区是否有夏令时保存。此外,还有一个要求,不要手动改变时间时,DST 打开或关闭的特定时区。它还要求任何其他系统通过 API (即 GetEndTimeByEvent)请求结束时间时,它总是以 UTC 格式发送结束时间。

方法1: 如果决定 以协调世界时存储,它可以存储在数据库表中,如下所示。

Event      UTCEndTime
=====================
ABC         07:00:00
MNO         06:00:00
PQR         04:00:00

对于第一个事件 ABC,协调世界时的结束时间是上午07:00,如果将其转换为显示从协调世界时到当地时间在2012年7月1日它将导致17:00当地时间,如果转换为在2012年10月10日(DST 是开启的日期为时区)那么将导致下午6时,这是不正确的结束时间。

我认为一种可能的方法是将 DST 时间存储在附加列中,并在时区为 DST ON 时使用该时间。

方法2: 但是,如果它是 储存为本地时间如下例如事件 ABC 它将总是17:00在任何日期,因为没有转换到从协调世界时到当地时间。

Event      LocalEndTime
=======================
ABC         17:00:00
MNO         16:00:00
PQR         14:00:00

应用程序层将本地时间转换为 UTC 时间,以便通过(API GetEndTimeByEvent)发送到其他系统。

在这种情况下,以 UTC 格式存储时间是否仍然是一个好主意?如果是,那么如何得到一个常数的本地时间?

相关问题: 有没有一个好的理由来存储时间不在 UTC?

79153 次浏览

I would just store the Time component only without any Zone. Whenever the API has to serve it, add the correct date and convert that as local time to UTC for that date.

Database = 17:00 (use a timestamp without date, hours as byte, minutes as byte, string)

Retrieve = Date where we want the event + Database 17:00 => Convert this from local to UTC

This way you will always serve the correct time in UTC.

I think that in order to answer that question, we should think about the benefits of using UTC to store timestamps.

I personally think that the main benefit to that is that the time is always (mostly) guaranteed to be consistent. In other words, whenever the timezone is changed, or DST applied, you don't get back or forth in time. This is especially useful in filesystems, logs and so on. But is it necessary in your application?

Think of two things. Firstly, about the time of DST clock shift. Is it likely that your events are going to occur between 2 AM and 3 AM (on the day the clock shift is done)? What should happen then?

Secondly, will the application be subject to actual timezone changes? In other words, are you going to fly with it from London to Warsaw, and change your computer timezone appropriately? What should happen in that case?

If you answered no to both of those questions, then you're better with the local time. It will make your application simpler. But if you answered yes at least once, then I think you should give it more thinking.


And that was all about the database. The other thing is the time format used internally by the application, and that should depend on what actually you will be doing with that time.

You mentioned it exposing the time via an API. Will the application query the database on every request? If you store the time internally as UTC, you will either need to do that or otherwise ensure that on DST/timezone change the cached times will be adjusted/pruned.

Will it do anything with the time itself? Like printing the event will occur in 8 hours or suspending itself for circa that time? If yes, then UTC will probably be better. Of course, you need to think of all the forementioned issues.

I like to think of it this way:

Computers don't care about time as a human-understandable representation. They don't care about time zones, date and time string formatting or any of that. Only humans care about how to interpret and represent time.

Let the database do what it's good at: storing time as a number--either a UNIX epoch (number of seconds elapsed since 1970-01-01) or a UTC timestamp (no timezone or daylight saving time information). Only concern yourself with representing time in a human-understandable way when you must. That means in your application logic, reporting system, console application or any other place a human will be viewing the data.

You're actually not storing a specific point in time as most time APIs assume. Use intervals if your database supports it (PostgreSQL does) or store it as an integer representing the number of seconds (minutes/hours) since midnight or corresponding beginning of the schedule (Monday, the first of the month, etc). In either case, you've dropped a lot of the headaches of worrying about how "Time" is handled between systems, and added only a very minor headache of converting seconds to time of day in your view.

The following wouldn't apply for a truly multi-tenant global SaaS product, so this opinion is aimed at simple "Line of Business" app developers.

Storing as UTC is fine but there is one requirement that causes pain if you do this: "Can you write me a report that shows me how many of X that occur per day?"

If you store dates as UTC, this requirement will cause pain; you need to write timezone adjustment code on the application server and in your reporting; Every ad-hoc query you perform on data that includes date criteria will need to factor this in.

If you application meets the following criteria:

  1. Each instance is based in a single timezone.
  2. Timezone transitions are usually outside office hours or you don't really care about "durations" of things to the level that a missing hour or so will matter.

I suggest you store the datetime as local date time, whilst using a library that isolates you from server timezone config issues (e.g. Noda.Time in the world of .net).

If your inter-system messages use ISO 8601, and your database is storing the origin local time + offset (like datetimeoffset in MSSQL or ISODate in Mongo as ISO 8601 captures it) and you're only using DateTimeOffset in .NET or OffsetDateTime in Java or some equivalent in your code, then no conversions are needed, at all. You just store it. All comparison functions will just work.

If you convert to UTC in your persistence, then you've lost the offset from the point-of-view of the user. Displaying when your user signed a document a decade ago is now a hard problem. Working that out from UTC will mean looking up the DST rules that were in play at that time in that territory. Nightmare.

I believe the reason we are all so used to converting to UTC for persistence is because we never used to have the right datastructures/data-types to allow us to do the right thing.

Can't we always compute the local time given UTC and a timezone? We can't really reliably store a time and a timezone encoded in the time itself since the offsets for timezones can change and the ISO standard only allows us to encode the offset which could change. So, we can't, say, store a time in the future encoded in the local time zone since we don't actually know the offset yet! So, store times in UTC and store the timezone as a separate entry and compute this when needed which is less error prone. Local time is usually an implementation detail. It seems when we store this we are probably mixing up concerns. It's the business of the view to show time relative to timezones most of the time. By storing the components of things and allowing computations to compose them we gain the most flexibility as a general rule.