提问人:muezz 提问时间:11/16/2023 更新时间:11/16/2023 访问量:47
按用户时区检索聚合数据
Retrieve aggregated data as per user time zone
问:
我有一个 postgres 数据库,其所有数据都是 UTC 格式。如果我需要显示一天的任何数据或聚合,我只需将本地时间转换为 UTC 并在查询中使用它即可。
但是,现在我必须实现一个图表,显示每天聚合的月份数据。例如,根据用户每天添加的食物日志计算出的 6 个月内每天消耗的卡路里。
问题在于,如果用户位于比格林威治标准时间早 9 小时以上的任何时区,则在上午 9 点(作为早餐)添加的任何日志都将存储在前一天。并且它不会包含在结果中。
我最初的想法是从开始时间开始聚合超过 24 小时的间隔,但对于何时应用或删除 DST 来说,这不是一个好主意。一天有 23 或 25 小时会将所有后续数据丢弃 1 小时。
在客户端,我可以访问用户的时区。我脑海中的解决方案是将时区与请求一起发送,以便可以使用时间戳检查所有行。AT TIME ZONE 'clients-time-zone'
这似乎是一个很常见的问题,我找不到任何好的资源。这是一个好主意,还是有比这更好的方法?
就上下文而言,该应用程序在 Flutter 中,后端构建在使用 Postgres 的 Supabase 之上。中间没有 API 层,因为我使用数据库函数(存储过程)来获取所有必需的数据。
答:
1赞
Laurenz Albe
11/16/2023
#1
如果日期存储在 的列 中,该列的类型包含 UTC 数据,并且客户端位于时区中,则聚合如下:t
timestamp without time zone
Europe/Vienna
GROUP BY CAST (t AT TIME ZONE 'UTC' AT TIME ZONE 'Europe/Vienna' AS date)
第一个转换为绝对时间戳,第二个将其转换为当时维也纳挂钟显示的内容,并且类型转换会截断日期。AT TIME ZONE
t
AT TIME ZONE
评论
0赞
muezz
11/16/2023
我已经尝试过这种方式,效果很好。我担心这是否是最优化的方式。也许我错了,这是唯一的方法?
0赞
Laurenz Albe
11/16/2023
我认为这是最好的方法。它之所以如此复杂,是因为您将 UTC 时间戳存储在数据库中而不是在数据库中使用。这将为您节省第一次转换。timestamp without time zone
timestamp with time zone
0赞
muezz
11/16/2023
只是出于好奇,如果我也开始保存时区,这样的查询会如何进行?我以为这样保存时区是没有用的。假设用户在加利福尼亚添加日志后从加利福尼亚转到维也纳,然后在维也纳添加日志。如果日志是在晚上 8 点在加利福尼亚添加的,我希望它会在凌晨 4 点出现在他们在维也纳的应用内日历中。因此,它将成为第二天消耗的总卡路里的一部分。
0赞
Laurenz Albe
11/17/2023
我不是在谈论保存时区。 不保存时区。这是一个“绝对时间”。因为,加州的晚上 8 点与维也纳的凌晨 4 点相同。它们在磁盘上是相同的。timestamp with time zone
timestamp with time zone
0赞
muezz
11/17/2023
嗯。我以为有一种数据类型也可以存储偏移量。这个想法是你以UTC保存时间戳,但有偏移量。也许我错了?timestamptz
评论
Europe/Vienna