【发布时间】:2017-03-19 06:23:03
【问题描述】:
Oracle 11g 中的BirthDatabase 表有以下五列:
-
ID- 非空 - 数字 -
Name- Varchar2(32) -
DOB- 日期 -
Place- Varchar2(32) -
BirthTime- 时间戳(6)
BirthTime 列不支持 TimeZone,但有 UTC 中的 DateTime 数据。
但是,(最重要的)数据库的系统时间戳在Europe\London。
这意味着 BirthTime 数据不知道 timezone 并且与系统 TZ 相比位于不同的 TZ。
任务:编写一个 SQL 查询以获取伦敦当地时间的 BirthTime(即 DST 关闭时的 UTC 和 DST 开启时的 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
我认为使用上述查询的输出获得所需输出的一种快速而肮脏的方法是修改 SQL 以计算以下内容:
BT_DESRIED = ORIG_BT + (BT_BST - BT_UTC)
我的问题如下:
上面的
BT_DESRIED = ORIG_BT + (BT_BST - BT_UTC)表达式的计算语法是什么有没有更优雅的方法来实现这一点?
【问题讨论】:
-
还有更优雅的方式——Oracle 有大量的时间戳函数可以从一个时区转换到另一个时区。我现在可以看到的最大问题是您想从 PLACE 推断 ORIG_BT 的时区。所以你需要一个帮助表来告诉你每个地方应该使用哪个时区。 (而且会有并发症 - 那个时候在那个地方使用什么时区名称?他们使用 DST THEN 吗?等等)
-
BirthTime\ORIG_BT 不知道 tz,但该列中的数据采用 UTC。 Place不需要翻译。我相信只要函数可以从一个 tz 转换为另一个,DST 应该不会造成任何问题。