I want to store the ZonedDateTime in TIMESTAMP WITH TIME ZONE datatype in oracle. If I am trying to store string directly as a String it throws not a valid month. then I found that I can convert it to the TIMESTAMPTZ in java then store because we need to convert the string to TIMESTAMPTZ and its throwing error.
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 trace:
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)
Someone please look into this.
CodePudding user response:
java.time
The following table depicts the mapping of ANSI SQL types with java.time
types:
ANSI SQL | Java SE 8 |
---|---|
DATE | LocalDate |
TIME | LocalTime |
TIMESTAMP | LocalDateTime |
TIME WITH TIMEZONE | OffsetTime |
TIMESTAMP WITH TIMEZONE | OffsetDateTime |
Parse the given Date-Time string into OffsetDateTime
as shown below:
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);
}
}
Output:
2021-10-28T02:36:08 02:00
Now, you can store this OffsetDateTime
into the database as shown below:
PreparedStatement st = conn.prepareStatement("INSERT INTO mytable (columnfoo) VALUES (?)");
st.setObject(1, odt);
st.executeUpdate();
st.close();
Learn more about the modern Date-Time API* from Trail: Date Time.
* If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8 APIs available through desugaring. Note that Android 8.0 Oreo already provides support for java.time
.
CodePudding user response:
The three-arg TIMESTAMPTZ(Connection, Timestamp, ZoneId) constructor
According to the documentation of the Oracle TIMESTAMPTZ
class (link at the bottom) it has a constructor that in addition to the connection takes a java.sql.Timestamp
and a java.time.ZoneId
as arguments (a funny mixture of an outdated and a modern Java class). Since we can extract a ZoneOffset
from your string and ZoneOffset
is a subclass of ZoneId
, we can use this constructor for your purpose:
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);
I used this formatter for parsing:
private static final DateTimeFormatter PARSER = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE)
.appendLiteral(' ')
.append(DateTimeFormatter.ISO_LOCAL_TIME)
.appendLiteral(' ')
.appendOffsetId()
.toFormatter(Locale.ROOT);
You may also save a time zone to Oracle
That the constructor I used accepts a ZoneId
opens the additional possibility that we may store a real time zone ID like Europe/Paris or Asia/Kolkata to the database rather than just a naked UTC offset. At least the way I read the Oracle database documentation, its timestamp with time zone
data type can hold a time zone ID. The example given in the documentation is America/Los_Angeles.
Links
- Documentation of
TIMESTAMPTZ
and itsTIMESTAMPTZ(Connection, Timestamp, ZoneId
) constructor. - Oracle database Datetime Data Types and Time Zone Support help, section Datetime and Interval Data Types. Scroll down to TIMESTAMP WITH TIME ZONE Data Type.