【问题标题】:How to convert "GMT+5.5_(INDIA) " into timezone region "Asia/Kolkata"如何将“GMT+5.5_(INDIA)”转换为时区“亚洲/加尔各答”
【发布时间】:2017-12-27 12:32:36
【问题描述】:

我想知道如何从时区偏移中导出时区名称。例如,如果我有 "GMT-07_(PDT) 我应该得到 America/Los_Angeles 返回。同样,GMT+5.5_(INDIA) 应该返回 Asia/KolkataGMT+09_(JAPAN) 应该返回 Asia/Tokyo

我必须在 Oracle 中实现它。

【问题讨论】:

  • @RonnieOosting - 这个问题绝非易事。这似乎是一个寻找者不知道如何开始的情况。

标签: oracle oracle11g timezone


【解决方案1】:

一些字符串操作和以下内容的组合应该会让你接近

首先,您需要提取提供的偏移量:

select regexp_replace( 'GMT+5.5_(INDIA)'
                     , '[[:alpha:]]{3}(-|\+)(\d+)(\.(\d+))?.*'
                     , '\1\2\3')
  from dual

然后,您需要将其转换为正确的格式。假设正则表达式为您提供了名为 s 的内容,那么:

with setup as (
select to_number(s) as n from ...
       )
    select case when n < 0 then '-' else '+' end 
           || lpad(trunc(n), 2, '0') 
           || ':' 
           || lpad((n - trunc(n)) * 60, 2, '0') as offset
      from dual

最后,您可以使用TZ_OFFSET 来查询我们的视图,以返回所有 个有效时区区域。

select tzname
  from v$timezone_names
 where tzoffset(tzname) = :offset

如果您想选择一个时区,您需要创建一些额外的逻辑来描述您希望选择的时区。

在单个查询中,这看起来很难看,但会像

with strip_characters as (
select to_number(regexp_replace( 'GMT+5.5_(INDIA)'
                               , '[[:alpha:]]{3}(-|\+)(\d+)(\.(\d+))?.*'
                               , '\1\2\3'))
  from dual
       )
, setup as (
select case when n < 0 then '-' else '+' end 
       || lpad(trunc(n), 2, '0') 
       || ':' 
       || lpad((n - trunc(n)) * 60, 2, '0') as offset
  from strip_characters
       )
select t.tzname
  from v$timezone_names t
  join setup s
 where tzoffset(t.tzname) = s.offset

【讨论】:

  • 从链接的文档看来,TZ_OFFSET 不接受时间戳输入,因此它只返回当前的标准时间偏移量。另外,不确定V$TIMEZONE 文档中的示例如何工作,即显示TZABBREV 返回它们的日光缩写,并且没有提供标准缩写的列?
  • TZ_OFFSET() 返回基于时区区域的偏移量,我假设查询执行时的夏令时状态。V$TIMEZONE_NAMES 包含时区区域根据需要多次。你的first example of America/Los_Angeles exists with 5 different timezones in Oracle 11.2。这个答案当然并不完美 - 但它与我所能得到的 OP 所追求的一样接近。也许他们会很幸运,并且在数据的缩写中拥有夏令时。
  • 哦,所以TZ_OFFSET 暗示 现在 作为它的基础?这很有趣——在处理之前记录的数据时也存在问题。感谢V$TIMEZONE_NAMES 的提琴。这显示了可能适用于该时区生命周期的所有缩写 - 这是有道理的,但如果有一个函数采用 tzname 和时间戳来为您提供适当的 tzabbrev 会更有用。不确定Oracle中是否存在。
【解决方案2】:

您所要求的并非以可靠的方式适用于所有情况。任何尝试都会偏向于特定的世界观。

比如你给GMT-07_(PDT),说应该是America/Los_Angeles。这意味着美国的时区标识符在某种程度上更为重要。以下所有规范区域标识符均使用太平洋夏令时间和 GMT-07:

  • America/Los_Angeles(美国)
  • America/Tijuana(墨西哥)
  • America/Vancouver(加拿大)
  • America/Dawson(加拿大)
  • America/Whitehorse(加拿大)

即使采用以美国为中心的世界观,并且仅限于现代,它仍然行不通。考虑另一个例子:GMT-07_(MST)。是America/Denver 还是America/Phoenix?丹佛代表一个在 -7 和 -6 之间转换的夏令时区域,但凤凰城代表一个全年处于 -7 没有夏令时的区域。

这些都是比较简单的例子。考虑一下你是否有GMT+01_(CET)。要处理的差异数不胜数。

还要考虑到并非每个时区都有一个有意义的缩写,并且时区缩写不一致(例如:HST 与 HAST)并且通常是模棱两可的(例如:CST)。

一般而言,可以确定特定时间点与时区标识符的偏移量(有时是缩写),但无法实现相反的方向。

另请参阅the timezone tag wiki 中的“时区!= 偏移量”。

【讨论】:

  • 纯粹出于兴趣,您介意列出与GMT+01_(CET) 的差异之一吗?这对我来说似乎相对简单,因为 CET 表示目前是欧洲中部时间(显然不是 CEST),其 UTC 偏移量为 +01:00。有两个事实相互印证,符合现实。 GMT-07_(PDT) 似乎是 OP 提供的潜在问题最少的示例。
  • Europe/Paris, Europe/Oslo, Europe/Rome... 更多的是在冬天使用 CET,在夏天使用 CEST。而且,Africa/TunisAfrica/Algiers 全年使用 CET(没有 CEST),尽管位于非洲,但仍将时区称为 CET(因为它们靠近地中海)。
  • 啊,你说的是时区。谢谢。除非数据库中有一些额外的数据可以帮助做出决定,否则 OP 在世界各地都遇到了麻烦。
  • 对。这就是我对 OP 正在寻找的东西的理解。底线是,由于数据的性质,它无法在任何技术平台中实现。最好的办法是确定哪些值对他们很重要并手动映射它们。例如,也许 OP 有一个他们知道的数据集,其中包含来自仅在某些地区运营的企业的数据。他们可以将反向映射限制在这些区域。或者更好的是,也许数据集中还有一些其他信息可以更可靠地识别时区,例如纬度/经度或城市+国家/地区。
  • 感谢您的回答
猜你喜欢
  • 2020-10-28
  • 1970-01-01
  • 2016-03-17
  • 2021-01-24
  • 1970-01-01
  • 2020-12-08
  • 1970-01-01
  • 1970-01-01
  • 2021-10-21
相关资源
最近更新 更多