【问题标题】:Correct way to handle dates in SQL Server when only datetime is available只有日期时间可用时在 SQL Server 中处理日期的正确方法
【发布时间】:2019-04-09 08:18:12
【问题描述】:

我们使用名为“Aras Innovator”的 PLM 软件,需要将日期存储为自定义项目属性。该软件使用 Microsoft SQL Server 存储其数据,并正式支持在数据库级别访问属性。

但是,我们的问题是该软件只支持日期时间,不支持日期。 日期以 UTC 格式存储 - 因此,当我们从中欧的客户存储“2020-01-01”时,它在数据库中变为“2019-12-31 23:00”左右(当天午夜前 1 小时)前)。并且查询“>= 2020-01-01”然后因此无法找到这些行。

软件制造商说:

没有仅存储月份和日期的标准功能;一种 快速选项可能是将其存储为字符串并执行 如果需要,对输入的字符串进行编程验证。

关于直接 SQL 查询,所有日期都以 UTC 格式存储 与多个时区的兼容性。他们是自动 通过标准 API 访问时转换。直接访问时 使用 SQL,您可以使用函数 ConvertToLocal 中描述的 Aras Innovator 11.0 - CD 上的配置国际化指南 图片,第 5.3 节:

SELECT item_number, innovator.ConvertToLocal(created_on, 'Eastern 标准时间') AS CreatedOn FROM innovator.Document

ConvertFromLocal 可用于指定要查询的日期 反对而不是要求这些日期以 UTC 格式发送。

我不相信使用字符串会是一个好的解决方案。 但也不相信他们的“ConvertTo/FromLocal”函数会是一个好的解决方案。 肯定有其他方法可以直接在 SQL Server 中处理这个问题吗?

【问题讨论】:

  • 我认为您的供应商的解决方案是正确的,并且是处理跨时区数据的最佳实现。如果您只存储日期,您基本上会掩盖您正在努力解决的时区问题,并且您可能至少有 24 个版本的“今天”要处理。 UTC 日期和时间将您的所有日期和时间都输入到 1 个时区,并且 ConvertToLocal 允许您确定任何给定查询中“今天”的位置。
  • 问题是我们真的只关心全球范围内的日期。对我们来说,使用时区是没有意义的。想象一个大公司的生日日历(只是举一个简单的例子),你想找到所有在 4 月 9 日出生的员工,无论他们出生在哪个时区或用户当前的时区是什么。或者所有 1980 年 5 月 5 日之后出生的员工。引入时区只会造成混乱。

标签: sql-server date datetime timezone


【解决方案1】:

SQL Server 2016 引入了AT TIME ZONE statement

考虑:

SELECT CONVERT(date, TheDateTime AT TIME ZONE 'UTC'
                                 AT TIME ZONE 'Central Europe Standard Time')

上面将首先将 TheDateTime 字段从 datetime 或 (datetime2) 转换为具有零偏移 (UTC) 的 datetimeoffset 类型。然后它将其转换为Central Europe Standard Time 区域,最后将其转换为date 类型,删除任何时间信息。

就您的陈述而言:

... >= 2020-01-01" 然后因此无法找到这些行。

您应该考虑转换相反的方向,以便查询 UTC 时间 - 这将是 sargable。例如:

SELECT ...
WHERE TheDateTime >= CONVERT(datetime,
                     '2020-01-01' AT TIME ZONE 'Central Europe Standard Time'
                     AT TIME ZONE 'UTC')

当然,您可以提前完成表达式的整个右侧,并改用局部变量。同样,如果您从应用程序调用此查询,您可以在应用程序代码中转换为 UTC,而根本不必在 SQL Server 中进行。

【讨论】:

  • 谢谢。这就是为什么使用字符串存储日期对我来说似乎是一个糟糕的主意。或者字符串比较会是 sargable 吗?然而,令我深感担忧的是,我们可能会从 CET 以外的时区插入日期。假设我们要从东京时间 (UTC+9) 的机器中插入“2020-02-02”。最有可能的是,日期将存储为“2020-02-01 15:00:00”(UTC)。那将是一场彻底的灾难。唯一的选择是始终将日期创建为 UTC 时间的午夜 - 但我不确定这是否可能,因为日期是“自动转换的”(见上文)。
  • 最好的办法是在 SQL 中存储为 date 类型,而不是 datetime。但是,因为听起来你不能这样做,所以将日期存储在中午而不是午夜。 Noon 永远不会切换转换日期(除非您在 Line Islands 有客户 (UTC+13, UTC+14))。
  • 我想我们会将数据保存为字符串。较慢的结果总比不正确的结果好。
  • 如果这样做,请确保始终使用YYYY-MM-DD 格式。否则它们将无法排序。
猜你喜欢
  • 2010-12-28
  • 1970-01-01
  • 1970-01-01
  • 2016-09-19
  • 2012-08-15
  • 2012-05-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多