Saving date in UTC in Oracle Timestamp column - spring

I have a requirement to save the current UTC date with time in an Oracle column of type TIMESTAMP WITH TIMEZONE. this is from a Spring Boot service with JPA and Hibernate
I have enabled the following in my application yml
jpa:
hibernate:
ddl-auto: none
show-sql: true
properties:
hibernate:
dialect: org.hibernate.dialect.Oracle12cDialect
jdbc:
time_zone: UTC
and the Entity class field looks like
#Column(name = "last_user_edit_date", columnDefinition = "TIMESTAMP WITH TIME ZONE")
#JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ")
private ZonedDateTime lastUserEditDate;
While setting date I am using
obj.setLastUserEditDate(ZonedDateTime.of(LocalDateTime.now(), ZoneId.of("UTC")));
The above is working fine with respect to the actual date value. The only problem is in the database it is saving the UTC time but mentions MST (my local timezone) as the timezone. For eg a value saved is
12-SEP-19 09.50.53.820000000 PM AMERICA/DENVER
Here the 9.50 PM is actually the UTC time but the timezone comes as AMERICA/DENVER. What i want is
12-SEP-19 09.50.53.820000000 PM UTC
How can i achieve this Spring JPA and with Java 8 classes?
Thanks

LocalDateTime is the wrong class
The LocalDateTime class is not capable of tracking a moment in time. I cannot imagine a scenario where calling LocalDateTime.now() makes sense. Read the Javadoc before using a class.
Track a moment: Instant, OffsetDateTime, ZonedDateTime
To track a moment, use Instant (always in UTC), OffsetDateTime (a moment with an offset-from-UTC), or ZonedDateTime (a moment as seen in a particular region).
Oddly, JDBC 4.2 requires support for OffsetDateTime yet leaves the most common two classes, Instant & ZonedDateTime, optional.
So, to capture the current moment in UTC for JDBC work:
OffsetDateTime odt = OffsetDateTime.now( ZoneOffset.UTC ) ;
Or the longer:
Instant instant = instant.now() ; // Capture current moment in UTC.
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
Send to database:
myPreparedStatement.setObject( … , odt ) ;
Retrieve from database:
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
JPA
I do not use JPA. But it looks this Question has you covered, JPA Storing OffsetDateTime with ZoneOffset. And see this post, What’s new in JPA 2.2 – Java 8 Date and Time Types.
Other time zones & offsets
only problem is in the database it is saving the UTC time but mentions MST
This documentation for Oracle Database seems to say that TIMESTAMP WITH TIME ZONE type does record the incoming data’s time zone or offset-from-UTC. Some other databases such as Postgres adjust incoming values to UTC (an offset of zero hours-minutes-seconds).
To get UTC, retrieve the OffsetDateTime as seen above, and call toInstant method to produce a Instant object which is always in UTC. Or produce another OffsetDateTime that is definitely in UTC:
OffsetDateTime odtUtc = odt.withOffsetSameInstant​( ZoneOffset.UTC ) ;

Related

Local date time in certain format yyyy-MM-dd-HH.mm.ss.SSSSSS

I am trying to get LocalDateTime in certain format for my spring data jpa entity column.
I am not getting last 3 digits of millis/micros. I am not sure exactly what to call it.
I am always getting 000 for last 3 SSS portion even If I format
final String YYYY_MM_DD_HH_MM_SS_SSSSSS = "yyyy-MM-dd-HH.mm.ss.SSSSSS";
ZonedDateTime zdtAtUtc = ZonedDateTime.now(ZoneId.of("UTC"));
LocalDateTime ldt = zdtAtUtc.toLocalDateTime();
DateTimeFormatter destFormatter = DateTimeFormatter.ofPattern(YYYY_MM_DD_HH_MM_SS_SSSSSS);
System.out.println(zdtAtUtc);
System.out.println(zdtAtUtc.format(destFormatter));
System.out.println(ldt);
Output
2019-07-30T15:23:18.232Z[UTC]
2019-07-30-15.23.18.232000
2019-07-30T15:23:18.232
This is clock precision in Java 8.
If you'll check the code of now() method, it use behind an instant obtained like this:
Instant now = clock.instant();
In Java 8 output for this instant:
2019-08-02T20:44:35.722Z
In later versions:
2019-08-02T20:39:27.343408800Z
So if you need more precision, you need to switch to a newer version of java.

Spring data mongodb: Work with dates, date has 2 hours of difference

