您的函数正在提取 today 的时区缩写并将其应用于提供的日期,有效地假设所有日期都在该区域中。它将在一半的时间内给出正确的结果 - 但只对传入的值的一半。(在冬天,它会弄错夏令时;在夏天,它会弄错冬天的时间)。如果您使用区域名称而不是缩写,那么它不会那样做。但是你不能使用new_time(),反正它只识别几个区域,所以你必须使用at time zone。
使用过去六个月的样本日期(跨越 DST 边界;这是在伦敦运行,但也将在芝加哥运行,如果假设是芝加哥,您的函数也可以),您可以看到当前函数为您提供了什么:
with t (dt) as (
select add_months(trunc(sysdate), -level)
from dual
connect by level <= 6
)
select dt dt,
unix_time_from_date(dt) unix_time_from_date
from t
order by dt;
DT UNIX_TIME_FROM_DATE
------------------- -------------------
2015-12-21 00:00:00 1450674000
2016-01-21 00:00:00 1453352400
2016-02-21 00:00:00 1456030800
2016-03-21 00:00:00 1458536400
2016-04-21 00:00:00 1461214800
2016-05-21 00:00:00 1463806800
您可以告诉 Oracle 日期应该代表哪个时区。如果您将日期转换为时间戳,则它基本上保持不变。如果您将其转换为带有 tome zone 的时间戳,则它将假定服务器的时区。然后,您可以使用at time zone 将其转换为 UTC,并从中减去 1970-01-01 以获得纪元数:
with t (dt) as (
select add_months(trunc(sysdate), -level)
from dual
connect by level <= 6
)
select dt dt,
cast(dt as timestamp) ts,
cast(dt as timestamp with time zone) tstz,
cast(dt as timestamp with time zone) at time zone 'UTC' as utc,
86400 * (cast(cast(dt as timestamp with time zone) at time zone 'UTC' as date)
- date '1970-01-01') as epoch
from t
order by dt;
DT TS TSTZ UTC EPOCH
------------------- ------------------- --------------------------------- ----------------------- -----------
2015-12-21 00:00:00 2015-12-21 00:00:00 2015-12-21 00:00:00 Europe/London 2015-12-21 00:00:00 UTC 1450656000
2016-01-21 00:00:00 2016-01-21 00:00:00 2016-01-21 00:00:00 Europe/London 2016-01-21 00:00:00 UTC 1453334400
2016-02-21 00:00:00 2016-02-21 00:00:00 2016-02-21 00:00:00 Europe/London 2016-02-21 00:00:00 UTC 1456012800
2016-03-21 00:00:00 2016-03-21 00:00:00 2016-03-21 00:00:00 Europe/London 2016-03-21 00:00:00 UTC 1458518400
2016-04-21 00:00:00 2016-04-21 00:00:00 2016-04-21 00:00:00 Europe/London 2016-04-20 23:00:00 UTC 1461193200
2016-05-21 00:00:00 2016-05-21 00:00:00 2016-05-21 00:00:00 Europe/London 2016-05-20 23:00:00 UTC 1463785200
作为获得等效 UTC 的替代方法,仍然基于服务器时区,您可以使用sys_extract_utc():
with t (dt) as (
select add_months(trunc(sysdate), -level)
from dual
connect by level <= 6
)
select dt dt,
cast(dt as timestamp) ts,
cast(dt as timestamp with time zone) tstz,
sys_extract_utc(cast(dt as timestamp)) as utc,
86400 * (cast(sys_extract_utc(cast(dt as timestamp with time zone)) as date)
- date '1970-01-01') as epoch
from t
order by dt;
或者,如果您不想使用服务器时区,而是指定一个,这对这个演示还是有帮助的:
with t (dt) as (
select add_months(trunc(sysdate), -level)
from dual
connect by level <= 6
)
select dt dt,
cast(dt as timestamp) ts,
from_tz(cast(dt as timestamp), 'America/Chicago') tstz,
from_tz(cast(dt as timestamp), 'America/Chicago') at time zone 'UTC' as utc,
86400 * (cast(from_tz(cast(dt as timestamp), 'America/Chicago') at time zone 'UTC' as date)
- date '1970-01-01') as epoch
from t
order by dt;
DT TS TSTZ UTC EPOCH
------------------- ------------------- ----------------------------------- ----------------------- -----------
2015-12-21 00:00:00 2015-12-21 00:00:00 2015-12-21 00:00:00 America/Chicago 2015-12-21 06:00:00 UTC 1450677600
2016-01-21 00:00:00 2016-01-21 00:00:00 2016-01-21 00:00:00 America/Chicago 2016-01-21 06:00:00 UTC 1453356000
2016-02-21 00:00:00 2016-02-21 00:00:00 2016-02-21 00:00:00 America/Chicago 2016-02-21 06:00:00 UTC 1456034400
2016-03-21 00:00:00 2016-03-21 00:00:00 2016-03-21 00:00:00 America/Chicago 2016-03-21 05:00:00 UTC 1458536400
2016-04-21 00:00:00 2016-04-21 00:00:00 2016-04-21 00:00:00 America/Chicago 2016-04-21 05:00:00 UTC 1461214800
2016-05-21 00:00:00 2016-05-21 00:00:00 2016-05-21 00:00:00 America/Chicago 2016-05-21 05:00:00 UTC 1463806800
并将计算出的时期与您的函数进行比较:
with t (dt) as (
select add_months(trunc(sysdate), -level)
from dual
connect by level <= 6
)
select dt dt,
unix_time_from_date(dt) unix_time_from_date,
86400 * (cast(from_tz(cast(dt as timestamp), 'America/Chicago') at time zone 'UTC' as date)
- date '1970-01-01') as epoch,
unix_time_from_date(dt) -
( 86400 * (cast(from_tz(cast(dt as timestamp), 'America/Chicago') at time zone 'UTC' as date)
- date '1970-01-01')) as diff
from t
order by dt;
DT UNIX_TIME_FROM_DATE EPOCH DIFF
------------------- ------------------- ----------- ------
2015-12-21 00:00:00 1450674000 1450677600 -3600
2016-01-21 00:00:00 1453352400 1453356000 -3600
2016-02-21 00:00:00 1456030800 1456034400 -3600
2016-03-21 00:00:00 1458536400 1458536400 0
2016-04-21 00:00:00 1461214800 1461214800 0
2016-05-21 00:00:00 1463806800 1463806800 0
但您仍然必须说明 - 因此可能假设 - 最初代表的日期是哪个时区。你已经在你的函数中这样做了,所以我认为这不是问题。