50

datetimeSQL Serverの値を値に変換するにはどうすればよいdatetimeoffsetですか?


たとえば、既存のテーブルには、datetimeすべて「ローカル」サーバー時間の値が含まれています。

SELECT TOP 5 ChangeDate FROM AuditLog

ChangeDate
=========================
2013-07-25 04:00:03.060
2013-07-24 04:00:03.073
2013-07-23 04:00:03.273
2013-07-20 04:00:02.870
2013-07-19 04:00:03.780

私のサーバー (たまたま) は (現在、今日) UTC から 4 時間遅れています (現在、米国東部時間帯で、サマータイムが有効です):

SELECT SYSDATETIMEOFFSET()

2013-07-25 14:42:41.6450840 -04:00

保存されたdatetime値をdatetimeoffset値に変換したい; サーバーの現在のタイムゾーン オフセット情報を使用します。

私が望む値は次のとおりです。

ChangeDate               ChangeDateOffset
=======================  ==================================
2013-07-25 04:00:03.060  2013-07-25 04:00:03.0600000 -04:00
2013-07-24 04:00:03.073  2013-07-24 04:00:03.0730000 -04:00
2013-07-23 04:00:03.273  2013-07-23 04:00:03.2730000 -04:00
2013-07-20 04:00:02.870  2013-07-20 04:00:02.8700000 -04:00
2013-07-19 04:00:03.780  2013-07-19 04:00:03.7800000 -04:00

望ましい特性を確認できます。

2013-07-19 04:00:03.7800000 -04:00
\_________________________/ \____/
           |                  |
      a "local" datetime      the offset from UTC

ただし、実際の値は次のとおりです。

SELECT TOP 5
   ChangeDate,
   CAST(ChangeDate AS datetimeoffset) AS ChangeDateOffset
FROM AuditLog

ChangeDate               ChangeDateOffset
=======================  ==================================
2013-07-25 04:00:03.060  2013-07-25 04:00:03.0600000 +00:00
2013-07-24 04:00:03.073  2013-07-24 04:00:03.0730000 +00:00
2013-07-23 04:00:03.273  2013-07-23 04:00:03.2730000 +00:00
2013-07-20 04:00:02.870  2013-07-20 04:00:02.8700000 +00:00
2013-07-19 04:00:03.780  2013-07-19 04:00:03.7800000 +00:00

無効な特性の場合:

2013-07-19 04:00:03.7800000 +00:00
\_________________________/ \____/
                              ^
                              |
                             No offset from UTC present

だから私は他のことをランダムに試します:

SELECT TOP 5
    ChangeDate, 
    CAST(ChangeDate AS datetimeoffset) AS ChangeDateOffset,
    DATEADD(minute, DATEDIFF(minute, GETDATE(), GETUTCDATE()), ChangeDate) AS ChangeDateUTC,
    CAST(DATEADD(minute, DATEDIFF(minute, GETDATE(), GETUTCDATE()), ChangeDate) AS datetimeoffset) AS ChangeDateUTCOffset,
    SWITCHOFFSET(CAST(ChangeDate AS datetimeoffset), DATEDIFF(minute, GETUTCDATE(), GETDATE())) AS ChangeDateSwitchedOffset
FROM AuditLog
ORDER BY ChangeDate DESC

結果:

