I have a field in postgres
Column | Type
created_at | timestamp without time zone
I have a unix timestamp stored in long in Java
long createdAtTime = data.getcreatedAtTime();
I want to convert it to timestamp in java so that I can store with activejdbc into postgres
I tried the following
Date convertedTime = new Date(createdAtTime*1000L);
record.set("created_at", convertedTime);
record.saveIt();
But I get the following error:
Can't infer the SQL type to use for an instance of java.util.Date. Use setObject() with an explicit Types value to specify the type to use.
Should I be using a different way to convert the date first?
java.sql.Timestamp timestamp = new Timestamp(createdAtTime*1000L);
record.set("created_at", convertedTime);
record.saveIt();
Instead of util you have tried with java.sql.Date.
Its a native type of SQL.
Incompatible types
I have a field in postgres …
timestamp without time zone …
…and…
I have a unix timestamp stored in long in Java
long createdAtTime = data.getcreatedAtTime();
This is a contradiction.
The SQL-standard type TIMESTAMP WITHOUT TIME ZONE purposely lacks any indicator of time zone or offset-from-UTC. As such, this type does not represent a moment, is not a point on the timeline. This type represents potential moments along a range of about 26-27 hours, the range of time zones around the globe.
If you are trying to track specific moments, use the other SQL-standard type, TIMESTAMP WITH TIME ZONE. In Postgres, all values of this type are stored in UTC (an offset of zero). If you pass a value indicating some other offset or time zone, Postgres adjusts the value to UTC before storing.
When retrieving a value from a column of type TIMESTAMP WITH TIME ZONE in Postgres, you are always getting a value in UTC. Unfortunately, some well-intentioned tools or drivers sitting between you and the database may decide the dynamically apply a time zone to the value. While well-intentioned, I consider this quite the anti-feature. This behavior creates the illusion of a time zone stored in the database while in fact Postgres only stores UTC in this type.
Date convertedTime = new Date(createdAtTime*1000L);
The java.util.Date class is terrible, poorly designed and flawed. Never use this class nor its siblings, Calendar, SimpleDateFormat, and such. These are all legacy now, supplanted years ago by the modern java.time classes defined in JSR 310.
Instant
The Instant class takes over for java.util.Date. Both classes represent a moment in UTC, though Instant has a finer resolution of nanoseconds versus milliseconds.
unix timestamp stored in long in Java
If you have a count of whole seconds from the epoch reference of the first moment of 1970 in UTC, 1970-01-01T00:00:00Z, convert to an Instant.
Instant instant = Instant.ofEpochSecond( 1_539_555_140L ) ;
Tip: Do not make a habit of tracking time as a count-from-epoch. This is ambiguous (different systems use different resolutions and different epoch references), error-prone, and makes debugging/logging treacherous. Use java.time objects and standard ISO 8601 strings for representing date-time values.
Your JDBC driver may be able to accept an Instant.
myPreparedStatement.setObject( … , instant ) ;
Retrieval:
Instant instant = myResultSet.getObject( … , Instant.class ) ;
OffsetDateTime
If not supporting Instant, use convert to OffsetDateTime. Any JDBC 4.2 or later driver is required to support OffsetDateTime.
OffsetDateTime represents a date and time-of-day with an offset-from-UTC. In contrast, Instant is fixed at UTC, serving as a basic building-block class in java.time framework. Also, OffsetDateTime is more flexible with abilities such as generating strings in various formats versus Instant using only standard ISO 8601 format.
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
myPreparedStatement.setObject( … , odt ) ;
Retrieval:
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
…or…
Instant instant = myResultSet.getObject( … , OffsetDateTime.class ).toInstant() ;
LocalDateTime
If you are not trying to represent moments, such as database type TIMESTAMP WITHOUT TIME ZONE, use the LocalDateTime class.
But if you are thinking use of these types is somehow avoiding the work of using time zones in tracking moments, you are sorely mistaken. This is a “pay now or pay later” situation: Either learn basic date-time concepts and handling practice now, or desperately wrestle with a horrible mess of failed data later.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
I see that your Database column stores value as time stamp without time zone,
why don't you try this
Timestamp current = Timestamp.from(Instant.now());
record.set("created_at", current);//I don't know if you might need to parse
record.saveIt();
Related
I am having a model with multiple member variables in that:
One with LocalDateTime type.
#Column(name = "localdatetime_field")
private LocalDateTime updatedAt;
Other with timestamp:
#Column(name = "timestamp_field")
private Timestamp addedAt;
The problem is:
When I save data in the DB, with mysql-connector v8.0.18:
-> It keeps the data of Localdatetime & Timestamp same as given.
with mysql-connector v5.1.34:
-> It changes the data of Localdatetime by +5.30.
I wonder is it because of mysql-connector or some jackson convertor working behind the scenes.
Avoid legacy date-time classes
The java.sql.Timestamp class is obsolete, supplanted years ago by the modern java.time classes defined in JSR 310.
java.time
Not a moment
The LocalDateTime class is appropriate only to database columns of a type akin to the SQL-standard type TIMESTAMP WITHOUT TIME ZONE. These types do not represent a moment, cannot be a point on the timeline. Without the context of a time zone or offset-from-UTC, we cannot know if noon on the 23rd is noon in Tokyo Japan, noon in Toulouse France, or noon in Toledo Ohio US — three different moments, several hours apart.
In the context of most business app, these types are not usually appropriate. If recording when something has happened, these are the wrong types. These types are only good for (a) describing something across all time zones such as when Christmas starts (different moments in various time zones), and (b) booking appointments in the future that should remain at a certain wall-clock time even if politicians change the time zone rules in than region (Ex: dental appointment at 3 PM should stay at 3 PM even if politicians push the clock forward or backward an hour).
A moment
For database columns of a type akin to the SQL-standard type TIMESTAMP WITH TIME ZONE, we would use either Instant, OffsetDateTime, or ZonedDateTime. Oddly, the JDBC 4.2 spec requires support only for the second of those three: OffsetDateTime.
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
Writing to the database:
myPreparedStatement.setObject( … , odt ) ;
If you want to see the returned OffsetDateTime in the time zone of your choice, apply a ZoneId to get a ZonedDateTime. Be sure to use a real time zone name in format of Continent/Region. Never use 2-4 character pseudo-zones such as IST, EST, and such.
ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;
Beware of middleware
Unfortunately, middleware and tooling often feels the need to inject a time zone adjustment into your date-time info. Most databases store a moment as UTC (an offset from UTC of zero hours-minutes-seconds). Yet some tooling will retrieve that UTC value, apply a time zone adjustment, and then report the result. This anti-feature clouds the picture of what was actually stored in the database.
To get around that anti-feature, you will need to study the documentation for your particular middleware or tool. You may be able to shut off the adjustment. Or as a workaround, you may need to set its applied time zone to be UTC/GMT, or in a pinch use the zone Atlantic/Reykjavik which happens to use zero as its offset.
If doing straight JDBC with the java.time classes, I expect you will see no such rude injection of time zone. At least I have not heard of any such behavior with any JDBC driver yet.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes. Hibernate 5 & JPA 2.2 support java.time.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
Java 9 brought some minor features and fixes.
Java SE 6 and Java SE 7
Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android (26+) bundle implementations of the java.time classes.
For earlier Android (<26), the process of API desugaring brings a subset of the java.time functionality not originally built into Android.
If the desugaring does not offer what you need, the ThreeTenABP project adapts ThreeTen-Backport (mentioned above) to Android. See How to use ThreeTenABP….
This should be quite simple
customerSearch.get("DateOfBirth") where customerSearch is a HashMap<String, Object> and it's a Gregorian Date.
But I need a normal Date object.
I tried
Date dateOfBirth = new Date(
((GregorianCalendar) customerSearch.get("DateOfBirth")).getTimeInMillis());
but said Gregorian Date cannot be cast to Date.
Any help?
tl;dr
( (GregorianCalendar) customerSearch.get( "DateOfBirth" ) ) // Retrieve and cast object of legacy class `GregorianCalendar`.
.toZonedDateTime() // Convert from terrible legacy class to modern *java.time* class.
.toLocalDate() // Extract the date-only portion, omitting time-of-day and time zone.
java.time
You are using, and possibly abusing, terrible date-time classes that were supplanted years ago by the java.time classes defined by JSR 310.
ZonedDateTime replaces GregorianCalendar
Instant replaces java.util.Date
LocalDate replaces java.sql.Date
If you must interoperate with old code not yet updated to java.time, you can convert back-and-forth. Call new conversion methods added to the old classes.
GregorianCalendar gc = customerSearch… ;
ZonedDateTime zdt = gt.toZonedDateTime() ;
If you want just the date without the time-of-day and without the time zone, extract a LocalDate.
LocalDate dateOfBirth = zdt.toLocalDate() ;
If by Date you meant, java.sql.Date class, the above line should be used instead making use of LocalDate.
If by Date you meant java.util.Date, that would be the wrong class to use there. That class represents a moment in UTC. By adjusting from the zoned moment in GregorianCalendar/ZonedDateTime to UTC, you could be changing the date.
Converting
If you need a java.util.Date object to interoperate with old code not yet updated for java.time, you can convert. A java.util.Date represents a moment in UTC, so we need the equivalent in java.time, Instant, also a moment in UTC but with a finer resolution of nanoseconds rather than milliseconds.
We can extract an Instant from our ZonedDateTime seen above. Effectively, this is simply adjusting from a zoned value to a UTC value. Same moment, same point on the timeline, different wall-clock time.
Instant instant = zdt.toInstant() ; // Extract a `Instant`, adjusting from zone to UTC.
Use new conversion methods on the old class.
java.util.Date myJavaUtilDate = java.util.Date.from( instant ) ; // Beware of possible data-loss in the fractional second, truncating from nanos to millis.
If you need go the other direction, from legacy to modern.
Instant instant = myJavaUtilDate.toInstant() ;
Use appropriate types
If you are trying to represent a date-of-birth is is commonly done, with just a date without time-of-day and without zone, then use LocalDate in your map. The classes GregorianCalendar, java.util.Date, and ZonedDateTime all represent a moment, a specific point on the timeline. They should never be used for a date-only.
The java.sql.Date class pretends to be a date-only, but through a terrible design decision as a subclass of java.util.Date actually does indeed carry a time-of-day and offset/zone. This class, as noted above, has been replaced with LocalDate.
normal Date object
There is nothing more “normal” about either java.util.Date or java.sql.Date than any other date-time class.
java.util.Date represents a moment in UTC, always UTC, despite what its terribly designed toString method tells you (a lie). Use java.time.Instant instead when you need a moment in UTC.
java.sql.Date is meant to represent a date-only, but as discussed, actually carries internally a time and zone/offset. Use java.time.LocalDate instead to represent a date rather than a moment.
GregorianCalendar represents a moment as seen in the wall-clock time used by the people of a specific region (a time zone). Instead use ZonedDateTime for this purpose.
java.sql.Timestamp represents a moment in UTC but with a finer resolution of nanoseconds rather than milliseconds. All the moment-related classes in java.time use a resolution of nanoseconds. So for a moment in UTC with a resolution of UTC, use java.time.Instant instead of Timestamp.
As of JDBC 4.2, we can directly exchange java.time classes with a database. So no need to ever touch java.sql.Date or java.sql.Timestamp again for your database work.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
There is no java class GregorianDate. Unless it is your own class which if so you didn't mention. So, just in case is Gregorian Date just a regular Date as most of the world today uses Gregorian calendar? So instances of what class does your map holds in your HashMap<String, Object>? If it is just a regular Date then your code should be just:
Date dateOfBirth = (Date)(customerSearch.get("DateOfBirth"));
I'm trying to parse an offset time using Java 8 DateTimeFormatter.
I live in EST time which is UTC-5, so when I try to convert
2019-01-22T13:09:54.620-05:00 should be --> 2019-01-22T18:09:54.620
However, with my code, it gets the current time and goes back 5 hours, resulting in 2019-01-22 08:09:54.620
Code:
import java.sql.Timestamp
import java.time._
import java.time.format.DateTimeFormatter
import scala.util.{Failure, Success, Try}
class MyTimeFormatter(parser: DateTimeFormatter) {
def parse(input: String): Try[Timestamp] = {
Try(new Timestamp(Instant.from(parser.withZone(ZoneOffset.UTC).parse(input)).toEpochMilli))
}
}
Test:
new MyTimeFormatter(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSxxx")).parse("2019-01-22T13:09:54.620-05:00") shouldEqual Timestamp.valueOf("2019-01-22T18:09:54.620")
where parser is of type DateTimeFormatter and input string is just "2019-01-22T13:09:54.620-05:00"
I want to use this parser.parse method and not with specific temporalAccessors like OffsetDateTime.parse(input, parser) so I can handle all cases like LocalTime, LocalDateTime, ZonedDateTime, OffsetDateTime, etc..
It seems like the code just grabs the time, subtracts the offset, and brands it as UTC instead of calculating the offset with respect to UTC.
Also, is there a way to apply this UTC conversion only if the input format is of ZonedDateTime/OffsetDateTime format? If I input a LocalDateTime (which doesn't have an offset) such as 2017-01-01 12:45:00 the parser will still apply the UTC offset conversion because I told the parser to parse with zone UTC.
tl;dr
Use modern java.time classes. Convert to legacy class only if necessary to work with old code.
Specifically, parse your input string as a OffsetDateTime object, adjust to UTC by extracting an Instant, and lastly, convert to java.sql.Timestamp (only if you must).
java.sql.Timestamp ts = // Avoid using this badly-designed legacy class if at all possible.
Timestamp // You can convert back-and-forth between legacy and modern classes.
.from( // New method added to legacy class to convert from modern class.
OffsetDateTime // Represents a moment with an offset-of-UTC, a number of some hours-minutes-seconds ahead or behind UTC.
.parse( "2019-01-22T13:09:54.620-05:00" ) // Text in standard ISO 8601 format can be parsed by default, without a formatting pattern.
.toInstant() // Adjust from an offset to UTC (an offset of zero) by extracting an `Instant`.
) // Returns a `Timestamp` object. Same moment as both the `OffsetDateTime` and `Instant` objects.
;
See this code run live at IdeOne.com, resulting in:
ts.toString(): 2019-01-22 18:09:54.62
If using JDBC 4.2 or later, skip the Timestamp altogether.
myPreparedStatement.setObject( … , myOffsetDateTime ) ;
Zulu
2019-01-22T13:09:54.620-05:00 should be --> 2019-01-22T18:09:54.620
If you meant that second value to represent a moment in UTC, append the offset-from-UTC to indicate that fact. Either +00:00 or Z (pronounced “Zulu”): 2019-01-22T18:09:54.620Z.
Reporting a moment without an offset-from-UTC or time zone indicator is like reporting an amount of money without a currency indicator.
OffsetDateTime
A string with an offset-from-UTC should be parsed as a OffsetDateTime object.
Your input string happens to comply with the ISO 8601 standard formats for textual date-time values. The java.time classes use ISO 8601 formats by default when parsing/generating strings. So no need to specify a formatting pattern.
OffsetDateTime odt = OffsetDateTime.parse( "2019-01-22T13:09:54.620-05:00" ) ;
Timestamp
Apparently you want a java.sql.Timestamp object. This is one of the terrible date-time classes bundled with the earliest versions of Java. These classes are now legacy, supplanted entirely by the modern java.time classes with the adoption of JSR 310. Avoid these legacy classes whenever possible.
If you must have a Timestamp to interoperate with old code not yet updated to work with java.time, you can convert. To convert, call new methods added to the old classes.
Instant
The java.sql.Timestamp class carries a from( Instant ) method. An Instant is a moment in UTC. To adjust from the offset of our OffsetDateTime to UTC, just extract an Instant.
Instant instant = odt.toInstant() ;
java.sql.Timestamp ts = Timestamp.from( instant ) ;
We have three objects ( odt, instant, & ts ) that all represent the same moment. The first has a different wall-clock time. But all three are the same simultaneous point on the timeline.
JDBC 4.2
As of JDBC 4.2, we can directly exchange java.time objects with the database. So no need to use Timestamp.
myPreparedStatement.setObject( … , odt ) ;
…and…
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
While I cannot reproduce your issue precisely (even with changing my clock to EST), this is what I am observing:
Instant instant = Instant.from(parser.withZone(ZoneOffset.UTC).parse("2019-01-22T13:09:54.620-05:00"));
This is producing the time you would expect (2019-01-22T18:09:54.620Z).
Timestamp ts = new Timestamp(instant.toEpochMilli());
Because this is based on java.util.Date, which displays as your local time.
A better way to convert an Instant to a Timestamp is via the LocalDateTime, like so:
Timestamp ts = Timestamp.valueOf(instant.atZone(ZoneOffset.UTC).toLocalDateTime());
I have a date column in postgres db whose value is 2018-11-20 22:07:20. The datatype is timestamz. I want to get the above value in java code and convert that to seconds with respect to the current time. Suppose the current date is 2018-11-21 22:07:20 then the final answer should be 86400 seconds. Can anyone help me with this?
tl;dr
Duration // Represent a span-of-time unattached to the timeline.
.between( // Calculate elapsed time between two moments.
OffsetDateTime.now( ZoneOffset.UTC ) , // Capture the current moment as seen in UTC.
myResultSet.getObject( … , OffsetDateTime.class ) // Retrieve the moment stored in your database as a `OffsetDateTime` object, *not* as a mere string.
) // Return a `Duration` object.
.toSeconds() // View that duration as a total number of whole seconds. Obviously, any fractional second is ignored.
Details
The Answer by Michael is close but not quite correct.
It fails to account for anomalies in your local time zone, such as Daylight Saving Time (DST): LocalDateTime is the wrong class there, as it cannot, by definition, represent a moment.
It also fails to address the bigger problem that dumb strings are being used to exchange date-time values with the database rather than using smart objects.
date column in postgres db whose value is 2018-11-20 22:07:20
No, that is not the value of the column. That is a textual representation of the value. What is the distinction? Well, unfortunately, many tools used to access your data take the liberty of altering the data being retrieved by applying a time zone adjustment.
Even worse, your example text lacks an indicator of time zone or offset-from-UTC. This contradicts your next statement.
The datatype is timestamz.
I think you misspelled timestampz (missing the p). Even so, this seems to be incorrect, as no such type is listed among the Postgres date/time types. Some systems use that word as an abbreviation, but I recommend always using the longer SQL-standard name for clarity.
You likely meant the type TIMESTAMP WITH TIME ZONE which Postgres, like some other databases, stores as a value in UTC. Any indicator of time zone or offset-from-UTC present within incoming data is used to adjust to UTC, then the indicator is discarded. So values going into, and out of, a TIMESTAMP WITH TIME ZONE column in Postgres is always in UTC. Beware, as mentioned above, some tools interfere with the data retrieval by injecting a time zone adjustment, a well-intentioned though very confusing anti-feature.
Smart objects, not dumb strings
As of JDBC 4.2, we can exchange java.time objects with the database via setObject and getObject methods. Use the object rather than mere strings to exchange date-time values.
OffsetDateTime
Retrieve your value from a column of type TIMESTAMP WITH TIME ZONE as an OffsetDateTime value with its offset set to UTC.
OffsetDateTime odtThen = myResultSet.getObject( … , OffsetDateTime.class ) ;
For comparison, get the current moment in UTC. Specify the offset using the constant ZoneOffset.UTC.
OffsetDateTime odtNow = OffsetDateTime.now( ZoneOffset.UTC ) ;
To generate text representing that duration in standard ISO 8601 format, call OffsetDateTime::toString.
Duration
Capture elapsed time as a Duration object.
Duration d = Duration.between( odtNow , odtThen ) ;
To generate text representing that duration in standard ISO 8601 format, call Duration::toString.
String output = d.toString() ; // PnYnMnDTnHnMnS
To see that entire duration as one big count of whole seconds, call Duration::toSeconds.
long secondsElapsed = d.toSeconds() ;
ZonedDateTime
By the way, if you wish to view either the that odtThen or odtNow value through the lens of the wall-clock time used by the people of a particular region (a time zone), apply a ZoneId to get a ZonedDateTime.
Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 2-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;
ZonedDateTime zdt = odtThen.atZoneSameInstant( z ) ;
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
Parse into a LocalDateTime, then get the Duration between that and the current time, and convert it to seconds.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("your pattern");
LocalDateTime dateTime = LocalDateTime.parse("2018-11-20 22:07:20", formatter);
return Duration.between(dateTime, LocalDateTime.now()).getSeconds();
You can work out the pattern yourself.
I sometimes get confused by the different Date types in java and their practical usage. Here
i am trying to summarize my understanding
java.sql.Date :- A thin wrapper around a millisecond value that allows JDBC to identify this as an SQL DATE value
java.sql.Timestamp :- A thin wrapper around java.util.Date that allows the JDBC API to identify this as an SQL
TIMESTAMP value. It adds the ability to hold the SQL TIMESTAMP fractional seconds value, by allowing the specification
of fractional seconds to a precision of nanoseconds
I have seen most of the projects prefer Timestamp instead of date. I think the main reason for this is that Timestamp can hold the value till
nano seconds precision whereas Data can hold till milli seconds. Correct?
Calendar :- This class is designed for date manipulation for example :- for converting between a specific instant in time and a
set of calendar fields such as YEAR, MONTH, DAY_OF_MONTH, HOUR, and so on, and for manipulating the calendar fields, such as getting
the date of the next week.Though i dont know why this class is abstract when only one implementation exists i.e GregorianCalendar.
java.sql.Timestamp A thin wrapper around java.util.Date that allows the JDBC API to identify this as an SQL TIMESTAMP value.
If you check java.sql.Timestamp JavaDoc, it is very explicit that this class extends from java.util.Date (as java.sql.Date does). And in real world projects you must plain java.util.Date when storing the data in your database and mostly java.sql.Timestamp since it stores date and time value, while java.sql.Date just stores date value.
On the other hand, java.util.Calendar is abstract since there are more implementations of this apart from java.util.GregorianCalendar. If you see the code of Calendar#getInstance from HotSpot, you will see that it calls createCalendar(TimeZone.getDefaultRef(), Locale.getDefault(Locale.Category.FORMAT)), and this method code uses 3 different calendars: BuddhistCalendar, JapaneseImperialCalendar and GregorianCalendar. This code is copied from JDK 7 source:
private static Calendar createCalendar(TimeZone zone,
Locale aLocale) {
Calendar cal = null;
String caltype = aLocale.getUnicodeLocaleType("ca");
if (caltype == null) {
// Calendar type is not specified.
// If the specified locale is a Thai locale,
// returns a BuddhistCalendar instance.
if ("th".equals(aLocale.getLanguage())
&& ("TH".equals(aLocale.getCountry()))) {
cal = new BuddhistCalendar(zone, aLocale);
} else {
cal = new GregorianCalendar(zone, aLocale);
}
} else if (caltype.equals("japanese")) {
cal = new JapaneseImperialCalendar(zone, aLocale);
} else if (caltype.equals("buddhist")) {
cal = new BuddhistCalendar(zone, aLocale);
} else {
// Unsupported calendar type.
// Use Gregorian calendar as a fallback.
cal = new GregorianCalendar(zone, aLocale);
}
return cal;
}
Now, why to work directly with Calendar instead of GregorianCalendar? Because you must work with abstract classes and interfaces when provided instead of working directly with implementations. This is better explained here: What does it mean to "program to an interface"?
Apart from this, if you will work with date and times, I recommend using a library like Joda-Time that already handles and solves lot of the problems with the current Java Date API and also provides methods to retrieve this date and times object in java.util.Date flavor.
java.time
You must first understand that those old date-time classes bundled with early versions of Java are a confusing mess of badly designed classes with hacks. They were the industry's first attempt at a sophisticated facility for date-time handling, and deserve credit for that. But ultimately they failed.
They have been supplanted by the new java.time framework built into Java 8 and later.
java.sql.Date — Use java.time.LocalDate instead
java.sql.Timestamp — Use java.time.Instant instead
java.util.Calendar & GregorianCalendar — Use java.time.ZonedDateTime instead
For date only, without time-of-day nor time zone, use java.time.LocalDate. For a moment on the timeline in UTC, use java.time.Instant. To assign a different time zone to an Instant, use java.time.ZonedDateTime.
Understand that an offset-from-UTC is merely a number of hours and minutes ahead of, or behind, UTC. A time zone is a history of past, present, and future changes to the offset used by the people of a certain region.
If you have a date-time value that has an offset-from-UTC rather than a time zone, represent that with the OffsetDateTime class. Then call its toInstant method to obtain a Instant object to be sent to your database in a column of type akin to the SQL-standard TIMESTAMP WITH TIME ZONE.
The SQL-standard type TIMESTAMP WITHOUT TIME ZONE (without, not with) purposely lacks any concept of time zone or offset-from-UTC. The legacy date-time classes had no way to represent such a value. Now, in java.time, we have LocalDateTime.
If your JDBC driver complies with JDBC 4.2 or later, you can directly exchange java.time objects with your database. No need to ever use the java.sql date-item types again.
myPreparedStatement.setObject( … , instant ) ;
And retrieval.
Instant instant = myResultSet.getObject( … , Instant.class ) ;
Adjust into the wall-clock time used by the people of a particular region (a time zone).
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
The first line in the original question contains the phrase " the different Date types in java and their practical usage"
The practical usage of the timestamp data type is exactly as it says - an timestamp used by the SQL to record a precise chronological value typically used for transactional ordering. Timestamps are usually only used internally... where nanoseconds count. There are use cases for external timestamp data, but they are relatively rare.
The date type handles 99% of external nonscientific data needs with millisecond precision.