AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 27276
Accepted
Rachel
Rachel
Asked: 2012-10-20 11:37:55 +0800 CST2012-10-20 11:37:55 +0800 CST 2012-10-20 11:37:55 +0800 CST

是否有更简洁的方法将 UTC 日期时间仅转换为本地日期?

  • 772

我正在尝试编写一个查询,该查询仅根据 UTC 日期时间字段的本地日期部分对记录进行分组。

例如,如果我的表包含10/19/2012 2:00:00,那么它应该被分组为10/18/2012,因为我的当地时间是 EST (-5h) 并且我只对字段的日期部分感兴趣。

我知道我DateAdd(day, DateDiff(day, 0, MyDate), 0)只能从日期时间字段中获取日期部分,并且可以DateAdd(minute, DateDiff(minute, GetUtcDate(), GetDate()), MyUtcDate)将 UTC 日期时间转换为本地日期时间。

但是将两者结合起来严重冒犯了我。

在 SQL Server 2005 中,有没有比这更好的方法来获取 UTC DateTime 字段的 Date 部分,转换为本地时间?

  SELECT DateAdd(day, DateDiff(day, 0, DateAdd(minute, DateDiff(minute, GetUtcDate(), GetDate()), MyUtcDate)), 0)
       , Count(*)
    FROM MyTable
GROUP BY DateAdd(day, DateDiff(day, 0, DateAdd(minute, DateDiff(minute, GetUtcDate(), GetDate()), MyUtcDate)), 0)
sql-server sql-server-2005
  • 3 3 个回答
  • 21764 Views

