javascript - SQL Server 和 Javascript 之间的时区名称转换

标签 javascript sql-server datetime timezone

我有一些想要报告的数据(为简洁起见,进行了简化):

MyDateTime (UTC)     MyValue
------               -------
2020-10-01 10:00:00  24
2020-10-01 15:00:00  53
2020-10-02 12:00:00  26
etc

所有日期均存储为 UTC。通常,我会尽可能长时间地保留 UTC 格式的所有内容,并根据用户区域设置在用户浏览器中转换为本地时间。

但是对于这个特定的报告,我想按整个日期聚合数据:

SELECT CAST(MyDateTime AS DATE), AVG(MyValue)
FROM MyTable
GROUP BY CAST(MyDateTime AS DATE)

因此,在 chop MyDateTime 列并对其进行聚合之前,我需要将日期转换为用户的本地时间。

在 SQL Server 中,我可以将 UTC datetime 转换为本地 chop 日期,如下所示:

CAST(CONVERT(datetime2, (SeizeTime AT TIME ZONE 'GMT Standard Time'), 1) AS DATE)

SQL Server 有一个 AT TIME ZONE 子句接受的时区名称列表,在我的示例中,我使用 GMT 标准时间,这是包括夏令时的英国时间.

浏览器中运行的 JavaScript 有另一种命名时区的方法:

console.log(Intl.DateTimeFormat().resolvedOptions().timeZone)
--> Europe/London

所以我的问题是 SQL Server 和 Javascript 之间没有命名时区的通用方法。如何可靠地将欧洲/伦敦映射到GMT标准时间以及世界上所有其他可能的时区?

到目前为止,我解决这个问题的选择是:

  • 使用硬编码查找表 - 如果将来时区信息发生变化,可能会中断。
  • 将所有预先聚合的数据发送到浏览器,将时区应用于日期,然后在客户端聚合数据 - 我希望避免不必要地移动太多数据。

还有我缺少的其他方法吗?

最佳答案

鉴于您的用户配置文件中的问题历史记录,我假设您在应用程序层中使用 .NET 来查询 SQL Server。如果不是这种情况,请发表评论,我会相应调整我的答案。

您问题的核心由 How to translate between Windows and IANA time zones? 解决。 。总之,你可以用我的TimeZoneConverter应用程序层中的库,用于转换来自 Intl 的 IANA 时区名称在浏览器中,更改为 SQL Server 能够识别的 Windows 时区名称。

但是,我还会针对您问题的 SQL 部分添加几点:

  • 在许多情况下,在应用程序层中进行时区转换比在 SQL Server 中更好。 .NET TimeZoneInfo在 Linux 上运行时,该类可以处理转换并理解 IANA 标识符。您可以使用TZConvert.GetTimeZoneInfo在 Windows 上运行时,可以使用 TimeZoneConverter 来使用它们。 (或者,您可以使用 Noda Time 进行转换。)

  • 如果您使用的数据点数量相对较少,请从 SQL 查询所有数据点,不进行分组,然后在应用程序层中对它们进行转换,然后进行分组并执行聚合。这将带来内存和网络开销 - 但将使您的查询更高效、转换更容易。

  • 如果您正在处理更大的数据集,那么聚合和转换确实必须在查询时完成。使用TZConvert.IanaToWindows来自 TimeZoneConverter ,并将其作为参数传递给您的查询以与 AT TIME ZONE 一起使用.

  • 为了防止查询引擎必须扫描整个表,您需要在 UTC 值上建立索引。您还需要一个WHERE使用该原始值的子句,因此您的查询是 "sargable" 。因此,在执行查询之前,您需要将所需的查询范围从客户端时区转换为 UTC。

  • 当源值为 datetime 时或datetime2 ,您需要使用AT TIME ZONE 两次。例如SomeDateTimeValue AT TIME ZONE 'UTC' AT TIME ZONE 'Pacific Standard Time' 。第一个将创建一个 datetimeoffset使用给定的时区,分配正确的偏移量 ( +00:00 ),同时保留日期和时间值。第二个将转换 datetimeoffset到另一个datetimeoffset在给定的时区中,相应地调整日期、时间和偏移量。

这是一个演示 SQL 方面的示例。我设置了一个包含一些附加值的临时表,以明确最终查询中包含和排除的内容。

--Temp table for demo purposes
CREATE TABLE #MyTable (UtcDateTime datetime2, MyValue int)
INSERT INTO #MyTable VALUES ('2020-10-01 06:00:00', 1000) -- excluded
INSERT INTO #MyTable VALUES ('2020-10-01 07:00:00', 100)  -- included
INSERT INTO #MyTable VALUES ('2020-10-01 10:00:00', 24)   -- included
INSERT INTO #MyTable VALUES ('2020-10-01 15:00:00', 53)   -- included
INSERT INTO #MyTable VALUES ('2020-10-02 12:00:00', 26)   -- included
INSERT INTO #MyTable VALUES ('2020-10-03 06:00:00', 100)  -- included
INSERT INTO #MyTable VALUES ('2020-10-03 07:00:00', 1000) -- excluded
 
-- These are the input values of the query
DECLARE @ClientTZ varchar(50) = 'Pacific Standard Time' -- Converted from 'America/Los_Angeles' in the application layer with TimeZoneConverter
DECLARE @FromClientDate date  = '2020-10-01'
DECLARE @ToClientDate date = '2020-10-02'


-- START OF QUERY

-- First you'll need to know the UTC datetimes of the range you are querying over.
-- This pair of values creates a half-open UTC datetime range to be used in the WHERE clause below.
DECLARE @FromUtcDateTime datetime2 = CAST(@FromClientDate AS datetime2) AT TIME ZONE @ClientTZ AT TIME ZONE 'UTC'
DECLARE @ToUtcDateTime datetime2 = CAST(DATEADD(DAY, 1, @ToClientDate) AS datetime2) AT TIME ZONE @ClientTZ AT TIME ZONE 'UTC'

-- Now you can do the query.  The inner subquery does the filtering and conversion.  The outer query does the aggregation.
SELECT ClientDate, AVG(MyValue) as AvgValue
FROM (
    SELECT CAST(UtcDateTime AT TIME ZONE 'UTC' AT TIME ZONE @ClientTZ AS date) as ClientDate, MyValue
    FROM #MyTable
    WHERE UtcDateTime >= @FromUtcDateTime AND UtcDateTime < @ToUtcDateTime
) q
GROUP BY q.ClientDate

-- END OF QUERY

-- Drop the temp table for demo cleanup
DROP TABLE #MyTable

关于javascript - SQL Server 和 Javascript 之间的时区名称转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64206430/

相关文章:

javascript - 将 +""添加到字符串后追加 "0"

javascript - 如何检查一个项目是否有逗号,然后只有两位数

javascript - 从 MS-Word 粘贴到任何基于浏览器的 HTML 编辑器

sql-server - 服务器升级后 Excel 宏上发生 SSL 安全错误

MySQL 按 DATETIME 在表中搜索记录

javascript - 当到达帧结束时如何将其位置重置回原点? javascript

sql-server - 是否有当前版本的 SQL Azure 和 SQL Server 2008 之间差异的明确列表?

sql - 在不丢失或更改当前数据的情况下更改身份种子

angularjs - mattlewis92/angular-bootstrap-calendar 在不同时区计算错误日期

python - Python 中的 ISO 时间 (ISO 8601)