TSQL:如何将本地时间转换为UTC? (SQL Server 2008)

发布于 2024-07-29 20:15:19 字数 189 浏览 8 评论 0原文

我们正在处理一个需要处理来自不同时区和夏令时设置的全球时间数据的应用程序。 这个想法是在内部以 UTC 格式存储所有内容,并且仅针对本地化用户界面来回转换。 SQL Server 是否提供任何机制来处理给定时间、国家/地区和时区的翻译?

这一定是一个常见问题,所以我很惊讶谷歌不会出现任何可用的东西。

有什么指点吗?

We are dealing with an application that needs to handle global time data from different time zones and daylight savings time settings. The idea is to store everything in UTC format internally and only convert back and forth for the localized user interfaces. Does the SQL Server offer any mechanisms for dealing with the translations given a time, a country and a timezone?

This must be a common problem, so I'm surprised google wouldn't turn up anything usable.

Any pointers?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

沉鱼一梦 2024-08-05 20:15:19

使用示例:

SELECT
    Getdate=GETDATE()
    ,SysDateTimeOffset=SYSDATETIMEOFFSET()
    ,SWITCHOFFSET=SWITCHOFFSET(SYSDATETIMEOFFSET(),0)
    ,GetutcDate=GETUTCDATE()
GO

返回:

Getdate SysDateTimeOffset   SWITCHOFFSET    GetutcDate
2013-12-06 15:54:55.373 2013-12-06 15:54:55.3765498 -08:00  2013-12-06 23:54:55.3765498 +00:00  2013-12-06 23:54:55.373

Sample usage:

SELECT
    Getdate=GETDATE()
    ,SysDateTimeOffset=SYSDATETIMEOFFSET()
    ,SWITCHOFFSET=SWITCHOFFSET(SYSDATETIMEOFFSET(),0)
    ,GetutcDate=GETUTCDATE()
GO

Returns:

Getdate SysDateTimeOffset   SWITCHOFFSET    GetutcDate
2013-12-06 15:54:55.373 2013-12-06 15:54:55.3765498 -08:00  2013-12-06 23:54:55.3765498 +00:00  2013-12-06 23:54:55.373
满身野味 2024-08-05 20:15:19

虽然其中一些答案将使您大致了解,但由于夏令时的原因,您无法对 SqlServer 2005 及更早版本的任意日期执行您想要执行的操作。 使用当前本地和当前 UTC 之间的差异将为我提供当前存在的偏移量。 我还没有找到一种方法来确定相关日期的偏移量。

也就是说,我知道 SqlServer 2008 提供了一些新的日期函数可以解决该问题,但使用早期版本的人们需要注意这些限制。

我们的方法是保留 UTC 并在客户端执行转换,这样我们可以更好地控制转换的准确性。

While a few of these answers will get you in the ballpark, you cannot do what you're trying to do with arbitrary dates for SqlServer 2005 and earlier because of daylight savings time. Using the difference between the current local and current UTC will give me the offset as it exists today. I have not found a way to determine what the offset would have been for the date in question.

That said, I know that SqlServer 2008 provides some new date functions that may address that issue, but folks using an earlier version need to be aware of the limitations.

Our approach is to persist UTC and perform the conversion on the client side where we have more control over the conversion's accuracy.

十雾 2024-08-05 20:15:19

以下是将一个区域 DateTime 转换为另一个区域 DateTime 注意的代码

DECLARE @UTCDateTime DATETIME = GETUTCDATE();
DECLARE @ConvertedZoneDateTime DATETIME;

-- 'UTC' to 'India Standard Time' DATETIME
SET @ConvertedZoneDateTime = @UTCDateTime AT TIME ZONE 'UTC' AT TIME ZONE 'India Standard Time'
SELECT @UTCDateTime AS UTCDATE,@ConvertedZoneDateTime AS IndiaStandardTime

-- 'India Standard Time' to 'UTC' DATETIME
SET @UTCDateTime = @ConvertedZoneDateTime AT TIME ZONE 'India Standard Time' AT TIME ZONE 'UTC'
SELECT @ConvertedZoneDateTime AS IndiaStandardTime,@UTCDateTime AS UTCDATE

AT TIME ZONE 有效仅在 SQL Server 2016+ 上,优点是在转换为特定时区时自动考虑夏令时

Here is the code to convert one zone DateTime to another zone DateTime

DECLARE @UTCDateTime DATETIME = GETUTCDATE();
DECLARE @ConvertedZoneDateTime DATETIME;

-- 'UTC' to 'India Standard Time' DATETIME
SET @ConvertedZoneDateTime = @UTCDateTime AT TIME ZONE 'UTC' AT TIME ZONE 'India Standard Time'
SELECT @UTCDateTime AS UTCDATE,@ConvertedZoneDateTime AS IndiaStandardTime

-- 'India Standard Time' to 'UTC' DATETIME
SET @UTCDateTime = @ConvertedZoneDateTime AT TIME ZONE 'India Standard Time' AT TIME ZONE 'UTC'
SELECT @ConvertedZoneDateTime AS IndiaStandardTime,@UTCDateTime AS UTCDATE

