-1

I'm trying to get java.util.Calendar date field as following.

This is the DTO.

import java.util.Calendar;
public class ImportExportProgressDTO {
    private Calendar prolongedDate;
}
public void update(ImportExportProgressDTO importExportProgressDTO){
System.out.println(importExportProgressDTO.getProlongedDate().getTime());
}
  • 2024-04-09 11:50:54—This is the value in the payload. At this moment user did some actions on the UI, so this API capture.
  • Mon Oct 15 11:50:54 UTC 14—This value is getting reflected in back end console.
21
  • 2
    private Calendar prolongedDate; You definitely need to change that. That outdated class can open up a whole world of problems. You seem to be treating it as an instant, so use java.time.Instant or ZonedDateTime Commented Apr 9, 2024 at 12:21
  • 1
    Your problem is likely caused by the column type beingREAL (Sqlite has no datetime types) which stores Julian day numbers Commented Apr 9, 2024 at 13:19
  • 1
    Actually the way to go to get the best and finest grained result is to store Instant::toString in a char type column, storing the timezone in another one Commented Apr 9, 2024 at 14:41
  • 1
    What are the limitations that tie you to Calendar? Asking both because you should never use that class and because I just can’t imagine. If some other developer or team has control over the ImportExportProgressDTO class, could you at least ask them kindly to add a method that returns the date as a ZonedDateTime, an Instant or some other meaningful modern type? Commented Apr 9, 2024 at 17:00
  • 1
    A minimal reproducible example would probably help. Commented Apr 9, 2024 at 17:05

1 Answer 1

1

private Calendar prolongedDate;

Never use the terribly flawed java.util.Calendar class. That class, like both Date classes and java.sql.Timestamp, is legacy. These classes were years ago supplanted by the modern java.time classes defined in JSR 310.

As a DTO used with database access, that type should be java.time.OffsetDateTime if representing a moment, a specific point on the timeline.

The database column should be of a type akin to the SQL standard type TIMESTAMP WITH TIME ZONE.

preparedStatement.setString(parameterIndex++, LocalDateTime.ofInstant(importExportProgressDTO.getProlongedDate().toInstant(), ZoneId.of("Asia/Kolkata")).toString());

That is an ugly mess of date-time code.

LocalDateTime

If you are representing a moment, a point on the timeline, then no LocalDateTime should be involved. That class represents a date with time but lacks the context of a time zone or offset-from-UTC. So this class cannot represent a moment. Such values are inherently ambiguous. Is 2023-01-23T12:00 noon in Tokyo Japan, noon in Toulouse France, or noon in Toledo Ohio US — three different moments several hours apart.

LocalDateTime.ofInstant

I cannot imagine a scenario where calling that method makes sense.

An Instant represents 3 components: date, time-of-day, and an offset-from-UTC of zero hours-minutes-seconds. A LocalDateTime has only two of those: date and time-of-day. So converting an Instant to a LocalDateTime involves data loss; you are intentionally discarding valuable information (the offset) with nothing gained in returned.

importExportProgressDTO.getProlongedDate()

I assume this call returns a java.util.Calendar. But you should have said so explicitly.

If you cannot fix your DTO to use OffsetDateTime, and are stuck with a Calendar object, then immediately convert. (However, this is a bizarre situation. The whole point of a DTO is to clearly transfer data between a source, such as a database, and a sink, such as an application. Having a DTO obscure the data types on both ends is perverse.)

To convert, verify the object is actually a GregorianCalendar object, which is highly likely. If so, convert to a ZonedDateTime object.

Calendar calendar = importExportProgressDTO.getProlongedDate();
ZonedDateTime zdt = null ;
if ( calendar instanceof java.util.GregorianCalendar )
{
    zdt = ( ( GregorianCalendar ) calendar ).toZonedDateTime() ;
}
else
{
    // Handle problem
}

Then convert to an OffsetDateTime. This Is the only class in JDBC that is mapped to TIMESTAMP WITH TIME ZONE. The other two moment classes, Instant and ZonedDateTime, are not so mapped.

OffsetDateTime odt = zdt.toOffsetDateTime() ;

ZoneId.of("Asia/Kolkata")

No need to apply a time zone.

Your original Calendar object (an GregorianCalendar object) already contained a time zone. That zone carried over to the ZonedDateTime object. The offset in use in that zone on that date and time is carried into the OffsetDateTime object.

Some databases such as Postgres will use that included offset to adjust to an offset of zero.

.toString()

Use smart objects, not dumb strings.

JDBC 4.2 and later requires support for java.time.

preparedStatement.setObject( … , odt ) ;

Later, you indicated your database is SQLite. That product has almost no data types, and no date-time types at all.

Your type DATETIME is mentioned in the documentation but not explained. That makes it unusable to my mind.

It is possible the code in this Answer will work. But I don’t know. SQLite has severe limitations.

You should know that SQLite is not intended to be a serious database. Its purpose is to be an alternative to opening a file.

If your project is serious enough to warrant the formality of a DTO, then you should not be using SQLite.

For serious work I recommend a serious database. Like H2 for smaller needs, like Postgres for enterprise-level work.

Sign up to request clarification or add additional context in comments.

1 Comment

I would agree that Sqlite is somewhat dubious for serious work, plus it relies on native code afaik, which is unfortunate and a possible attack vector. If, for some reason, you are forced to use it, you can use the strategy I mentioned HERE

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.