如何在 Oracle 的 TIMESTAMPTZ 中存储 java 的 ZonedDateTime?
How to store ZonedDateTime of java in TIMESTAMPTZ in oracle?
我想将 ZonedDateTime 存储在 Oracle 中的 TIMESTAMP WITH TIME ZONE 数据类型中。
如果我试图将字符串直接存储为字符串,它会抛出无效月份。
然后我发现我可以将它转换为 java 中的 TIMESTAMPTZ 然后存储,因为我们需要将字符串转换为 TIMESTAMPTZ 及其抛出错误。
String d = "2021-10-28 02:36:08.000000 +02:00";
TIMESTAMPTZ t = new TIMESTAMPTZ(con, d);
PreparedStatement ps = con.prepareStatement(query);
ps.setObject(1,t);
Error/stack 追踪:
Exception in thread "main" java.lang.IllegalArgumentException: Timestamp format must be yyyy-mm-dd hh:mm:ss[.fffffffff]
at java.sql.Timestamp.valueOf(Timestamp.java:251)
at oracle.sql.TIMESTAMPTZ.toBytes(TIMESTAMPTZ.java:1919)
at oracle.sql.TIMESTAMPTZ.<init>(TIMESTAMPTZ.java:253)
at OracleSelectQuery.main(OracleSelectQuery.java:21)
请有人调查一下。
java.time
following table 描述了 ANSI SQL 类型与 java.time
类型的映射:
ANSI SQL
Java SE 8
DATE
LocalDate
TIME
LocalTime
TIMESTAMP
LocalDateTime
TIME WITH TIMEZONE
OffsetTime
TIMESTAMP WITH TIMEZONE
OffsetDateTime
将给定的日期时间字符串解析为OffsetDateTime
,如下所示:
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSSSSS XXX", Locale.ENGLISH);
String strDateTime = "2021-10-28 02:36:08.000000 +02:00";
OffsetDateTime odt = OffsetDateTime.parse(strDateTime, dtf);
System.out.println(odt);
}
}
输出:
2021-10-28T02:36:08+02:00
现在,您可以将此 OffsetDateTime
存储到数据库中,如下所示:
PreparedStatement st = conn.prepareStatement("INSERT INTO mytable (columnfoo) VALUES (?)");
st.setObject(1, odt);
st.executeUpdate();
st.close();
详细了解 modern Date-Time API* from Trail: Date Time。
* 如果您正在为 Android 项目工作,并且您的 Android API 级别仍然不符合 Java-8,请检查Java 8+ APIs available through desugaring. Note that Android 8.0 Oreo already provides support for java.time
。
三参数 TIMESTAMPTZ(Connection, Timestamp, ZoneId) 构造函数
根据 Oracle TIMESTAMPTZ
class(底部的 link)的文档,它有一个构造函数,除了连接需要一个 java.sql.Timestamp
和a java.time.ZoneId
作为参数(过时的和现代的 Java class 的有趣混合体)。由于我们可以从您的字符串中提取 ZoneOffset
并且 ZoneOffset
是 ZoneId
的子 class,因此我们可以将此构造函数用于您的目的:
String d = "2021-10-28 02:36:08.000000 +02:00";
OffsetDateTime odt = OffsetDateTime.parse(d, PARSER);
Instant inst = odt.toInstant();
ZoneId offsetAsZoneId = odt.getOffset();
TIMESTAMPTZ t = new TIMESTAMPTZ(con, Timestamp.from(inst), offsetAsZoneId);
我使用这个格式化程序进行解析:
private static final DateTimeFormatter PARSER = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE)
.appendLiteral(' ')
.append(DateTimeFormatter.ISO_LOCAL_TIME)
.appendLiteral(' ')
.appendOffsetId()
.toFormatter(Locale.ROOT);
您还可以将时区保存到 Oracle
我使用的构造函数接受 ZoneId
开启了额外的可能性,我们可以将 Europe/Paris 或 Asia/Kolkata 之类的实时时区 ID 存储到数据库中,而不仅仅是一个裸体UTC 偏移量。至少我阅读 Oracle 数据库文档的方式是,它的 timestamp with time zone
数据类型可以包含时区 ID。文档中给出的例子是America/Los_Angeles.
有关将 ZonedDateTime
转换为 TIMESTAMPTZ
的简单示例:
ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Asia/Kolkata"));
Instant inst = zdt.toInstant();
ZoneId zid = zdt.getZone();
TIMESTAMPTZ t = new TIMESTAMPTZ(con , Timestamp.from(inst), zid);
链接
- Documentation of
TIMESTAMPTZ
and its TIMESTAMPTZ(Connection, Timestamp, ZoneId
)构造函数。
- Oracle 数据库日期时间数据类型和时区支持 帮助,第 Datetime and Interval Data Types 部分。向下滚动到 TIMESTAMP WITH TIME ZONE 数据类型。
我想将 ZonedDateTime 存储在 Oracle 中的 TIMESTAMP WITH TIME ZONE 数据类型中。 如果我试图将字符串直接存储为字符串,它会抛出无效月份。 然后我发现我可以将它转换为 java 中的 TIMESTAMPTZ 然后存储,因为我们需要将字符串转换为 TIMESTAMPTZ 及其抛出错误。
String d = "2021-10-28 02:36:08.000000 +02:00";
TIMESTAMPTZ t = new TIMESTAMPTZ(con, d);
PreparedStatement ps = con.prepareStatement(query);
ps.setObject(1,t);
Error/stack 追踪:
Exception in thread "main" java.lang.IllegalArgumentException: Timestamp format must be yyyy-mm-dd hh:mm:ss[.fffffffff] at java.sql.Timestamp.valueOf(Timestamp.java:251) at oracle.sql.TIMESTAMPTZ.toBytes(TIMESTAMPTZ.java:1919) at oracle.sql.TIMESTAMPTZ.<init>(TIMESTAMPTZ.java:253) at OracleSelectQuery.main(OracleSelectQuery.java:21)
请有人调查一下。
java.time
following table 描述了 ANSI SQL 类型与 java.time
类型的映射:
ANSI SQL | Java SE 8 |
---|---|
DATE | LocalDate |
TIME | LocalTime |
TIMESTAMP | LocalDateTime |
TIME WITH TIMEZONE | OffsetTime |
TIMESTAMP WITH TIMEZONE | OffsetDateTime |
将给定的日期时间字符串解析为OffsetDateTime
,如下所示:
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSSSSS XXX", Locale.ENGLISH);
String strDateTime = "2021-10-28 02:36:08.000000 +02:00";
OffsetDateTime odt = OffsetDateTime.parse(strDateTime, dtf);
System.out.println(odt);
}
}
输出:
2021-10-28T02:36:08+02:00
现在,您可以将此 OffsetDateTime
存储到数据库中,如下所示:
PreparedStatement st = conn.prepareStatement("INSERT INTO mytable (columnfoo) VALUES (?)");
st.setObject(1, odt);
st.executeUpdate();
st.close();
详细了解 modern Date-Time API* from Trail: Date Time。
* 如果您正在为 Android 项目工作,并且您的 Android API 级别仍然不符合 Java-8,请检查Java 8+ APIs available through desugaring. Note that Android 8.0 Oreo already provides support for java.time
。
三参数 TIMESTAMPTZ(Connection, Timestamp, ZoneId) 构造函数
根据 Oracle TIMESTAMPTZ
class(底部的 link)的文档,它有一个构造函数,除了连接需要一个 java.sql.Timestamp
和a java.time.ZoneId
作为参数(过时的和现代的 Java class 的有趣混合体)。由于我们可以从您的字符串中提取 ZoneOffset
并且 ZoneOffset
是 ZoneId
的子 class,因此我们可以将此构造函数用于您的目的:
String d = "2021-10-28 02:36:08.000000 +02:00";
OffsetDateTime odt = OffsetDateTime.parse(d, PARSER);
Instant inst = odt.toInstant();
ZoneId offsetAsZoneId = odt.getOffset();
TIMESTAMPTZ t = new TIMESTAMPTZ(con, Timestamp.from(inst), offsetAsZoneId);
我使用这个格式化程序进行解析:
private static final DateTimeFormatter PARSER = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE)
.appendLiteral(' ')
.append(DateTimeFormatter.ISO_LOCAL_TIME)
.appendLiteral(' ')
.appendOffsetId()
.toFormatter(Locale.ROOT);
您还可以将时区保存到 Oracle
我使用的构造函数接受 ZoneId
开启了额外的可能性,我们可以将 Europe/Paris 或 Asia/Kolkata 之类的实时时区 ID 存储到数据库中,而不仅仅是一个裸体UTC 偏移量。至少我阅读 Oracle 数据库文档的方式是,它的 timestamp with time zone
数据类型可以包含时区 ID。文档中给出的例子是America/Los_Angeles.
有关将 ZonedDateTime
转换为 TIMESTAMPTZ
的简单示例:
ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Asia/Kolkata"));
Instant inst = zdt.toInstant();
ZoneId zid = zdt.getZone();
TIMESTAMPTZ t = new TIMESTAMPTZ(con , Timestamp.from(inst), zid);
链接
- Documentation of
TIMESTAMPTZ
and itsTIMESTAMPTZ(Connection, Timestamp, ZoneId
)构造函数。 - Oracle 数据库日期时间数据类型和时区支持 帮助,第 Datetime and Interval Data Types 部分。向下滚动到 TIMESTAMP WITH TIME ZONE 数据类型。