系统处于TimeZone C时,将TimeStamp列的TimeZone从A转换为B的SQL

时间:2016-11-05 14:17:57

标签: sql oracle timezone

Oracle 11g中的

BirthDatabase表有以下五列:

  1. ID - 非空 - 数字
  2. Name - Varchar2(32)
  3. DOB - 日期
  4. Place - Varchar2(32)
  5. BirthTime - TimeStamp(6)
  6. BirthTime列不支持TimeZone,但其日期时间数据位于UTC

    但是,(最重要的)数据库的系统时间戳位于Europe\London

    这意味着BirthTime数据不会timezone识别,并且与系统TZ相比处于不同的TZ中。

    任务:编写一个SQL查询以在伦敦当地时间获取BirthTime(即当DST为OFF时为UTC,当DST为ON时为UTC + 1)

    我的方法:

    我尝试在SQL中使用cast函数,但没有达到预期的输出

    select
        ID, Name, DOB, Place,
        BirthTime as orig_BT,
        cast(BirthTime as timestamp with time zone) as BT_withTz, 
        cast(cast(BirthTime as timestamp with time zone) at time zone 'Europe/London' as timestamp) BT_BST,
        cast(cast(BirthTime as timestamp with time zone) at time zone 'UTC' as timestamp) BT_UTC
    from
        BirthDatabase
    

    返回以下输出:

    ID  NAME    DOB         PLACE   ORIG_BT                         BT_WITHTZ                                   BT_BST                          BT_UTC
    ________________________________________________________________________________________________________________________________________________________________________
    1   John    28-OCT-16   Bristol 28-OCT-16 10.48.12.000000000    28-OCT-16 10.48.12.000000000 EUROPE/LONDON  28-OCT-16 10.48.12.000000000    28-OCT-16 09.48.12.000000000
    2   Jane    01-NOV-16   London  01-NOV-16 11.48.29.000000000    01-NOV-16 11.48.29.000000000 EUROPE/LONDON  01-NOV-16 11.48.29.000000000    01-NOV-16 11.48.29.000000000
    

    我想要的输出如下:

    ID  NAME    DOB         PLACE   ORIG_BT                         BT_DESIRED
    ____________________________________________________________________________________________
    1   John    28-OCT-16   Bristol 28-OCT-16 10.48.12.000000000    28-OCT-16 11.48.12.000000000
    2   Jane    01-NOV-16   London  01-NOV-16 11.48.29.000000000    01-NOV-16 11.48.29.000000000
    

    我认为使用上述查询的输出获取 Desired output 的快捷方法之一是修改SQL以计算以下内容:

    BT_DESRIED = ORIG_BT + (BT_BST - BT_UTC)
    

    我的问题如下:

    1. 计算BT_DESRIED = ORIG_BT + (BT_BST - BT_UTC)

    2. 的上述表达式的语法是什么
    3. 有没有更优雅的方法来实现这一目标?

2 个答案:

答案 0 :(得分:1)

您可以使用以下查询:

select
   ID, Name, DOB, Place, BirthTime as orig_BT,
   FROM_TZ(BirthTime, 'UTC') AT TIME ZONE 'Europe/London' AS BT_BST
FROM BirthDatabase;

当您cast(BirthTime as timestamp with time zone)时,Oracle会将 SESSIONTIMEZONE 用于转换 - 而不是数据库系统时区。

当您事先执行cast(BirthTime as timestamp with time zone) at time zone 'Europe/London'时,

alter session set time_zone = 'UTC';会给出正确的结果。

答案 1 :(得分:0)

我的服务器位于时区AMERICA/CHICAGO。在下面的示例中,假设给出了时间戳ts(没有时区)。我选择的第二个值是相同的时间戳,附加了我服务器的时区。

如果您想将其视为表示不同时区而非服务器时区,则可以使用FROM_TZ()函数进行处理 - 请参阅我选择的第三个表达式。然后,您可以使用NEW YORK修饰符(第四个值)从LONDON时区转换为AT TIME ZONE时区。我将值显示在另一个下面以适合窗口(当然在屏幕上它们将在一个非常长的行中)。此外,时间戳的格式使用我当前的设置 - 它们在您的计算机上可能看起来不同,或者使用to_char()显式格式模型。

select ts, 
       cast(ts as timestamp with time zone)                         as ts_at_server_tz,
       from_tz(ts, 'America/New_York')                              as ts_at_NY_tz,
       from_tz(ts, 'America/New_York') at time zone 'Europe/London' as ts_at_LN_tz
from   ( 
         select to_timestamp('2000-01-15 14:30:00', 'yyyy-mm-dd hh24:mi:ss') as ts 
         from   dual 
       )
;


TS                              
------------------------------- 
15-JAN-00 02.30.00.000000000 PM

TS_AT_SERVER_TZ                        
----------------------------------------------- 
15-JAN-00 02.30.00.000000000 PM AMERICA/CHICAGO 

TS_AT_NY_TZ                            
-------------------------------------- ---------
15-JAN-00 02.30.00.000000000 PM AMERICA/NEW_YORK


TS_AT_LN_TZ
---------------------------------------------
15-JAN-00 07.30.00.000000000 PM EUROPE/LONDON