从存储在oracle数据库中的long var char毫秒值中获取日期

时间:2010-11-30 10:12:39

标签: sql oracle date timestamp date-arithmetic

我在数据库中有一个日期存储作为varchar中的long值,例如:1230748200000。 我需要通过oracle查询从中获取年份。我可以在oracle中进行操作吗?有没有一种方法可以将其转换为日期以便我能获得一年?问题是我无法使用to_char(SYSTIMESTAMP,'yyyy')或to_Date,因为我没有时间戳或日期格式的日期...而是将其作为长varchar

谢谢。

编辑: 您能为以下场景提供解决方案吗?我在我的表中有1262284398000保存为var char.so因为我说我需要得到一年我使用以下sql返回年份为2009

    select 
to_char(
to_date('01-JAN-1970','DD-MM-YYYY HH24:MI SS') + ( 1262284398000 / (1000*60 * 60 * 24) ) ,'YYYY')
from dual ; 

但是在java代码中,相同的值会将日期返回到2010年,因此年份会变得不同,

Calendar c = Calendar.getInstance();
  c.setTimeInMillis(1262284398000l);
  System.out.println(c.getTime());
  System.out.println(c.get(Calendar.YEAR)); 

哪个日期返回为Fri Jan 01 00:03:18 IST2010为什么这里有区别?

3 个答案:

答案 0 :(得分:2)

查看here了解更多信息

select epoch_time, extract(year from epoch_time) as year
from (
  select date '1970-01-01' + 1291116794/86400 as epoch_time
  from dual
)

可能会出现时区等问题,因为我相信纪元时间将是UTC,但这超出了我的意愿。

此外,看起来您的值是13位数而不是10位,所以您可能只需要添加一些额外的零,即除以86400000而不是86400。

编辑:正如我上面所说....可能存在时区问题。看起来Java代码采用1970-01-01(在UTC中,应该是这样)添加偏移并将其转换为本地时间。您还需要对数据库查询执行此操作。

我对Oracle如何处理时区有点不清楚,但经过一些实验后,我想出了以下示例

alter session set time_zone = 'Asia/Calcutta';
select 
  sessiontimezone,
  to_char(to_date('01-JAN-1970','DD-MM-YYYY HH24:MI SS') + 
    ( 1262284398000 / (1000*60 * 60 * 24) ) ,'YYYY'),
  extract(year from cast(timestamp '1970-01-01 00:00:00 +00:00' at local + 
    numtodsinterval(1262284398000 / 1000, ' SECOND') as timestamp with time zone)),
  to_char(timestamp '1970-01-01 00:00:00 +00:00' at local + 
    numtodsinterval(1262284398000 / 1000, ' SECOND'), 'YYYY'),
  extract(year from cast(timestamp '1970-01-01 00:00:00 +00:00' at local + 
    numtodsinterval(1262284398000 / 1000, ' SECOND') as timestamp with local time 
    zone))
from dual; 

在上面的例子中,前两列(在sessiontimezone之后)应该是2009年,最后两列应该是2010年。虽然这一切都是通过实验找到的,所以你的里程可能会有所不同。

答案 1 :(得分:1)

@MikeyByCrikey发布了一个很好的起点,但在将字符串值转换为日期之前,您需要回答几个问题:

一个。什么日期用'0'表示?也就是说,这个毫秒计数值从哪里开始?在@ Mikey的例子中,使用了1970年1月1日的Unix“开始”日期(也称为“纪元日期”),但是您的帖子中没有足够的信息来了解“0”日期究竟是什么。其他系统使用不同的纪元日期。例如,在运行VMS操作系统的系统上,纪元日期是1858年11月17日(恰好是Julian day 2,400,000); Windows(32位和64位版本)使用01年1月1 - 1601年(400年公历周期的第一年,这是该操作系统设计时的当前版本);和其他计算机系统使用不同的'0'日期。

B中。将字符串转换为Oracle中的数字非常简单。我只使用TO_NUMBER函数,如:

  strMillisecs   VARCHAR2(100) := '1230748200000';
  nMilliseconds  NUMBER;

  nMilliseconds := TO_NUMBER(strMillisecs);

℃。一旦你到达这一点(已知'0'日期,并将字符串转换为数字),可以按如下方式提取年份:

  dtEpoch_date         DATE := TO_DATE('01-JAN-1970', 'DD-MON-YYYY');  -- for example
  strMillisecs         VARCHAR2(100) := '1230748200000';
  nMilliseconds        NUMBER;
  dtTarget_date        DATE;
  nYear                NUMBER;
  nMillisecs_in_a_day  NUMBER := 86400000;

  nMilliseconds := TO_NUMBER(strMillisecs);

  -- Note: there are 

  dtTarget_date := dtEpoch_date + (nMilliseconds / nMillisecs_in_a_day);

  -- FINALLY!

  nYear := TO_NUMBER(TO_CHAR(dtTarget_date, 'YYYY'));

希望这很有用。

分享并享受。

答案 2 :(得分:1)

我们希望将存储在数据库中的长值转换为中心时区的TIMESTAMP值。

这很有用。

select FROM_TZ(
    TO_TIMESTAMP('1970-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS') + 
    NUMTODSINTERVAL( 1386655200000/1000,'SECOND'), 
    'UTC') at time zone 'America/Chicago' 
from dual

其中1386655200000是2013年12月10日中央时区的java.util.Date的毫秒值。