Reputation: 220
I'm trying to retrieve the datetime value from my database and I have declared the upload_date_time to be Instant and this is how the value is stored in database.
However, when I attempted to retrieve the value from the database it is giving me '2022-03-01T14:00:00Z'.
UploadOrder Table
@NotNull
@Column(name = "upload_date_time", nullable = false)
private Instant uploadDateTime;
public Instant getUploadDateTime() {
return uploadDateTime;
}
public UploadOrder uploadDateTime(Instant uploadDateTime) {
this.uploadDateTime= uploadDateTime;
return this;
}
public void setUploadDateTime(Instant uploadDateTime) {
this.uploadDateTime= uploadDateTime;
}
Service
public PrePickOrderOverPickEmailDTO generateOverPickEmails() {
log.debug("Request to retrieve Upload data : {}");
List<UploadOrder> uploadOrders = uploadPickRepository.findAllByEmailSent(false);
String data = "";
for (UploadOrder order : uploadOrders) {
data = data +
"Upload Date: " + order.getUploadDateTime() +"\n" +
// do others
}
}
Curious to know what am I doing wrong here. Any help would be great. Thanks
Upvotes: 1
Views: 124
Reputation: 339472
The Tag on your Question indicates you are using Microsoft SQL Server as your database engine.
According to the doc, you should be defining your column as the data type datetimeoffset
. That type is akin to the SQL standard type TIMESTAMP WITH TIME ZONE
which stores a moment.
Do not use the types smalldatetime
, datetime
, nor datetime2
. These lack the context of a time zone or offset-from-UTC. So these cannot represent a moment, a specific point on the time line.
👉 Given your code snippets using the name uploadDateTime
, your business logic requires tracking a moment. So your table column must be of type datetimeoffset
.
Your first sentence says:
I'm trying to retrieve the datetime value
If you mean literally, datetime
type in Microsoft SQL Server, you are using the wrong type for your column. This will cause you confusion and trouble.
OffsetDateTime
While you neglected to mention what framework library you are using with your @Column
annotation. So I cannot say with certainty, but I can guess that Instant
is the wrong Java class to use here.
The JDBC specification for JDBC 4.2 and later requires JDBC drivers to support the java.time classes. The spec maps values of the SQL standard type TIMESTAMP WITH TIME ZONE
to the Java class java.time.OffsetDateTime
. The Java class Instant
is not mapped at all in JDBC.
After retrieving an OffsetDateTime
, you can extract an Instant
if needed: Instant instant = myOffsetDateTime.toInstant() ;
.
Upvotes: -1
Reputation:
Since you commented your database timezone is UTC+10:00, then what you are seeing is correct.
2022-03-02T00:00+10:00
is the same date as 2022-03-01T14:00:00Z
, Z is UTC(+0), so they both represent the same date value, just represented with different time zones.
You can verify this by:
jshell> java.time.OffsetDateTime.parse("2022-03-02T00:00+10:00").toInstant()
$4 ==> 2022-03-01T14:00:00Z
To localize the UTC instant to a different zone, you can use Instant::atZone()
or Instant::atOffset()
.
Upvotes: 3
Reputation: 79877
An Instant
is a moment in time, without any time zone being specified. And the Instant
that you're actually storing is 2pm on 1 March UTC, which is the same as midnight on 2 March AEST.
When you're looking at this value through your SQL client, the SQL client is translating it to your local time, so you're seeing midnight on 2 March.
When you're retrieving it with your Java program, you're displaying it without specifying a time zone or time offset. When you do that to an Instant
, you get to see it in UTC.
What you actually want to do is convert the Instant
to a LocalDateTime
before you display it - that way, you'll be able to see it in AEST, or whatever your local time zone happens to be. The LocalDateTime
class has a static
method called ofInstant
, which will do that. You need to pass the ZoneId
for your timezone, like this.
LocalDateTime timeInBrisbane = LocalDateTime.ofInstant(uploadDateTime, ZoneId.of("Australia/Brisbane"));
or even like this, to get the system default time zone.
LocalDateTime timeInDefaultZone = LocalDateTime.ofInstant(uploadDateTime, ZoneId.systemDefault());
Upvotes: -1