处理 UTC、时区并使用 LocalTime 对其进行 GROUP BY

发布于 2024-11-16 16:07:27 字数 724 浏览 2 评论 0原文

我被困住了。需要帮助。

我将 UTC 日期存储在数据库中。

示例行:

GenerateAt:

  • 2011-06-08 23:30
  • 2011-06-09 03:30
  • 2011-06-09 15:30

我的用户的当地时间是 -2 小时(中欧)。当我想要 09 开始的行时,我有 3 行。

问题在于用于报告目的的 GROUP BY day 。我有 1 代表 08 年,2 代表 09 年,但对于我的当地时间来说,情况并非如此。

我到处都看到:“以 UTC 格式存储数据”。如何正确地做到这一点?

更新1:
对于数据访问,我使用 NHibernate,并且我更喜欢独立于数据库引擎的解决方案。所以,我正在寻找诸如日期/时间维度表(或类似的东西)之类的解决方案。

我的数据表具有如下列:

  • GenerateAt(日期时间)
  • GenerateAt_Year(int)
  • GenerateAt_Month(int)
  • GenerateAt_Day(int)
  • GenerateAt_Hour(int)

感谢我可以轻松地按以下方式分组:年,年+月,年+月+日,年+月+日+小时。不幸的是,这是 UTC。 :(

如何重构这个解决方案来处理用户时区?

I'm stuck. Need help.

I store UTC dates in database.

Example rows:

GeneratedAt:

  • 2011-06-08 23:30
  • 2011-06-09 03:30
  • 2011-06-09 15:30

Local time for my user is -2 hours (Central Europe). When I want rows from 09 then I have 3 rows.

Problem is with GROUP BY day for reporting purposes. I have 1 for 08 and 2 for 09 but this is not true for my local time.

Everywhere I see: "store data in UTC". How to do this properly?

UPDATE 1:
For data access I'm using NHibernate and I prefer solution independent of the database engine. So, I'm looking for solution with something like Date/Time Dimension table (or something like that).

My data table has columns like this:

  • GeneratedAt (datetime)
  • GeneratedAt_Year (int)
  • GeneratedAt_Month (int)
  • GeneratedAt_Day (int)
  • GeneratedAt_Hour (int)

Thanks to that I can easily grouping by: year, year+month, year+month+day, year+month+day+hour. Unfortunately this is UTC. :(

How to refactor this solution to deal with user timezones?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

天生の放荡 2024-11-23 16:07:27

您可以创建该表的视图,通过应用 DATEADD 函数提供所需中欧时区的日期时间值。

因此,如果您的表列是:id, other_id, evt_time

,那么 select 语句(用于视图定义)将是:

SELECT id, other_id, evt_time, DATEADD( hh, -2, evt_time ) AS evt_time_ce
  FROM MyTable

那么您可以使用该视图并将 GROUP_BY 应用于evt_time_ce

You could create a view of that table which provides the datetime value in the desired Central Europe timezone by applying a DATEADD function.

So if your table columns are: id, other_id, evt_time

then the select statement (for the view definition) would be:

SELECT id, other_id, evt_time, DATEADD( hh, -2, evt_time ) AS evt_time_ce
  FROM MyTable

then you can use the view and apply the GROUP_BY to the evt_time_ce column

风蛊 2024-11-23 16:07:27

我一般也有类似的问题,但我的时差是8小时。

我使用 dateadd(hour,8, [Timestamp]) 选择当地时间,然后使用 dateadd(hour, -8, @dateFrom) 在 WHERE 子句中 - 这也适用于 GROUP BY。

例如:

DECLARE @dateFrom datetime, @dateUntil datetime
SET @dateFrom =  '2011-06-20 00:00:02.000'
SET @dateUntil = '2011-06-22 10:00:00.000'

SELECT TOP 100
    dateadd(hour, 8, [Timestamp]) LocalTime, 
        *
FROM [Log] L (nolock)
WHERE L.[Timestamp] BETWEEN dateadd(hour, -8, @dateFrom) AND dateadd(hour, -8, @dateUntil)
ORDER BY LogID DESC

I have a similar issue in general, but my time difference is 8 hours.

I use dateadd(hour,8, [Timestamp]) to select the local time, and dateadd(hour,-8, @dateFrom) in WHERE clauses - which should work for GROUP BY as well.

For example:

DECLARE @dateFrom datetime, @dateUntil datetime
SET @dateFrom =  '2011-06-20 00:00:02.000'
SET @dateUntil = '2011-06-22 10:00:00.000'

SELECT TOP 100
    dateadd(hour, 8, [Timestamp]) LocalTime, 
        *
FROM [Log] L (nolock)
WHERE L.[Timestamp] BETWEEN dateadd(hour, -8, @dateFrom) AND dateadd(hour, -8, @dateUntil)
ORDER BY LogID DESC
千年*琉璃梦 2024-11-23 16:07:27

SQL Server 2016 引入了 AT TIME ZONE 可以帮助解决此问题,包括处理夏令时。

AT TIME ZONE 允许您在 Windows 注册表中列出的时区之间转换日期。您可以通过运行简单的 SELECT 来查看可用的时区:

select * from sys.time_zone_info

下面的 SQL 将 UTC 存储的日期转换为另一个时区的日期

GeneratedAt
    AT TIME ZONE 'UTC' 
    AT TIME ZONE 'Central Europe Standard Time'

因此,根据本地时区按天分组的 SQL 可能如下所示:

SELECT DATEADD(DAY,0, DATEDIFF(DAY, 0, GeneratedAt
    AT TIME ZONE 'UTC' 
    AT TIME ZONE 'Central Europe Standard Time'))
FROM YourTable
GROUP BY DATEADD(DAY,0, DATEDIFF(DAY, 0, GeneratedAt
    AT TIME ZONE 'UTC' 
    AT TIME ZONE 'Central Europe Standard Time'))

如果您想了解更多内容,这里有一篇关于该主题的好文章

SQL Server 2016 has introduced AT TIME ZONE that can help with this, including handling daylight savings time.

AT TIME ZONE lets you convert dates between time zones listed in the windows registry. You can see what timezones are available by running a simple SELECT:

select * from sys.time_zone_info

Here's the SQL that converts your UTC stored date into a date at another timezone

GeneratedAt
    AT TIME ZONE 'UTC' 
    AT TIME ZONE 'Central Europe Standard Time'

So your SQL to group by day based on a local timezone might look something like this:

SELECT DATEADD(DAY,0, DATEDIFF(DAY, 0, GeneratedAt
    AT TIME ZONE 'UTC' 
    AT TIME ZONE 'Central Europe Standard Time'))
FROM YourTable
GROUP BY DATEADD(DAY,0, DATEDIFF(DAY, 0, GeneratedAt
    AT TIME ZONE 'UTC' 
    AT TIME ZONE 'Central Europe Standard Time'))

Here's a good article about the topic if you want to read more.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文