Note: AT TIME ZONE works only on SQL Server 2016+ and the advantage is that it automatically considers Daylight when converting to a particular Time zone

勿忘初心 2024-08-05 20:15:19

对于 SQL Server 2016 及更高版本以及 Azure SQL 数据库,请使用内置的 AT TIME ZONE 语句

对于旧版本的 SQL Server,您可以使用我的 SQL Server 时区支持 项目在 IANA 标准之间进行转换时区,此处列出

UTC 到本地是这样的:

SELECT Tzdb.UtcToLocal('2015-07-01 00:00:00', 'America/Los_Angeles')

本地到 UTC 是这样的:

SELECT Tzdb.LocalToUtc('2015-07-01 00:00:00', 'America/Los_Angeles', 1, 1)

数字选项是用于控制本地时间值受夏令时影响时的行为的标志。 这些在项目的文档中有详细描述。

For SQL Server 2016 and newer, and Azure SQL Database, use the built in AT TIME ZONE statement.

For older editions of SQL Server, you can use my SQL Server Time Zone Support project to convert between IANA standard time zones, as listed here.

UTC to Local is like this:

SELECT Tzdb.UtcToLocal('2015-07-01 00:00:00', 'America/Los_Angeles')

Local to UTC is like this:

SELECT Tzdb.LocalToUtc('2015-07-01 00:00:00', 'America/Los_Angeles', 1, 1)

The numeric options are flag for controlling the behavior when the local time values are affected by daylight saving time. These are described in detail in the project's documentation.

陌路终见情 2024-08-05 20:15:19

SQL Server 2008 有一个名为datetimeoffset 的类型。 对于这类东西来说它确实很有用。

http://msdn.microsoft.com/en-us/library/bb630289。 aspx

然后您可以使用函数 SWITCHOFFSET 将其从一个时区移动到另一个时区,但仍保持相同的 UTC 值。

http://msdn.microsoft.com/en-us/library/bb677244。 aspx

罗布

SQL Server 2008 has a type called datetimeoffset. It's really useful for this type of stuff.

http://msdn.microsoft.com/en-us/library/bb630289.aspx

Then you can use the function SWITCHOFFSET to move it from one timezone to another, but still keeping the same UTC value.

http://msdn.microsoft.com/en-us/library/bb677244.aspx

Rob

缪败 2024-08-05 20:15:19

我倾向于使用 DateTimeOffset 来存储与本地事件无关的所有日期时间(即:会议/聚会等,博物馆中午 12 点至下午 3 点)。

要获取当前的 DTO 作为 UTC:

DECLARE @utcNow DATETIMEOFFSET = CONVERT(DATETIMEOFFSET, SYSUTCDATETIME())
DECLARE @utcToday DATE = CONVERT(DATE, @utcNow);
DECLARE @utcTomorrow DATE = DATEADD(D, 1, @utcNow);
SELECT  @utcToday [today]
        ,@utcTomorrow [tomorrow]
        ,@utcNow [utcNow]

注意:通过网络发送时我将始终使用 UTC...客户端 JS 可以轻松地往返于本地 UTC。 请参阅:new Date().toJSON() ...

以下 JS 将处理将 ISO8601 格式的 UTC/GMT 日期解析为本地日期时间。

if (typeof Date.fromISOString != 'function') {
  //method to handle conversion from an ISO-8601 style string to a Date object
  //  Date.fromISOString("2009-07-03T16:09:45Z")
  //    Fri Jul 03 2009 09:09:45 GMT-0700
  Date.fromISOString = function(input) {
    var date = new Date(input); //EcmaScript5 includes ISO-8601 style parsing
    if (!isNaN(date)) return date;

    //early shorting of invalid input
    if (typeof input !== "string" || input.length < 10 || input.length > 40) return null;

    var iso8601Format = /^(\d{4})-(\d{2})-(\d{2})((([T ](\d{2}):(\d{2})(:(\d{2})(\.(\d{1,12}))?)?)?)?)?([Zz]|([-+])(\d{2})\:?(\d{2}))?$/;

    //normalize input
    var input = input.toString().replace(/^\s+/,'').replace(/\s+$/,'');

    if (!iso8601Format.test(input))
      return null; //invalid format

    var d = input.match(iso8601Format);
    var offset = 0;

    date = new Date(+d[1], +d[2]-1, +d[3], +d[7] || 0, +d[8] || 0, +d[10] || 0, Math.round(+("0." + (d[12] || 0)) * 1000));

    //use specified offset
    if (d[13] == 'Z') offset = 0-date.getTimezoneOffset();
    else if (d[13]) offset = ((parseInt(d[15],10) * 60) + (parseInt(d[16],10)) * ((d[14] == '-') ? 1 : -1)) - date.getTimezoneOffset();

    date.setTime(date.getTime() + (offset * 60000));

    if (date.getTime() <= new Date(-62135571600000).getTime()) // CLR DateTime.MinValue
      return null;

    return date;
  };
}

I tend to lean towards using DateTimeOffset for all date-time storage that isn't related to a local event (ie: meeting/party, etc, 12pm-3pm at the museum).

