【问题标题】:Convert to datetimeoffset from SQL query to local time based on TimeZoneInfo基于 TimeZoneInfo 从 SQL 查询到本地时间转换为 datetimeoffset
【发布时间】:2015-09-29 14:28:53
【问题描述】:

无论出于何种愚蠢的原因,我在处理时区时仍然感到困惑。

创建记录时,我使用:

getutcdate()

例如,它存储在 datetimeoffset 列中,如下所示:

2015-07-03 20:44:21.0300000 +00:00

所以没有偏移,只是原始的 UTC。

现在,在服务器代码中,我想做一些事情...我有一个查询,它只获取为特定用户发布的文章的 CreatedDate。我将其存储在数据表中:

Dim tz as TimeZoneInfo = GetUserTZInfo(User)
Dim dt as DataTable = GetArticleDates(User)
Dim MaxArticles As Integer = 5
Dim PostedThisMonth As Integer
Dim Remaining As Integer

我将用户限制为每月发布 5 篇文章,因此您可以根据用户的时区查看在月初或月底的时间可能会不稳定的地方。明天在某个地方,但在任何地方都是同一时刻。

但我希望它是用户友好的,并且只是基于用户,而不是服务器时间。

由于我的数据类型为 datetimeoffset

,我在使用一些转换为当地时间的示例时遇到了困难

任何人都可以就如何实现以下目标提出最佳实践/方法:

  1. dt 中搜索任何等于用户月份的创建日期。
  2. 根据找到的内容生成 PostedThisMonth 的计数。

像我说的唯一的粘性区域是在月初或月底...基本上是 12 小时窗口,然后当然是 DST,但我不太关心。

【问题讨论】:

  • 只需使用日期数学并根据用户时区进行调整。您在某个地方有用户时区吗?
  • @SeanLange 我愿意。我向您展示的示例函数为用户返回一个 TimeZoneInfo 对象。
  • 在数据库中这样做不是更有意义吗?否则,您必须返回所有信息,然后对其进行过滤。首先只返回您想要的数据会更有效。
  • 数据库中没有存储偏移量。从技术上讲,我只是查询前 5 个 desc,因此查询很小,但例如,如果它接近月底的午夜,对于某些人来说,它已经是下个月了,尽管对每个人来说都是同一时间。天哪,这让人困惑。
  • 那么你怎么知道给定用户使用什么偏移量?你似乎比实际情况更难做到这一点。如果用户偏移量为 +5,那么您只需在存储的日期上增加 5 小时,即可根据他们的偏移量获得相同的时间范围。

标签: asp.net sql-server vb.net timezone timezone-offset


【解决方案1】:

恭喜,您领先于大多数人。通过将 UTC 时间存储在数据库中并使用 TimeZoneInfo 跟踪用户的时区,您做得对。

如果您从不偏离 +00:00,您可以存储一个 datetimedatetime2 而不是 datetimeoffset,但它不会伤害任何东西,它有明确使用 UTC 的额外好处。

您真正需要做的就是:

  • 使用用户的时区将用户当地月份的开始和结束时间转换为其等效的 UTC 时间点。

  • 使用该范围的值查询您的数据库。

    // compute the start of this month and the next month, by the user's time zone
    Dim today As DateTime = TimeZoneInfo.ConvertTime(DateTime.UtcNow, tz).Date
    Dim startDateOfThisMonth As DateTime = New DateTime(today.Year, today.Month, 1)
    Dim startDateOfNextMonth As DateTime = startDateOfThisMonth.AddMonths(1)
    
    // convert those to UTC
    Dim startUtc As DateTime = TimeZoneInfo.ConvertTimeToUtc(startDateOfThisMonth, tz)
    Dim endUtc As DateTime = TimeZoneInfo.ConvertTimeToUtc(startDateOfNextMonth, tz)
    

    或者,由于您在数据库中使用datetimeoffset,您可以在最后一步中构建一个DateTimeOffset。 SQL 会在扫描索引时使用偏移量在内部转换为 UTC。

    Dim start As DateTimeOffset = New DateTimeOffset(startDateOfThisMonth,
                                            tz.GetUtcOffset(startDateOfThisMonth))
    Dim end As DateTimeOffset = New DateTimeOffset(startDateOfNextMonth,
                                            tz.GetUtcOffset(startDateOfNextMonth))
    

查询数据库时,使用table.dto >= @start AND table.dto < @end(半开区间)。

【讨论】:

  • 非常酷和有趣的方法。谢谢你的加入。现在试试这个。我已经完成了所有工作,但它仍然有点麻烦和昂贵。
  • 这太棒了..所以要完全清楚,如果我通过一个正或负偏移量的开始和/或结束,SQL Server 会处理它吗?这似乎有效,但只是想确定一下。非常感谢。
  • 如果您的字段是datetimeoffset,并且您的查询参数也是DateTimeOffset,那么是的 - SQL 将在查询过程中将其标准化为 UTC。否则,您将首先自己转换为 UTC。如果您愿意,或者您只是不相信 SQL 来做,您仍然可以自己做。 ;)
猜你喜欢
  • 2023-04-03
  • 2019-01-31
  • 2019-11-01
  • 2015-10-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-13
  • 2017-06-10
相关资源
最近更新 更多