前端与数据库之间如何正确管理日期和时区

移动开发 2026-07-11

我似乎找不到一个对这个问题的明确方案,选项很多,优缺点也各不相同。

我有一个用Flutter编写的医疗应用,用来记录执行某个治疗/操作的日期和时间。显示的日期需要始终以“墙钟时间”呈现——也就是说如果某次操作在下午4点进行,第二天时区因夏令时变化,前端展示的历史记录需要显示当日的4 点。

我读到的建议大多如下:
- 在前端把本地日期时间转换为UTC,并通过网络发送。
- 在数据库中将日期以UTC存储。
- 将日期以UTC的形式返回给前端,在前端再转换成本地时间

这会导致时间随时区变化而改变——也就是说某天会显示为2 点,夏令时变化后,历史记录将显示为1 点。

其他选项建议存储:
- 以UTC存储日期/时间/时区(在C#中使用datetimeoffset)
- 本地日期/时间
- 时区(即Australia/Sydney)

我不理解的是,为什么不直接把执行该手术/治疗时的本地日期/时间/时区(使用datetimeoffset)存入数据库,然后在前端始终显示这个?很多帖子都建议不要这样做,但我不能理解原因。

另外,我还需要能够对在某一天执行的所有手术/治疗进行报表,因此仅使用UTC的日期/时间在这种场景下行不通(我需要知道用户所在的时区,以判断该操作是在第12日还是第13日,例如)。

解决方案

你的直觉是对的。所谓“只存UTC”的建议,是面向只关心时间瞬点的应用——这类应用占多数,因此成了所谓的“标准”建议。你的应用关心的是墙钟时间。

下面这样的方案可以同时满足两方面的需求:

procedure_at  TIMESTAMPTZ NOT NULL,  -- UTC, for ordering and comparisons
timezone      TEXT NOT NULL           -- "Australia/Sydney"

UTC给你一个统一的时间线,用于排序和跨时区比较(如果你需要的话),而IANA时区名称让你把时间转换回该日期的正确墙钟时间。时区数据库应包含历史规则,因此它应用的是当时生效的偏移量,而不是今天的偏移量。

要报出“12日所有的操作”,请把 procedure_at 转换到存储的时区,并按本地日期进行筛选。

你的 DateTimeOffset 方法也可以工作,因为你直接得到墙钟时间,并且可以从偏移量推导出UTC。你只是失去了地点名称,因此 +11:00 可能是Sydney或 Solomon Islands。对于一个地点上下文可能很重要的医疗应用,我会偏向使用IANA名称。我认为现在大多数平台对它的支持都相当好。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章