根据 TimeZoneInfo 将 SQL 查询转换为本地时间的 datetimeoffset

Convert to datetimeoffset from SQL query to local time based on TimeZoneInfo

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

创建记录时,我使用:

getutcdate()

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

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

因此没有偏移量,只有原始 UTC。

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

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 篇文章 per/month,因此您可以根据用户的时区了解在月初或月底哪里时间可能会不稳定。明天某个地方,但到处都是同一时刻。

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

由于我的数据类型 datetimeoffset

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

任何人都可以建议 practice/method 如何实现以下目标:

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

像我说的唯一棘手的区域是在月初或月底...基本上是 12 小时 window,当然还有夏令时,但我不太关心那个。

恭喜,您领先于大多数人。通过将 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(半开区间)。