Oracle 时间戳到 BST 时间转换
Oracle Timestamp to BST time conversion
我知道有很多关于时间转换的不同教程,但是这个让我很困惑。我的任务是从 Oracle DB 读取 UTC DATE 并将其转换为 BST 时间(以更易于阅读的格式)。
事实:
- 数据库中的字段是
DATE
类型。
- 当我执行
SELECT
查询时 returns 2011-07-12 15:26:07
结果。
- 我位于波兰,因此在 7 月,这里的时区是
UTC+2
发生了什么:
在 Java 方面,我正在使用 "classical" JDBC 连接到数据库。
当我执行 Timestamp timestampDate = resultSet.getTimestamp(COLUMN_NAME)
时,我得到了结果......但是......
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 = 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());
同样的结果。
问题
如何从 Oracle DB 中正确读取 "timezone agnostic" 格式的 DATE 并将其转换为 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 时间戳并输出 'Europe/London' 区域的时间戳。像这样指定区域(而不是传递特定的 +01:00 时区)意味着生成的时间戳将具有夏令时意识。不建议将区域指定为三个字母的快捷方式,因为这可能代表多个区域 - 例如BST 可以是英国夏令时间或白令标准时间;两者截然不同!
我假设 BST
你的意思是 British Summer Time
,所以我将要移动到的时间戳的区域指定为 Europe/London
。如果您需要不同的时区,则需要根据需要进行调整。
我在我的示例数据中包含了一个冬季和一个夏季日期,以向您展示将其转换为 BST 的效果 - 夏季时间预计会发生变化,而冬季时间不会。
其实不是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)));
}
您将看到每个日历 returns 时间字段 (HOUR_OF_DAY, MINUTE, SECOND
) 根据其时区,而不是您从 Calendar.getTime()
)
打印或格式化的内容
我做了什么,它似乎对我有用:
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(...)
从数据库 "as it is" 返回日期(因为 DATE
列类型不保留时区)隐含地添加关于我当地时区的一些信息——我不想要这些信息。
最简单的解决方案是使用 joda
并创建新对象,保留值,但将时区更改为 UTC
。从那时起,使用 SimpleDateFormat
的转换非常简单。
我知道有很多关于时间转换的不同教程,但是这个让我很困惑。我的任务是从 Oracle DB 读取 UTC DATE 并将其转换为 BST 时间(以更易于阅读的格式)。
事实:
- 数据库中的字段是
DATE
类型。 - 当我执行
SELECT
查询时 returns2011-07-12 15:26:07
结果。 - 我位于波兰,因此在 7 月,这里的时区是
UTC+2
发生了什么:
在 Java 方面,我正在使用 "classical" JDBC 连接到数据库。
当我执行 Timestamp timestampDate = resultSet.getTimestamp(COLUMN_NAME)
时,我得到了结果......但是......
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 = 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());
同样的结果。
问题
如何从 Oracle DB 中正确读取 "timezone agnostic" 格式的 DATE 并将其转换为 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 时间戳并输出 'Europe/London' 区域的时间戳。像这样指定区域(而不是传递特定的 +01:00 时区)意味着生成的时间戳将具有夏令时意识。不建议将区域指定为三个字母的快捷方式,因为这可能代表多个区域 - 例如BST 可以是英国夏令时间或白令标准时间;两者截然不同!
我假设 BST
你的意思是 British Summer Time
,所以我将要移动到的时间戳的区域指定为 Europe/London
。如果您需要不同的时区,则需要根据需要进行调整。
我在我的示例数据中包含了一个冬季和一个夏季日期,以向您展示将其转换为 BST 的效果 - 夏季时间预计会发生变化,而冬季时间不会。
其实不是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)));
}
您将看到每个日历 returns 时间字段 (HOUR_OF_DAY, MINUTE, SECOND
) 根据其时区,而不是您从 Calendar.getTime()
)
我做了什么,它似乎对我有用:
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(...)
从数据库 "as it is" 返回日期(因为 DATE
列类型不保留时区)隐含地添加关于我当地时区的一些信息——我不想要这些信息。
最简单的解决方案是使用 joda
并创建新对象,保留值,但将时区更改为 UTC
。从那时起,使用 SimpleDateFormat
的转换非常简单。