【问题标题】:Why does Oracle's to_timestamp_tz return the wrong time and/or time zone?为什么 Oracle 的 to_timestamp_tz 返回错误的时间和/或时区?
【发布时间】:2017-05-04 20:35:45
【问题描述】:

我之前使用过 Oracle 的带时区时间戳,但这次我将值作为字符串获取并尝试将它们加载到数据库中。

在转换字符串时,我最终得到了数据库时区中的值。这很奇怪,但如果它相应地调整了时间,但它没有。见下文:

SELECT TO_CHAR(systimestamp AT TIME ZONE 'Canada/Pacific', 
                                               'HH24:MI:SS Mon DD, YYYY TZD') now_pst
     , TO_CHAR(systimestamp AT TIME ZONE 'Canada/Eastern', 
                                               'HH24:MI:SS Mon DD, YYYY TZD') now_est 
FROM DUAL

导致:

now_pst                       now_est
09:55:50 Dec 19, 2016 PST     12:55:50 Dec 19, 2016 EST 

现在使用 to_timestamp_tz:

SELECT '09:55:50 Dec 19, 2016 PST' now_pst
 , TO_TIMESTAMP_TZ('09:55:50 Dec 19, 2016 PST', 'HH24:MI:SS Mon DD, YYYY TZD') now_pst_tz
 , '12:55:50 Dec 19, 2016 EST' now_est
 , TO_TIMESTAMP_TZ('12:55:50 Dec 19, 2016 EST', 'HH24:MI:SS Mon DD, YYYY TZD') now_est_tz 
FROM dual

结果:

now_pst                   now_pst_tz                     now_est                   now_est_tz 
09:55:50 Dec 19, 2016 PST 19.12.2016 09:55:50.000 -05:00 12:55:50 Dec 19, 2016 EST 19.12.2016 12:55:50.000 -05:00 

我应该得到的是: NOW_PST_TZ = 19.12.2016 09:55:50.000 -08:00 (不是 -05:00)

NOW_EST_TZ = 19.12.2016 12:55:50.000 -05:00

我有很多期望在这里没有发生,但主要是这些期望应该是同一时间 - 一个在加拿大/东部,一个在加拿大/太平洋。然而我得到了 2 个不同的时间。

to_timestamp_tz 未能将字符串转换为正确的 TZD。

根据要求:

select sessiontimezone, dbtimezone from dual

结果:

SESSIONTIMEZONE DBTIMEZONE 
-05:00          +00:00

【问题讨论】:

  • 您能否运行此查询:select sessiontimezone, dbtimezone from dual; 并将其结果附加到问题中?
  • @krokodilko,你对dbtimezone的价值有什么期望?
  • @Wernfried Domscheit systimestamp 函数返回数据库所在系统的系统日期以及系统时区dbtimezone 函数返回这个时区(系统时区)。 sessiontimezone 返回会话的时区。它们可以不同(dbtimezone 和 sessiontimezone)。
  • @krokodilko, no systimestamp 返回数据库服务器操作系统时区的时间,不是dbtimezone,见stackoverflow.com/questions/29271224/…

标签: oracle timezone


【解决方案1】:

TZD 表示夏令时信息。 TZD 值是带有夏令时信息的缩写时区字符串。它必须与 TZR 中指定的区域相对应。

使用没有时区区域的 TZD 是不明确的,请检查以下查询:

SELECT tzabbrev, tzname, TZ_OFFSET(tzname) 
FROM V$TIMEZONE_NAMES 
WHERE tzabbrev in ('PST', 'EST');