ChangeDate               ChangeDateOffset                    ChangeDateUTC            ChangeDateUTCOffset                 ChangeDateSwitchedOffset
=======================  ==================================  =======================  ==================================  ==================================
2013-07-25 04:00:03.060  2013-07-25 04:00:03.0600000 +00:00  2013-07-25 08:00:03.060  2013-07-25 08:00:03.0600000 +00:00  2013-07-25 00:00:03.0600000 -04:00
2013-07-24 04:00:03.073  2013-07-24 04:00:03.0730000 +00:00  2013-07-24 08:00:03.073  2013-07-24 08:00:03.0730000 +00:00  2013-07-24 00:00:03.0730000 -04:00
2013-07-23 04:00:03.273  2013-07-23 04:00:03.2730000 +00:00  2013-07-23 08:00:03.273  2013-07-23 08:00:03.2730000 +00:00  2013-07-23 00:00:03.2730000 -04:00
2013-07-20 04:00:02.870  2013-07-20 04:00:02.8700000 +00:00  2013-07-20 08:00:02.870  2013-07-20 08:00:02.8700000 +00:00  2013-07-20 00:00:02.8700000 -04:00
2013-07-19 04:00:03.780  2013-07-19 04:00:03.7800000 +00:00  2013-07-19 08:00:03.780  2013-07-19 08:00:03.7800000 +00:00  2013-07-19 00:00:03.7800000 -04:00
                         ----------------------------------                           ----------------------------------  ----------------------------------
                                              No UTC offset                           Time in UTC          No UTC offset  Time all wrong

それらのどれも目的の値を返しません。

直感的に欲しいものを返す何かを誰かが提案できますか?

4

4 に答える 4

77

編集:SQL Server 2016のより良い回答を更新

SELECT 
   ChangeDate,  --original datetime value
   ChangeDate AT TIME ZONE 'Eastern Standard Time' AS ChangeDateOffset
FROM AuditLog

では、日付の変換時に夏時間AT TIME ZONE有効であったかどうかが考慮されます。また、 「東部標準時で「標準」と表示されていても、夏時間も表示されます。

ChangeDate               ChangeDateOffset
-----------------------  ------------------------------
2019-01-21 09:00:00.000  2019-01-21 09:00:00.000 -05:00
2019-02-21 09:00:00.000  2019-02-21 09:00:00.000 -05:00
2019-03-21 09:00:00.000  2019-03-21 09:00:00.000 -04:00  <-- savings time
2019-04-21 09:00:00.000  2019-04-21 09:00:00.000 -04:00  <-- savings time
2019-05-21 09:00:00.000  2019-05-21 09:00:00.000 -04:00  <-- savings time
2019-06-21 09:00:00.000  2019-06-21 09:00:00.000 -04:00  <-- savings time
2019-07-21 09:00:00.000  2019-07-21 09:00:00.000 -04:00  <-- savings time
2019-08-21 09:00:00.000  2019-08-21 09:00:00.000 -04:00  <-- savings time
2019-09-21 09:00:00.000  2019-09-21 09:00:00.000 -04:00  <-- savings time
2019-10-21 09:00:00.000  2019-10-21 09:00:00.000 -04:00  <-- savings time
2019-11-21 09:00:00.000  2019-11-21 09:00:00.000 -05:00
2019-12-21 09:00:00.000  2019-12-21 09:00:00.000 -05:00

Eastern Standard Timestring のハードコーディングを回避し、サーバーの現在のタイムゾーンを使用するにはどうすればよいですか? あなたはSOLです。

元のSQL Server 2016以前の回答

私はそれを考え出した。秘訣は、ToDateTimeOffset任意のオフセット情報を指定されdatetime.

たとえば、同一のクエリは次のとおりです。

SELECT ToDateTimeOffset('2013-07-25 15:35:27', -240)     --  -240 minutes
SELECT ToDateTimeOffset('2013-07-25 15:35:27', '-04:00') --  -4 hours

どちらも戻ります:

2013-07-25 15:35:27.0000000 -04:00

: へのオフセット パラメータToDateTimeOffsetは、次のいずれかになります。

  • integer分数を表す
  • a string、時間と分を表す ({+|-}TZH:THM形式)

サーバーの現在の UTC オフセットが必要です

次に、UTC からのサーバーの現在のオフセットが必要です。integerUTC からの分数をSQL Server に返す方法は 2 つあります。

DATEPART(TZOFFSET, SYSDATETIMEOFFSET()) 
DATEDIFF(minute, GETUTCDATE(), GETDATE())

両方とも戻る

-240

TODATETIMEOFFSETこれを関数にプラグインします。

SELECT ToDateTimeOffset(
      '2013-07-25 15:35:27',
      DATEPART(TZOFFSET, SYSDATETIMEOFFSET()) --e.g. -240
)

datetimeoffset私が望む値を返します:

2013-07-25 15:35:27.0000000 -04:00

全体的に言えば

これで、datetime を datetimeoffset に変換するためのより優れた関数を使用できます。

CREATE FUNCTION dbo.ToDateTimeOffset(@value datetime2)
    RETURNS datetimeoffset AS
BEGIN
/*
    Converts a date/time without any timezone offset into a datetimeoffset value, 
    using the server's current offset from UTC. 
    
    For this we use the built-in ToDateTimeOffset function; 
    which attaches timezone offset information with a datetimeoffset value.
    
    The trick is to use DATEDIFF(minutes) between local server time and UTC 
    to get the offset parameter.
    
    For example:
        DATEPART(TZOFFSET, SYSDATETIMEOFFSET())
    returns the integer
        -240

    for people in EDT (Eastern Daylight Time), which is 4 hours (240 minutes) behind UTC.
    Pass that value to the SQL Server function:
        TODATETIMEOFFSET(@value, -240)
*/
    
    RETURN TODATETIMEOFFSET(@value, DATEPART(TZOFFSET, SYSDATETIMEOFFSET()))
END;

使用例

SELECT TOP 5
    ChangeDate, 
    dbo.ToDateTimeOffset(ChangeDate) AS ChangeDateOffset
FROM AuditLog

必要なものを返します:

ChangeDate               ChangeDateOffset
=======================  ==================================
2013-07-25 04:00:03.060  2013-07-25 04:00:03.0600000 -04:00
2013-07-24 04:00:03.073  2013-07-24 04:00:03.0730000 -04:00
2013-07-23 04:00:03.273  2013-07-23 04:00:03.2730000 -04:00
2013-07-20 04:00:02.870  2013-07-20 04:00:02.8700000 -04:00
2013-07-19 04:00:03.780  2013-07-19 04:00:03.7800000 -04:00

組み込み関数が次のようになっていれば理想的でした。

TODATETIMEOFFSET(value)

「オーバーロード」を作成するのではなく:

dbo.ToDateTimeOffset(value)

: すべてのコードはパブリック ドメインにリリースされます。帰属は必要ありません。

于 2013-07-25T20:02:42.863 に答える
3

現地時間から現在の時間オフセットを持つ datetimeoffset に変換するには、いくつかのトリックが必要なようです。おそらくもっと簡単な方法がありますが、これでうまくいくようです。

SELECT ChangeDate, 
  CONVERT(DATETIMEOFFSET, CONVERT(VARCHAR, ChangeDate, 120) + 
          RIGHT(CONVERT(VARCHAR, SYSDATETIMEOFFSET(), 120), 6), 120)
FROM AuditLog;

おそらく関数を作成する価値があります。

CREATE FUNCTION LOCALIFY(@dt DATETIME) 
  RETURNS DATETIMEOFFSET AS
BEGIN
 RETURN CONVERT(DATETIMEOFFSET, 
          CONVERT(VARCHAR, @dt, 120) + 
          RIGHT(CONVERT(VARCHAR, SYSDATETIMEOFFSET(), 120), 6), 120)
END;

...そして、ただ...

SELECT ChangeDate, dbo.LOCALIFY(ChangeDate) FROM AuditLog;
于 2013-07-25T19:16:20.063 に答える
0

OP から少し遅れていますが、このスレッドはdatetimeへの変換方法に注意するのに役立ちますdatetimeoffset

私はいくつかの機能を使用しましたが、デフォルトが に設定されたフィールドを使用することもお勧めしますsysdatetimeoffset()。これにより、項目が挿入されたとき (現在のタイムスタンプ) が挿入されたときと相対的になります。その後、変更が必要な場合は、更新手順でソースから TZ を利用できます。

これは、 を必要とするOData v4トランザクションで特に顕著になりましたdatetimeoffset

于 2014-12-09T15:30:41.417 に答える