To get the current DTO as UTC:

DECLARE @utcNow DATETIMEOFFSET = CONVERT(DATETIMEOFFSET, SYSUTCDATETIME())
DECLARE @utcToday DATE = CONVERT(DATE, @utcNow);
DECLARE @utcTomorrow DATE = DATEADD(D, 1, @utcNow);
SELECT  @utcToday [today]
        ,@utcTomorrow [tomorrow]
        ,@utcNow [utcNow]

NOTE: I will always use UTC when sending over the wire... client-side JS can easily get to/from local UTC. See: new Date().toJSON() ...

The following JS will handle parsing a UTC/GMT date in ISO8601 format to a local datetime.

if (typeof Date.fromISOString != 'function') {
  //method to handle conversion from an ISO-8601 style string to a Date object
  //  Date.fromISOString("2009-07-03T16:09:45Z")
  //    Fri Jul 03 2009 09:09:45 GMT-0700
  Date.fromISOString = function(input) {
    var date = new Date(input); //EcmaScript5 includes ISO-8601 style parsing
    if (!isNaN(date)) return date;

    //early shorting of invalid input
    if (typeof input !== "string" || input.length < 10 || input.length > 40) return null;

    var iso8601Format = /^(\d{4})-(\d{2})-(\d{2})((([T ](\d{2}):(\d{2})(:(\d{2})(\.(\d{1,12}))?)?)?)?)?([Zz]|([-+])(\d{2})\:?(\d{2}))?$/;

    //normalize input
    var input = input.toString().replace(/^\s+/,'').replace(/\s+$/,'');

    if (!iso8601Format.test(input))
      return null; //invalid format

    var d = input.match(iso8601Format);
    var offset = 0;

    date = new Date(+d[1], +d[2]-1, +d[3], +d[7] || 0, +d[8] || 0, +d[10] || 0, Math.round(+("0." + (d[12] || 0)) * 1000));

    //use specified offset
    if (d[13] == 'Z') offset = 0-date.getTimezoneOffset();
    else if (d[13]) offset = ((parseInt(d[15],10) * 60) + (parseInt(d[16],10)) * ((d[14] == '-') ? 1 : -1)) - date.getTimezoneOffset();

    date.setTime(date.getTime() + (offset * 60000));

    if (date.getTime() <= new Date(-62135571600000).getTime()) // CLR DateTime.MinValue
      return null;

    return date;
  };
}
岁月染过的梦 2024-08-05 20:15:19

是的,在某种程度上详细此处
我使用的方法(2008 年之前)是在插入数据库之前在 .NET 业务逻辑中进行转换。

Yes, to some degree as detailed here.
The approach I've used (pre-2008) is to do the conversion in the .NET business logic before inserting into the DB.

素年丶 2024-08-05 20:15:19

您可以使用 GETUTCDATE() 函数获取 UTC 日期时间
也许您可以选择 GETUTCDATE() 和 GETDATE() 之间的差异,并使用此差异将您的日期调整为 UTC

但我同意之前的消息,在业务层中控制正确的日期时间要容易得多(例如在 .NET 中) )。

You can use GETUTCDATE() function to get UTC datetime
Probably you can select difference between GETUTCDATE() and GETDATE() and use this difference to ajust your dates to UTC

But I agree with previous message, that it is much easier to control right datetime in the business layer (in .NET, for example).

场罚期间 2024-08-05 20:15:19

SUBSTRING(CONVERT(VARCHAR(34), SYSDATETIMEOFFSET()), 29, 5)

返回(例如):

-06:0

不是 100% 肯定这总是有效。

SUBSTRING(CONVERT(VARCHAR(34), SYSDATETIMEOFFSET()), 29, 5)

Returns (for example):

-06:0

Not 100% positive this will always work.

空袭的梦i 2024-08-05 20:15:19

7 年过去了...
实际上,这个 SQL Server 2016 新功能可以满足您的需求。
它称为 AT TIME ZONE,考虑 DST(夏令时)的变化,将日期转换为指定的时区。
更多信息请点击这里:
https://msdn.microsoft.com/en-us/library/mt612795.aspx

7 years passed and...
actually there's this new SQL Server 2016 feature that does exactly what you need.
It is called AT TIME ZONE and it converts date to a specified time zone considering DST (daylight saving time) changes.
More info here:
https://msdn.microsoft.com/en-us/library/mt612795.aspx

甲如呢乙后呢 2024-08-05 20:15:19

这适用于当前与 SQL Server 主机具有相同 UTC 偏移量的日期; 它不考虑夏令时的变化。 将 YOUR_DATE 替换为要转换的本地日期。

SELECT DATEADD(第二个, DATEDIFF(第二个, GETDATE(), GETUTCDATE()), YOUR_DATE);

This works for dates that currently have the same UTC offset as SQL Server's host; it doesn't account for daylight savings changes. Replace YOUR_DATE with the local date to convert.

SELECT DATEADD(second, DATEDIFF(second, GETDATE(), GETUTCDATE()), YOUR_DATE);

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文