Java Oracle时间戳到BST时间转换

Java Oracle时间戳到BST时间转换,java,oracle,date,timezone,jodatime,Java,Oracle,Date,Timezone,Jodatime,我知道有很多关于时间转换的教程,但是这一个让我很困惑。我的任务是从OracleDB读取UTC日期,并将其转换为BST时间(以更易于阅读的格式) 事实: 数据库中的字段为DATE类型 当我执行SELECTquery时,它返回2011-07-12 15:26:07result 我位于波兰,因此7月份这里的时区为UTC+2 发生了什么: 在Java方面,我使用“经典”JDBC连接到数据库 当我执行Timestamp Timestamp date=resultSet.getTimestamp(列名)

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

事实:

  • 数据库中的字段为
    DATE
    类型
  • 当我执行
    SELECT
    query时,它返回
    2011-07-12 15:26:07
    result
  • 我位于波兰,因此7月份这里的时区为
    UTC+2
发生了什么:

在Java方面,我使用“经典”JDBC连接到数据库

当我执行
Timestamp Timestamp date=resultSet.getTimestamp(列名)
时,我得到了结果。。。但是

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

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

当我根据此代码执行转换时:

ukDateFormatter=新的SimpleDateFormat(“yyyy-MM-dd-HH:MM:ss”);
setTimeZone(TimeZone.getTimeZone(“BST”));
返回ukDateFormatter.format(timestampDate.getTime());

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

我也试过这个

GregorianCalendar日历=新的GregorianCalendar();
calendar.setTime(时间戳日期);
calendar.setTimeZone(TimeZone.getTimeZone(“BST”));
返回ukDateFormatter.format(calendar.getTime());

同样的结果

问题


如何正确地以“时区不可知”格式从Oracle DB读取日期并将其转换为BST?

以下是在数据库端执行此操作的一种方法:

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
第四列(
dt_at_bst
)显示了如何在bst将日期转换为另一个日期。它首先将日期转换为时间戳,然后告诉Oracle在UTC将其视为时间戳,并输出“欧洲/伦敦”区域的时间戳。如下指定区域(而不是传递特定的+01:00时区)意味着生成的时间戳将支持夏令时。不建议将区域指定为三个字母的快捷方式,因为这可能代表多个区域-例如,英国夏令时可以是英国夏令时或白令标准时;这两种情况完全不同

我假设英国夏令时的
BST
指的是
英国夏季时间
,因此我已将时间戳移动到的区域指定为
欧洲/伦敦
。如果您需要不同的时区,您需要对其进行适当调整


我在示例数据中包含了冬季和夏季日期,以向您展示将其转换为BST的效果—夏季时间预计会发生变化,而冬季时间则不会发生变化。

事实上,这与Oracle无关,更多的是与Java有关。 首先: 当你使用

System.out.println(timestampDate)
在输出中,您可以看到已将时间调整到计算机时区

当您使用
日期
(即

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)));

}

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

我做了什么,它似乎在为我工作:

ukDateFormatter=新的SimpleDateFormat(“yyyy-MM-dd-HH:MM:ss”);
ukDateFormatter.setTimeZone(TimeZone.getTimeZone(“欧洲/伦敦”);

以及表演:

Timestamp Timestamp date=rs.getTimestamp(…);
DateTime DateTime=new
DateTime(timestampDate).WithZoneReainFields(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
转换非常简单。

我感到困惑。如果数据库中的字段(实际上是“列”)是
DATE
数据类型,那么通常情况下,这不是“UTC日期”。Oracle中的
DATE
数据类型没有附加时区。如果您位于波兰,请输入
插入到表中(日期列)值(截止日期('2015-12-11 10:00:00',yyyy-mm dd hh24:mi:ss))
输入到您的数据库中,我在美国也这样做,这是为我们两人存储的日期,它将是一个没有时区的日期。请澄清您的意思;当您阅读
日期时,您如何确定它真正属于哪个时区?让我们假设,该日期列没有附加时区:-那么为什么在Java中读入
时间戳
并执行
getTime
我得到了一个令人困惑的结果?-因此,根据您所说的,我应该能够从DB中读取日期并使用日历进行简单的转换…但不知怎的,我无法以如此简单的方式进行转换。注意-Java将解释
“BST”“
就像你说的是“孟加拉国标准时间”。它字面上把它映射到
“亚洲/达卡”
。不要使用时区缩写