TZABBREV    TZNAME  TZ_OFFSET(TZNAME)
EST America/Antigua -04:00
EST America/Atikokan    -05:00
EST America/Cambridge_Bay   -07:00
EST America/Cancun  -06:00
EST America/Cayman  -05:00
EST America/Chicago -06:00
EST America/Coral_Harbour   -05:00
EST America/Detroit -05:00
EST America/Fort_Wayne  -05:00
EST America/Grand_Turk  -05:00
EST America/Indiana/Indianapolis    -05:00
EST America/Indiana/Knox    -06:00
EST America/Indiana/Marengo -05:00
EST America/Indiana/Petersburg  -05:00
EST America/Indiana/Tell_City   -06:00
EST America/Indiana/Vevay   -05:00
EST America/Indiana/Vincennes   -05:00
EST America/Indiana/Winamac -05:00
EST America/Indianapolis    -05:00
EST America/Iqaluit -05:00
EST America/Jamaica -05:00
EST America/Kentucky/Louisville -05:00
EST America/Kentucky/Monticello -05:00
EST America/Knox_IN -06:00
EST America/Louisville  -05:00
EST America/Managua -06:00
EST America/Menominee   -06:00
EST America/Merida  -06:00
EST America/Moncton -04:00
EST America/Montreal    -05:00
EST America/Nassau  -05:00
EST America/New_York    -05:00
EST America/Nipigon -05:00
EST America/Panama  -05:00
EST America/Pangnirtung -05:00
EST America/Port-au-Prince  -05:00
EST America/Rankin_Inlet    -06:00
EST America/Resolute    -06:00
EST America/Santo_Domingo   -04:00
EST America/Thunder_Bay -05:00
EST America/Toronto -05:00
EST Antarctica/Macquarie    +11:00
EST Australia/ACT   +11:00
EST Australia/Brisbane  +10:00
EST Australia/Broken_Hill   +10:30
EST Australia/Canberra  +11:00
EST Australia/Currie    +11:00
EST Australia/Hobart    +11:00
EST Australia/LHI   +11:00
EST Australia/Lindeman  +10:00
EST Australia/Lord_Howe +11:00
EST Australia/Melbourne +11:00
EST Australia/NSW   +11:00
EST Australia/Queensland    +10:00
EST Australia/Sydney    +11:00
EST Australia/Tasmania  +11:00
EST Australia/Victoria  +11:00
EST Australia/Yancowinna    +10:30
EST CST -06:00
EST Canada/Eastern  -05:00
EST EST -05:00
EST EST5EDT -05:00
EST Jamaica -05:00
EST US/Central  -06:00
EST US/East-Indiana -05:00
EST US/Eastern  -05:00
EST US/Indiana-Starke   -06:00
EST US/Michigan -05:00
PST America/Bahia_Banderas  -06:00
PST America/Boise   -07:00
PST America/Creston -07:00
PST America/Dawson  -08:00
PST America/Dawson_Creek    -07:00
PST America/Ensenada    -08:00
PST America/Hermosillo  -07:00
PST America/Inuvik  -07:00
PST America/Juneau  -09:00
PST America/Los_Angeles -08:00
PST America/Mazatlan    -07:00
PST America/Metlakatla  -08:00
PST America/Santa_Isabel    -08:00
PST America/Sitka   -09:00
PST America/Tijuana -08:00
PST America/Vancouver   -08:00
PST America/Whitehorse  -08:00
PST Canada/Pacific  -08:00
PST Canada/Yukon    -08:00
PST Mexico/BajaNorte    -08:00
PST Mexico/BajaSur  -07:00
PST PST -08:00
PST PST8PDT -08:00
PST Pacific/Pitcairn    -08:00
PST US/Pacific  -08:00
PST US/Pacific-New  -08:00

当您使用TO_TIMESTAMP_TZ() 时,您应该使用带有完整区域名称的TZR

您的表达式TO_TIMESTAMP_TZ('09:55:50 Dec 19, 2016 PST', 'HH24:MI:SS Mon DD, YYYY TZD') 等价于TO_TIMESTAMP_TZ('09:55:50 Dec 19, 2016 '||SESSIONTIMEZONE||' PST', 'HH24:MI:SS Mon DD, YYYY TZR TZD')。如果您当前的会话时区缩写不在PST/EST 中,它将失败。

【讨论】:

    【解决方案2】:

    将格式模型的最后一部分从YYYY TZD 更改为YYYY TZR TZD - 您在格式模型中缺少TZR

    SQL> SELECT '09:55:50 Dec 19, 2016 PST' now_pst
      2   , TO_TIMESTAMP_TZ('09:55:50 Dec 19, 2016 PST', 'HH24:MI:SS Mon DD, YYYY TZR TZD') now_pst_tz
      3   , '12:55:50 Dec 19, 2016 EST' now_est
      4   , TO_TIMESTAMP_TZ('12:55:50 Dec 19, 2016 EST', 'HH24:MI:SS Mon DD, YYYY TZR TZD') now_est_tz
      5  FROM dual;
    
    NOW_PST                   NOW_PST_TZ
    ------------------------- ---------------------------------------------------------------------------
    NOW_EST                   NOW_EST_TZ
    ------------------------- ---------------------------------------------------------------------------
    09:55:50 Dec 19, 2016 PST 19.12.2016 09:55:50.000 -08:00
    12:55:50 Dec 19, 2016 EST 19.12.2016 12:55:50.000 -05:00
    
    
    1 row selected.
    

    编辑:此外,正如 Wernfried 在他的回答中所显示的,在输入字符串中最好使用 Canada/Pacific 而不是 PSTCanada/Eastern 而不是 EST

    【讨论】:

    • 有趣... TZR 给出了 ORA -01882 时区 %s 未找到,但在 PLSQL 中确实有效。这可能就足够了。
    • 顺便说一句,数据来自贝宝,我无法控制它。在社会中,这种格式的日期/时间是很好理解的。然而,我可能把自己锁在一个只考虑北美的沙盒里。也许我需要看看边缘大声笑我发现的小文档似乎支持 TZD 格式而不是 TZR TZD。但是,格式掩码上没有太多内容。我会看看我能否在未来几天证明这一点。感谢您的快速回复:)
    猜你喜欢
    • 2022-06-11
    • 2021-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-22
    • 1970-01-01
    • 2013-11-05
    • 2019-12-13
    相关资源
    最近更新 更多