2016-08-17 51 views
0

我有一个查询正在做一些时区转换。举个例子,我想从一个EST时间转换为GMTOracle - 如何正确*从EST/EDT转换为GMT?

对于EDT时间3/13/2016 @2:00 AM(紧接EST-以下> EDT转换)我应该得到的3/13/2016 7:00:00 AMverified here一个GMT时间为3日/ 13/2016 @ 2am)。

SELECT NEW_TIME(TO_DATE('2016/3/13 02:00:00 AM', 
       'YYYY/MM/DD HH:MI:SS AM'),'EDT','GMT') 
FROM DUAL; 

对于EST时3/13/2016 @1:00AM的(一秒的转换之前)我得到什么似乎是正确的结果:

SELECT NEW_TIME(TO_DATE('2016/3/13 01:59:59 AM', 
         'YYYY/MM/DD HH:MI:SS AM'),'EST','GMT') 
FROM DUAL; 

结果相反,我从使用此查询得到3/13/2016 6:00:00 AM

3/13/2016 6:59:59 AM 

我在做什么错在这里?我已阅读了关于NEW_TIME的Oracle文档,并试图用GMT(基于它们在页面底部的一个示例)切换EDT/EST,但这给我带来了更多奇怪的结果。

+0

实际上,我看到这里到底发生了什么,我不敢相信这花了我很长时间才弄明白。凌晨2:00在3/13/2016不存在'EPT'时间!在这一天你永远不会看到凌晨2点!我们只是跳到凌晨3点...(男人我讨厌夏令时!) –

+1

你应该使用完全合格的位置标识符'America/New_York' –

+0

这似乎并不是你这里的问题,但要确保如果您使用的是时区数据,尤其是如果您的数据来自世界各地的时区,而不仅仅是美国的少数几个时区,那么您最新的数据库时区修补程序是最新的。很多生产数据库都没有及时提供有关DST从不同位置开始的所有问题。 –

回答

2

您不应该使用Oracle推荐的旧时尚功能NEW_TIME,使用FROM_TZDatetime Expressions

一个问题是时间区域ESTEDT没有任何夏令时!无论冬天的夏天是什么,EST总是意味着(很有可能)UTC-05:00。 EDT总是意味着(很有可能)UTC-04:00无论冬天的夏天。

除了缺少夏令支持,ESTEDT暧昧,看到这份名单:

SELECT tzabbrev, TZ_OFFSET(tzname), tzname 
FROM V$TIMEZONE_NAMES 
WHERE tzname IN ('EST', 'EDT') OR tzabbrev IN ('EST', 'EDT') 
ORDER BY 1,2; 

TZABBREV TZ_OFFSET(TZNAME) TZNAME 
=============================================== 
EDT -04:00 America/Detroit 
EDT -04:00 US/Eastern 
EDT -04:00 US/East-Indiana 
EDT -04:00 EST5EDT 
EDT -04:00 Canada/Eastern 
EDT -04:00 America/Toronto 
EDT -04:00 America/Thunder_Bay 
EDT -04:00 America/Santo_Domingo 
EDT -04:00 America/Pangnirtung 
EDT -04:00 America/Nipigon 
EDT -04:00 America/New_York 
EDT -04:00 America/Nassau 
EDT -04:00 America/Montreal 
EDT -04:00 America/Louisville 
EDT -04:00 America/Kentucky/Monticello 
EDT -04:00 America/Kentucky/Louisville 
EDT -04:00 America/Iqaluit 
EDT -04:00 America/Indianapolis 
EDT -04:00 America/Indiana/Winamac 
EDT -04:00 America/Indiana/Vincennes 
EDT -04:00 America/Indiana/Vevay 
EDT -04:00 America/Indiana/Petersburg 
EDT -04:00 America/Indiana/Marengo 
EDT -04:00 US/Michigan 
EDT -04:00 America/Fort_Wayne 
EDT -04:00 America/Grand_Turk 
EDT -04:00 America/Indiana/Indianapolis 
EDT -05:00 America/Jamaica 
EDT -05:00 America/Indiana/Tell_City 
EDT -05:00 Jamaica 
EDT -05:00 America/Cancun 
EDT -05:00 America/Port-au-Prince 
EST +09:30 Australia/Broken_Hill 
EST +09:30 Australia/Yancowinna 
EST +10:00 Australia/Canberra 
EST +10:00 Australia/Brisbane 
EST +10:00 Australia/ACT 
EST +10:00 Australia/Currie 
EST +10:00 Australia/Hobart 
EST +10:00 Australia/Lindeman 
EST +10:00 Australia/Melbourne 
EST +10:00 Australia/NSW 
EST +10:00 Australia/Queensland 
EST +10:00 Australia/Tasmania 
EST +10:00 Australia/Sydney 
EST +10:00 Australia/Victoria 
EST +10:30 Australia/Lord_Howe 
EST +10:30 Australia/LHI 
EST +11:00 Antarctica/Macquarie 
EST -03:00 America/Moncton 
EST -04:00 America/Antigua 
EST -04:00 America/Detroit 
EST -04:00 America/Fort_Wayne 
EST -04:00 America/Grand_Turk 
EST -04:00 America/Indiana/Indianapolis 
EST -04:00 America/Indiana/Marengo 
EST -04:00 America/Indiana/Petersburg 
EST -04:00 America/Indiana/Vevay 
EST -04:00 America/Indiana/Vincennes 
EST -04:00 America/Indiana/Winamac 
EST -04:00 America/Indianapolis 
EST -04:00 America/Iqaluit 
EST -04:00 America/Kentucky/Louisville 
EST -04:00 America/Kentucky/Monticello 
EST -04:00 America/Louisville 
EST -04:00 America/Montreal 
EST -04:00 America/Nassau 
EST -04:00 America/New_York 
EST -04:00 America/Nipigon 
EST -04:00 America/Pangnirtung 
EST -04:00 America/Santo_Domingo 
EST -04:00 America/Thunder_Bay 
EST -04:00 America/Toronto 
EST -04:00 Canada/Eastern 
EST -04:00 EST5EDT 
EST -04:00 US/East-Indiana 
EST -04:00 US/Eastern 
EST -04:00 US/Michigan 
EST -05:00 US/Central 
EST -05:00 Jamaica 
EST -05:00 America/Cancun 
EST -05:00 America/Cayman 
EST -05:00 America/Chicago 
EST -05:00 America/Coral_Harbour 
EST -05:00 America/Indiana/Knox 
EST -05:00 America/Indiana/Tell_City 
EST -05:00 America/Jamaica 
EST -05:00 America/Knox_IN 
EST -05:00 America/Atikokan 
EST -05:00 America/Menominee 
EST -05:00 America/Merida 
EST -05:00 America/Panama 
EST -05:00 America/Port-au-Prince 
EST -05:00 America/Rankin_Inlet 
EST -05:00 America/Resolute 
EST -05:00 CST 
EST -05:00 EST 
EST -05:00 US/Indiana-Starke 
EST -06:00 America/Managua 
EST -06:00 America/Cambridge_Bay 