I've this document stored in mongo:
{
"_id" : "cpd4-734fc2db-a5b0-4881-b5d7-bf85d894178d",
"expiresAt" : ISODate("2018-10-10T00:00:00Z")
}
In order to get sure, all data is right, I've got first the document and I've log some data:
Reference ref = this.mongoTemplate.findById("cpd4-734fc2db-a5b0-4881-b5d7-bf85d894178d", Reference.class);
LOG.info(ref.getExpiresAt().toString());
LOG.info(Long.toString(ref.getExpiresAt().getTime()));
The result is:
Wed Oct 10 02:00:00 CEST 2018 <<<<<<<<<<<<<<<<<<<
1539129600000
As you can see when I get the object, the expiresAt field is 02:00:00 instead of 00:00:00.
Value in database is expiresAt field is: ISODate("2018-10-10T00:00:00Z")
Any ideas or thoughts welcome for this issue!
This date is in Zulu time (note the 'Z' on the end):
ISODate("2018-10-10T00:00:00Z")
When you do this, specifically the call to .toString(), you are converting the date into a local date string in your time zone, which appears to be Zulu+2:
LOG.info(ref.getExpiresAt().toString());
I usually set my server's time zone to UTC/Zulu/GMT, in order to avoid any automatic timezone conversions happening like this.

net.fortuna.ical4j.model.DateTime to ORACLE date

I have net.fortuna.ical4j.model.DateList which contains
net.fortuna.ical4j.model.Date objects
The output is: 20170522,20170523,20170525
(UTC time zone)
I have to convert it to ORACLE date in SystemDefault timeZone.
I tried to do this:
List<DATE> result = new ArrayList<DATE>
for(Date d : rdates){
result.add(new DATE(new Timestamp(d.getTime()));
}
But oracle date is different as expected.From net.fortuna.ical4j.model.Date 20170522,20170523,20170525 I got 20170521,20170522,20170524 ORACLE DATE.
There is shifting. How can I handle this?
Ical4j Date objects have an underlying timezone that is not defined as part of the formal specification (an implementation quirk).
By default this timezone will be UTC, however you can change this to system default using the following compatibility hint:
net.fortuna.ical4j.timezone.date.floating=true

Java8 Adding Hours To LocalDateTime Not Working

I tried like below, but in both the cases it is showing same time? What i am doing wrong.
LocalDateTime currentTime = LocalDateTime.now(ZoneId.of("UTC"));
Instant instant = currentTime.toInstant(ZoneOffset.UTC);
Date currentDate = Date.from(instant);
System.out.println("Current Date = " + currentDate);
currentTime.plusHours(12);
Instant instant2 = currentTime.toInstant(ZoneOffset.UTC);
Date expiryDate = Date.from(instant2);
System.out.println("After 12 Hours = " + expiryDate);
"Current Date" Time is showing Same as "After 12 Hours"...
The documentation of LocalDateTime specifies the instance of LocalDateTime is immutable, for example plusHours
public LocalDateTime plusHours(long hours)
Returns a copy of this LocalDateTime with the specified number of
hours added.
This instance is immutable and unaffected by this method call.
Parameters:
hours - the hours to add, may be negative
Returns:
a LocalDateTime based on this date-time with the hours added, not null
Throws:
DateTimeException - if the result exceeds the supported date range
So, you create a new instance of LocalDateTime when you execute plus operation, you need to assign this value as follows:
LocalDateTime nextTime = currentTime.plusHours(12);
Instant instant2 = nextTime.toInstant(ZoneOffset.UTC);
Date expiryDate = Date.from(instant2);
System.out.println("After 12 Hours = " + expiryDate);
I hope it can be helpful for you.
From the java.time package Javadoc (emphasis mine):
The classes defined here represent the principal date-time concepts,
including instants, durations, dates, times, time-zones and periods.
They are based on the ISO calendar system, which is the de facto world
calendar following the proleptic Gregorian rules. All the classes are
immutable and thread-safe.
Since every class in the java.time package is immutable, you need to capture the result:
LocalDateTime after = currentTime.plusHours(12);
...
This is simple, you can use
LocalDateTime's method "plusHours(numberOfHours)
Like This
localDateTime.plusHours(numberOfHours);

How to getHourOfDay from a timestamp using java.time?

From a java.util.Date( a timestamp), how can I get the hour of day?
In joda.time I use getHourOfDay().
There are multiple solutions for this. If you wish to use the Java 8 classes from java.time the following you need to covert a Date to one of the DateTime classes. The following can be used to convert a Date to a ZonedDateTime where you then can get the hour:
Date date = new Date();
// Convert to java 8 ZonedDateTime
Date date = new Date();
final ZonedDateTime dateTime = date.toInstant()
.atZone(ZoneId.systemDefault());
// Get the hour
int hour = dateTime.getHour();
Quite verbose as you have noticed but the simple reason for this is that a Date is sort of an Instant
Despite its name, java.util.Date represents an instant on the time-line, not a "date". The actual data stored within the object is a long count of milliseconds since 1970-01-01T00:00Z (midnight at the start of 1970 GMT/UTC).
Another approach is simply to get the field from a Calendar instance.
final Calendar instance = Calendar.getInstance();
instance.setTime(date);
final int hourOfDay = instance.get(Calendar.HOUR_OF_DAY);

Resources