3 个回答

  • Voted
  1. Best Answer
    Hannah Vernon
    2012-10-20T14:08:01+08:002012-10-20T14:08:01+08:00

    此答案未考虑夏令时更改、闰秒的添加,并且对不是与 UTC 整小时偏移的时区不敏感。有关SQL Server 2016 及更高版本的更准确方法,请参阅我关于此问题的第二个答案。

    如果你不反对让一个函数做脏活,这有助于使语句更清晰:

    CREATE FUNCTION LocalDateFromUTCTime
    (
        @UTCDateTime datetime
    )
    RETURNS datetime
    BEGIN
        DECLARE @diff int;
        SET @diff = datediff(hh,GetUTCDate(), GetDate());
        RETURN DATEADD(day, DATEDIFF(day, 0, DATEADD(hh, @diff, @UTCDateTime)),0);
    END
    

    然后,您可以执行以下操作:

    SELECT dbo.LocalDateFromUTCTime(MyUTCDate), COUNT(*)
    FROM MyTable
    GROUP BY dbo.LocalDateFromUTCTime(MyUTCDate);
    

    上面的代码将截断输入到函数的日期的任何时间部分(这是设计使然)。因此,正如我在回答开头所指出的,任何实施分钟的时区,例如加拿大的爱德华王子岛 (UTC -4:30)、印度 (UTC -4:30) 和加德满都 (UTC +5:45 ),不会看到正确的结果。

    请注意,在大量行上使用这样的函数会影响性能。如下所示的AT TIME ZONE构造不会受到该问题的影响,尽管它绝不是灵丹妙药,性能方面。

    • 6
  2. 孔夫子
    2012-10-20T14:36:13+08:002012-10-20T14:36:13+08:00

    通常,我使用这个表达式

    CAST(LEFT(GetDate() - GetUtcDate() + MyUtcDate, 11) AS DATETIME)
    

    但在 SQL Server 2008 上,这简化为

    CAST(GetDate() - GetUtcDate() + MyUtcDate AS DATE)
    

    除了在这里给出替代表达式之外,如果你是一个 T-SQL 纯粹主义者,嫁给了 DATE 函数来操纵日期时间,我认为除了使用标量函数之外,没有更简洁的方法来获取本地时间。

    • 3
  3. Hannah Vernon
    2022-08-16T13:48:48+08:002022-08-16T13:48:48+08:00

    在 SQL Server 2016 及更高版本中,使用AT TIME ZONE 'timezone'构造在时区之间转换日期时间值。 AT TIME ZONE考虑到多年来为符合夏令时等所需的更改。

    这第一位设置了一些示例数据供我们使用:

    USE [tempdb];
    GO
    
    DROP TABLE IF EXISTS [dbo].[my_table];
    GO
    
    CREATE TABLE [dbo].[my_table]
    (
        [my_table_id]           int         NOT NULL
            PRIMARY KEY
            CLUSTERED
            IDENTITY(-2147483648, 1)
        , [utc_date_column]     datetime    NOT NULL
    );
    
    INSERT INTO [dbo].[my_table] ([utc_date_column])
    SELECT TOP(50039) DATEADD(SECOND, CRYPT_GEN_RANDOM(4) % 86400, DATEADD(DAY, ROW_NUMBER() OVER (ORDER BY (SELECT (NULL))) - 1, '1900-01-01T00:00:00.000'))
    FROM [sys].[syscolumns] sc1
        CROSS JOIN [sys].[syscolumns] sc2;
    GO
    

    接下来,我们获取样本数据并将其填充到中间临时表中,AT TIME ZONE用于首先在“中部标准时间”时区创建日期列的副本,然后仅创建该时间的日期部分。

    DROP TABLE IF EXISTS #intermediate_results;
    CREATE TABLE #intermediate_results
    (
          [original_column]             datetimeoffset(7)   NOT NULL
        , [original_column_local_time]  datetimeoffset(7)   NOT NULL
        , [local_time_date_only]        date                NOT NULL
            INDEX irc CLUSTERED
    );
    
    INSERT INTO #intermediate_results WITH (TABLOCKX)
    (
          [original_column]
        , [original_column_local_time]
        , [local_time_date_only]
    )
    SELECT 
          [original_column]             = mt.[utc_date_column]
        , [original_column_local_time]  = mt.[utc_date_column] AT TIME ZONE 'UTC' AT TIME ZONE 'Central Standard Time'
        , [local_time_date_only]        = CONVERT(date, mt.[utc_date_column] AT TIME ZONE 'UTC' AT TIME ZONE 'Central Standard Time')
    FROM dbo.[my_table] mt
    ORDER BY mt.[utc_date_column] ASC;
    GO
    

    按日期分组的查询变得超级简单:

    SELECT 
          ir.local_time_date_only
        , [rows_on_this_local_day] = COUNT_BIG(1)
    FROM #intermediate_results ir
    GROUP BY ir.local_time_date_only;
    

    行样本的分组输出:

    local_time_date_only rows_on_this_local_day
    1899-12-30 1
    1899-12-31 1
    1900-01-02 1
    1900-01-04 2
    1900-01-05 1
    1900-01-06 1
    1900-01-07 1
    1900-01-09 2

    这些行的基础数据:

    原始列 original_column_local_time local_time_date_only
    1899-12-31 00:27:57.0000000 +00:00 1899-12-30 18:27:57.0000000 -06:00 1899-12-30
    1900-01-01 03:58:45.0000000 +00:00 1899-12-31 21:58:45.0000000 -06:00 1899-12-31
    1900-01-02 07:33:52.0000000 +00:00 1900-01-02 01:33:52.0000000 -06:00 1900-01-02
    1900-01-04 21:49:23.0000000 +00:00 1900-01-04 15:49:23.0000000 -06:00 1900-01-04
    1900-01-05 03:05:18.0000000 +00:00 1900-01-04 21:05:18.0000000 -06:00 1900-01-04
    1900-01-06 04:13:23.0000000 +00:00 1900-01-05 22:13:23.0000000 -06:00 1900-01-05
    1900-01-06 19:21:57.0000000 +00:00 1900-01-06 13:21:57.0000000 -06:00 1900-01-06
    1900-01-07 14:35:54.0000000 +00:00 1900-01-07 08:35:54.0000000 -06:00 1900-01-07
    1900-01-09 21:02:35.0000000 +00:00 1900-01-09 15:02:35.0000000 -06:00 1900-01-09
    1900-01-09 17:17:39.0000000 +00:00 1900-01-09 11:17:39.0000000 -06:00 1900-01-09

    此数据显示了 2022 年从标准时间到夏令时的过渡:

    原始列 original_column_local_time local_time_date_only
    2022-03-12 17:22:25.0000000 +00:00 2022-03-12 11:22:25.0000000 -06:00 2022-03-12
    2022-03-13 07:49:40.0000000 +00:00 2022-03-13 01:49:40.0000000 -06:00 2022-03-13
    2022-03-13 22:43:44.0000000 +00:00 2022-03-13 17:43:44.0000000 -05:00 2022-03-13
    2022-03-15 03:20:19.0000000 +00:00 2022-03-14 22:20:19.0000000 -05:00 2022-03-14
    2022-03-16 23:23:51.0000000 +00:00 2022-03-16 18:23:51.0000000 -05:00 2022-03-16
    2022-03-16 08:00:17.0000000 +00:00 2022-03-16 03:00:17.0000000 -05:00 2022-03-16
    2022-03-17 10:48:36.0000000 +00:00 2022-03-17 05:48:36.0000000 -05:00 2022-03-17
    2022-03-18 15:35:20.0000000 +00:00 2022-03-18 10:35:20.0000000 -05:00 2022-03-18
    2022-03-20 11:04:19.0000000 +00:00 2022-03-20 06:04:19.0000000 -05:00 2022-03-20
    2022-03-21 01:39:34.0000000 +00:00 2022-03-20 20:39:34.0000000 -05:00 2022-03-20
    • 0

相关问题

  • 我需要为每种类型的查询使用单独的索引,还是一个多列索引可以工作?

  • 什么时候应该使用唯一约束而不是唯一索引?

  • 死锁的主要原因是什么,可以预防吗?

  • 如何确定是否需要或需要索引

  • 从 SQL Server 2008 降级到 2005

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何查看 Oracle 中的数据库列表?

    • 8 个回答
  • Marko Smith

    mysql innodb_buffer_pool_size 应该有多大?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    从 .frm 和 .ibd 文件恢复表?

    • 10 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    如何选择每组的第一行?

    • 6 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    pedrosanta 使用 psql 列出数据库权限 2011-08-04 11:01:21 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST
  • Martin Hope
    bernd_k 什么时候应该使用唯一约束而不是唯一索引? 2011-01-05 02:32:27 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve