Oracle时间戳到BST时间转换

时间:2017-01-25 14:19:09

标签: java oracle date timezone jodatime

我知道有很多关于时间转换的不同教程,但这个让我很困惑。我的任务是从Oracle DB读取UTC DATE并将其转换为BST时间(以更易读的格式)。

事实:

  • 数据库中的字段为DATE类型。
  • 当我执行SELECT查询时,会返回2011-07-12 15:26:07结果。
  • 我位于波兰,因此7月TimeZone在UTC+2

发生了什么:

在Java方面,我正在使用与数据库的“经典”JDBC连接。

当我执行Timestamp timestampDate = resultSet.getTimestamp(COLUMN_NAME)时,我得到了结果......但是......

System.out.println(timestampDate)打印到控制台2011-07-12 15:26:07.0(这与我在数据库工具中看到的类似。

System.out.println(timestampDate.getTime());打印到控制台1310477167000(这很奇怪,因为根据我在网上找到的ms to date转换器,它基本上是2011-07-12 13:26:07.0(2小时前 - 不知怎的可能与该日的波兰时区有关)

根据此代码执行转换时:

ukDateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); ukDateFormatter.setTimeZone(TimeZone.getTimeZone("BST")); return ukDateFormatter.format(timestampDate.getTime());

我得到的2011-07-12 19:26:07我无法解释。

我也在尝试这个

GregorianCalendar calendar = new GregorianCalendar(); calendar.setTime(timestampDate); calendar.setTimeZone(TimeZone.getTimeZone("BST")); return ukDateFormatter.format(calendar.getTime());

具有相同的结果。

问题

如何以“timezone agnostic”格式从Oracle DB正确读取DATE并将其转换为BST?

3 个答案:

答案 0 :(得分:1)

这是在数据库方面做到这一点的一种方式:

    sys_language_mode = content_fallback

第四列(with dates as (select to_date('01/07/2016 10:39:29', 'dd/mm/yyyy hh24:mi:ss') dt from dual union all select to_date('01/02/2016 09:18:41', 'dd/mm/yyyy hh24:mi:ss') dt from dual) select dt, cast(dt AS TIMESTAMP) utc_dt_ts, from_tz(cast(dt AS TIMESTAMP), 'UTC') AT time zone 'Europe/London' dt_as_ts_bst, cast(from_tz(cast(dt AS TIMESTAMP), 'UTC') AT time zone 'Europe/London' AS DATE) dt_at_bst from dates; DT UTC_DT_TS DT_AS_TS_BST DT_AT_BST ------------------- ------------------------------------------------- ------------------------------------------------- ------------------- 01/07/2016 10:39:29 01-JUL-16 10.39.29.000000 01-JUL-16 11.39.29.000000 EUROPE/LONDON 01/07/2016 11:39:29 01/02/2016 09:18:41 01-FEB-16 09.18.41.000000 01-FEB-16 09.18.41.000000 EUROPE/LONDON 01/02/2016 09:18:41 )是显示如何在BST上将日期转换为另一个日期的列。它通过首先将日期作为时间戳投射,然后告诉Oracle将其视为UTC的时间戳并输出“欧洲/伦敦”的时间戳来实现此目的。区域。指定这样的区域(而不是传递特定的+01:00时区)意味着结果时间戳将是夏令时识别。不建议将该区域指定为三个字母的快捷方式,因为这可能代表多个区域 - 例如BST可以是英国夏令时或白令标准时间;两者截然不同!

我假设dt_at_bst你的意思是BST,所以我已将时区的区域指定为British Summer Time。如果您需要不同的时区,则需要根据需要进行调整。

我在样本数据中加入了冬季和夏季日期,以向您展示将其投入BST的效果 - 夏季时间有望改变,而冬季时间则没有。

答案 1 :(得分:0)

实际上它不是关于Oracle,而是关于Java的更多信息。 首先:  当你使用

System.out.println(timestampDate)

在输出中,您会看到已经调整到计算机时区的时间。

使用Date(即

)时始终会对其进行调整

Calendar.getTime()Timestamp.getTime()

使用的代码:

    SimpleDateFormat dtFmt = new SimpleDateFormat("HH:mm:ss");
    NumberFormat nFmt = NumberFormat.getIntegerInstance();
    nFmt.setMinimumIntegerDigits(2);
    long currentTimeMs = System.currentTimeMillis();

    GregorianCalendar utcCalendar = new GregorianCalendar(
            TimeZone.getTimeZone("UTC"));

    GregorianCalendar bstCalendar = new GregorianCalendar(
            TimeZone.getTimeZone("Europe/London"));

    GregorianCalendar localCalendar = new GregorianCalendar();

    utcCalendar.setTimeInMillis(currentTimeMs);
    bstCalendar.setTimeInMillis(currentTimeMs);
    localCalendar.setTimeInMillis(currentTimeMs);

    System.out.println("---- milliseconds ----");
    System.out.println("Current ms       : " + currentTimeMs);
    System.out.println("Local Calendar ms: " + localCalendar.getTimeInMillis());
    System.out.println("UTC Calendar   ms: " + utcCalendar.getTimeInMillis());
    System.out.println("BST Calendar   ms: " + bstCalendar.getTimeInMillis());

    System.out.println("---- SimpleFormat Time ----");
    System.out.println("Current Time: "
            + dtFmt.format(new Date(currentTimeMs)));
    System.out.println("Local Time: " + dtFmt.format(localCalendar.getTime()));
    System.out.println("UTC Time  : " + dtFmt.format(utcCalendar.getTime()));
    System.out.println("BST Time  : " + dtFmt.format(bstCalendar.getTime()));

    System.out.println("---- Calendar Zone Time ----");
    System.out.println("Local Zone Time: "
            + nFmt.format(localCalendar.get(Calendar.HOUR_OF_DAY)) + ":"
            + nFmt.format(localCalendar.get(Calendar.MINUTE)) + ":"
            + nFmt.format(localCalendar.get(Calendar.SECOND)));

    System.out.println("UTC Zone Time  : "
            + nFmt.format(utcCalendar.get(Calendar.HOUR_OF_DAY)) + ":"
            + nFmt.format(utcCalendar.get(Calendar.MINUTE)) + ":"
            + nFmt.format(utcCalendar.get(Calendar.SECOND)));

    System.out.println("BST Zone Time  : "
            + nFmt.format(bstCalendar.get(Calendar.HOUR_OF_DAY)) + ":"
            + nFmt.format(bstCalendar.get(Calendar.MINUTE)) + ":"
            + nFmt.format(bstCalendar.get(Calendar.SECOND)));

}

正如您将看到每个日历根据其TimeZone返回时间字段(HOUR_OF_DAY, MINUTE, SECOND),而不是您从Calendar.getTime()打印或格式化的内容

答案 2 :(得分:0)

我做了什么,似乎对我有用:

ukDateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); ukDateFormatter.setTimeZone(TimeZone.getTimeZone("Europe/London"));

并表演:

Timestamp timestampDate = rs.getTimestamp(...); DateTime dateTime = new DateTime(timestampDate).withZoneRetainFields(DateTimeZone.UTC); System.out.println(ukDateFormatter.format(dateTime.getMillis()));

打印:

来自输入2011-07-12 16:26:07

2011-07-12 15:26:07

为什么会在这里发生?

这里有什么问题,是rs.getTimestamp(...)从数据库“按原样”返回日期(因为DATE列类型不会隐式保留时区)但是添加了一些信息关于我当地的时区 - 我不想要。

最简单的解决方案是使用joda并创建新对象,保留值,但将时区更改为UTC。从那时起,使用SimpleDateFormat进行转换非常简单。