Oracle数据库中DST更改的时间似乎是凌晨1点,而不是2点

时间:2019-05-14 09:36:41

标签: sql oracle

我正在尝试从Oracle中的UTC时间转换为BST时间-但是,看来Oracle中的数据更改时间是1 am而不是2 am。或者我在这里想念什么?我使用以下代码来说明和测试问题:

WITH time1 AS (select cast('2020-03-29 01:00:00 UTC' ASTIMESTAMP WITH TIME ZONE) AS UTC_time FROM dual)
SELECT UTC_time, (UTC_time AT TIME ZONE 'Europe/London') AS bst FROM time1

在世界标准时间1:00:00,BST时间是2:00:00-应该是1:00:00

1 个答案:

答案 0 :(得分:1)

Oracle是正确的,您的期望似乎是错误的。您可以看到欧洲/伦敦DST的更改here

The IANA time zone database在欧洲/伦敦具有以下特点:

# See EU for rules starting in 1996.
...
# Zone  NAME            GMTOFF  RULES   FORMAT  [UNTIL]
Zone    Europe/London   -0:01:15 -      LMT     1847 Dec  1  0:00s
                         0:00   GB-Eire %s      1968 Oct 27
                         1:00   -       BST     1971 Oct 31  2:00u
                         0:00   GB-Eire %s      1996
                         0:00   EU      GMT/BST

因此,自1996年以来,英国一直遵循欧盟的规则,即:

# Europe

# The following rules are for the European Union and for its
# predecessor organization, the European Communities.
# For brevity they are called "EU rules" elsewhere in this file.

# Rule  NAME    FROM    TO      TYPE    IN      ON      AT      SAVE    LETTER/S
Rule    EU      1977    1980    -       Apr     Sun>=1   1:00u  1:00    S
Rule    EU      1977    only    -       Sep     lastSun  1:00u  0       -
Rule    EU      1978    only    -       Oct      1       1:00u  0       -
Rule    EU      1979    1995    -       Sep     lastSun  1:00u  0       -
Rule    EU      1981    max     -       Mar     lastSun  1:00u  1:00    S
Rule    EU      1996    max     -       Oct     lastSun  1:00u  0       -

因此...在英国(和欧盟其他国家),DST从3月的最后一个星期日的世界标准时间01:00开始应用,明年是2020-03-29 01:00:00世界标准时间。它将一直保持夏令时,直到10月的最后一个星期日UTC时间01:00,第二年是2020-10-25 01:00:00 UTC。

Oracle遵循这些规则:

with time1 (utc_time) as (
            select timestamp '2020-03-29 00:00:00.000 UTC' FROM dual
  union all select timestamp '2020-03-29 00:59:59.999 UTC' FROM dual
  union all select timestamp '2020-03-29 01:00:00.000 UTC' FROM dual
  union all select timestamp '2020-03-29 01:59:59.999 UTC' FROM dual
  union all select timestamp '2020-03-29 02:00:00.000 UTC' FROM dual
  --
  union all select timestamp '2020-10-25 00:00:00.000 UTC' FROM dual
  union all select timestamp '2020-10-25 00:59:59.999 UTC' FROM dual
  union all select timestamp '2020-10-25 01:00:00.000 UTC' FROM dual
  union all select timestamp '2020-10-25 01:59:59.999 UTC' FROM dual
  union all select timestamp '2020-10-25 02:00:00.000 UTC' FROM dual
)
select utc_time,
  utc_time at time zone 'Europe/London' as london_time,
  to_char(utc_time at time zone 'Europe/London', 'TZD') as "DST?"
from time1
order by utc_time;

UTC_TIME                          LONDON_TIME                                 DST?  
--------------------------------- ------------------------------------------- ------
2020-03-29 00:00:00.000000000 UTC 2020-03-29 00:00:00.000000000 EUROPE/LONDON GMT   
2020-03-29 00:59:59.999000000 UTC 2020-03-29 00:59:59.999000000 EUROPE/LONDON GMT   
2020-03-29 01:00:00.000000000 UTC 2020-03-29 02:00:00.000000000 EUROPE/LONDON BST   
2020-03-29 01:59:59.999000000 UTC 2020-03-29 02:59:59.999000000 EUROPE/LONDON BST   
2020-03-29 02:00:00.000000000 UTC 2020-03-29 03:00:00.000000000 EUROPE/LONDON BST   
2020-10-25 00:00:00.000000000 UTC 2020-10-25 01:00:00.000000000 EUROPE/LONDON BST   
2020-10-25 00:59:59.999000000 UTC 2020-10-25 01:59:59.999000000 EUROPE/LONDON BST   
2020-10-25 01:00:00.000000000 UTC 2020-10-25 01:00:00.000000000 EUROPE/LONDON GMT   
2020-10-25 01:59:59.999000000 UTC 2020-10-25 01:59:59.999000000 EUROPE/LONDON GMT   
2020-10-25 02:00:00.000000000 UTC 2020-10-25 02:00:00.000000000 EUROPE/LONDON GMT   

在欧洲中部,夏令时适用于同一UTC时间,但是当地时间当然不同:

with time1 (utc_time) as (
  ...
)
select utc_time,
  utc_time at time zone 'Europe/Paris' as paris_time,
  to_char(utc_time at time zone 'Europe/Paris', 'TZD') as "DST?"
from time1
order by utc_time;

UTC_TIME                          PARIS_TIME                                 DST?  
--------------------------------- ------------------------------------------ ------
2020-03-29 00:00:00.000000000 UTC 2020-03-29 01:00:00.000000000 EUROPE/PARIS CET   
2020-03-29 00:59:59.999000000 UTC 2020-03-29 01:59:59.999000000 EUROPE/PARIS CET   
2020-03-29 01:00:00.000000000 UTC 2020-03-29 03:00:00.000000000 EUROPE/PARIS CEST  
2020-03-29 01:59:59.999000000 UTC 2020-03-29 03:59:59.999000000 EUROPE/PARIS CEST  
2020-03-29 02:00:00.000000000 UTC 2020-03-29 04:00:00.000000000 EUROPE/PARIS CEST  
2020-10-25 00:00:00.000000000 UTC 2020-10-25 02:00:00.000000000 EUROPE/PARIS CEST  
2020-10-25 00:59:59.999000000 UTC 2020-10-25 02:59:59.999000000 EUROPE/PARIS CEST  
2020-10-25 01:00:00.000000000 UTC 2020-10-25 02:00:00.000000000 EUROPE/PARIS CET   
2020-10-25 01:59:59.999000000 UTC 2020-10-25 02:59:59.999000000 EUROPE/PARIS CET   
2020-10-25 02:00:00.000000000 UTC 2020-10-25 03:00:00.000000000 EUROPE/PARIS CET   

可能,这就是为什么您希望直到02:00才能看到时间更改,但如果这样,则您会混淆UTC和当地时间,和/或英国和中欧。 >


与您的问题没有直接关系,但是在我的CTE中,我已经从将字符串转换为timsetamp,改为使用a timestamp literal。除了稍微减少键入之外,该格式是明确的。进行强制转换时,您依赖于会话的NLS设置与您提供的字符串格式相匹配,因此,尽管强制转换对您有用,但对于其他运行您的代码的人可能无效。如果您不想(或不能)使用文字,那么将to_timestamp_tz()与显式格式掩码一起使用会更安全。