试试这个样子,那么你的时间会自动正确地转换你的季节,不管:

SELECT 
    FROM_TZ(TO_TIMESTAMP('2016/January/01 12:00:00 AM', 'YYYY/MONTH/DD HH:MI:SS AM'), 'America/New_York') AT TIME ZONE 'UTC', 
    FROM_TZ(TO_TIMESTAMP('2016/July/01 12:00:00 AM', 'YYYY/MONTH/DD HH:MI:SS AM'), 'America/New_York') AT TIME ZONE 'UTC' 
FROM dual; 
+0

在大多数情况下,我会建议人们使用您的答案,但我被指示使用一个不同的解决方案(我的答案)。如果完全取决于我,我会按照您的建议使用'FROM_TZ()'函数。谢谢! –

-1

我结束了使用:

SELECT SYSDATE+(SUBSTR(TO_CHAR(SYSTIMESTAMP, 'TZR'),2,2))/24 
FROM DUAL; 

其中(SUBSTR(TO_CHAR(SYSTIMESTAMP, 'TZR'),2,2))为您提供utc时间的当前偏移量。我同意FROM_TZ在时区中存在的许多边缘情况下可能更准确,但我们确实在寻找将这些内容嵌入到视图中时快速计算的内容。

要正确区域之间的转换,我只是增加了电流偏移到什么时候也是,我需要转换:

DECLARE 
l_convert_me_to_utc DATE := TO_DATE('9/12/2016 1:00:00 PM','MM/DD/YYYY HH12:MI:SS AM'); 
l_converted DATE; 
BEGIN 
    l_converted:=(l_convert_me_to_utc+(SUBSTR(TO_CHAR(SYSTIMESTAMP, 'TZR'),2,2))/24); 
    DBMS_OUTPUT.put_line ('UTC TIME IS: '||TO_CHAR(l_converted, 'MM/DD/YYYY HH12:MI:SS AM'));  
END; 

UTC TIME IS: 09/12/2016 05:00:00 PM 

这是有道理的,因为现在的我在纽约TZ在EDT有 - 从UTC的4偏移量

编辑:根据下面的注释,这真的只适用于如果您将任何您的OS SYSDATE现在转换为UTC。如果这是其他时区或过去或未来的某个时间,那么这并不是真的有效。我的最终逻辑比你上面看到的更复杂。对于我的应用程序和更复杂的逻辑(从现在到2100年检查所有TZ切换日期的表格),这确实可行。只是不要拿我以上的东西,并假设它完全按照原样转换为UTC。

+0

不 - 对不起。您不能认为* current * offset是您所处理时间点的正确偏移量。在涉及时区转换时,这是数据错误的主要来源。请参阅[时区标记wiki](http://stackoverflow.com/tags/timezone/info)中的“时区!=偏移量”。您需要使用“America/New_York”来正确表示美国东部时区的所有状态和转换。考虑一下,尽管NY中的当前偏移量是-4,但如果您转换的日期是12月(例如),那么正确的偏移量将是-5。 –

+0

(另外,你说的+4,这将适用于俄罗斯和中东的部分地区,你的意思是-4) –

+0

请注意,'SYSTIMESTAMP'返回数据库操作系统时区的时区中的时间。由于日光节约时间,可能会每年更换两次! (至少我在许多服务器上看到过这种行为)。请考虑使用[SYS_EXTRACT_UTC](http://docs.oracle.com/cd/E11882_01/server.112/e41084/functions186.htm#SQLRF06119)获取UTC时间。 –