Datetime fields in json - java

How do we store postgres datetime objects in java pojo classes for json objects? I am trying to sort them and want to check if I should be comparing datetime or strings? Date compareTo doesn't work but strings comparTo works fine for datetime objects
private Date fieldA;
private Date fieldB;
fieldA.compareTo(fieldB);

tl;dr
How do we store postgres datetime objects in java pojo classes for json objects?
It depends.
For a Postgres column of TIMESTAMP WITH TIME ZONE, use the java.time.Instant class.
For a Postgres column of TIMESTAMP WITHOUT TIME ZONE, use the java.time.LocalDateTime class.
As for JSON, there are no JSON data types for date-time values. Generate strings in standard ISO 8601 format.
I am trying to sort them
The java.time classes know how to sort themselves, implementing the Comparable interface.
if I should be comparing datetime or strings?
Always use smart objects, not dumb strings. That is why you have JDBC technology and JDBC drivers.
Date compareTo doesn't work
Never use the java.util.Date class. Never use the java.sql.Date class. Use only java.time classes.
strings comparTo works fine for datetime objects
Nope. Date-time strings can come in all kinds of formats, using all kinds of human languages and cultural norms, with various time zones or offsets-from-UTC applied. Strings are not appropriate for sorting date-time values. Use smart java.time objects, not dumb strings.
Or do your sorting on the database side, where Postgres is optimized for such chores.
private Date fieldA; private Date fieldB;
Make that:
private Instant fieldA, fieldB ;
…
boolean isAEarlier = fieldA.isBefore( fieldB ) ;
boolean isAtheSame = fieldA.equals( fieldB ) ; // Note that some other java.time classes have `isEqual` method as well as `equals` method.
boolean isALater = fieldA.isAfter( fieldB ) ;
boolean isAEqualToOrLaterThan = ( ! fieldA.isBefore( fieldB ) ) ; // "Is equal to or later than" is a common use-case. "Not before" is a logical shortcut with the same effect.
java.time
The Date class is now legacy, part of the terribly troublesome old date-time classes that were supplanted by the java.time classes years ago. Never use Date, Calendar, SimpleDateFormat, and such.
Your Question is a duplicate of many others, so I'll be brief here. Search Stack Overflow to learn more.
Attached to the timeline
For the database column type TIMESTAMP WITH TIME ZONE defined in the SQL standard and used in Postgres, that represents a moment, a specific point on the timeline.
In Postgres, this type has a resolution of microseconds and is always in UTC. Any inputs with an indicator of time zone or offset-from-UTC are adjusted into UTC, and the zone/offset then discarded. So the type is a bit of a misnomer, as the original zone/offset is forgotten and the stored value is always in UTC. Other databases may vary in this behavior, so beware, as the SQL spec barely touches on the subject of date-time.
Beware that when using tools other than JDBC, your tool may be injecting a time zone or offset-from-UTC after retrieving the stored UTC value; this can be quite misleading and confusing to a novice (and is an unfortunate design decision in my opinion).
In Java, generally best to work in UTC. As a programmer, learn to think, store, and exchange moments as UTC. Generally, use the Instant class for this. For defining member variables in your classes, Instant is your go-to class.
Instant instant = Instant.now() ; // Capture the current moment in UTC, with a resolution as fine as nanoseconds.
You may want to truncate any nanoseconds to microseconds to match retrieved values from Postgres. Specify resolution with ChronoUnit.
Instant instant = Instant.now().truncatedTo( ChronoUnit.MICROS ) ;
For presentation to the user in their desired/expected time zone, assign a ZonedId 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 3-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( "America/Montreal" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
To get back to UTC, extract a Instant.
Instant instant = zdt.toInstant() ;
To generate localized text representing the value of the ZonedDateTime object, use DateTimeFormatter. Search Stack Overflow for much more info.
Not attached to the timeline
The database type TIMESTAMP WITHOUT TIME ZONE purposely lacks any concept of time zone or offset-from-UTC. As such it does not represent a moment, is not a point on the timeline, and is not what you likely want in a business app except when:
Scheduling appointments out into the future.
Representing the concept of a date and time to every zone or any zone, not a particular zone.
In Postgres, any zone or offset accompanying input is ignored. The date and the time-of-day are stored as-is with no adjustment.
The matching type in Java is LocalDateTime.
The “Local” in this class name does not mean “a particular locality”. Just the opposite! It means every locality, or any locality, but not a particular locality. If you do not understand this, do some study, read the class doc, and search Stack Overflow.
Database
Use smart objects rather than dumb strings to exchange date-time values with your database.
As of JDBC 4.2, you can directly exchange java.time objects with the database. Never use java.sql.Timestamp, java.sql.Date, and java.sql.Time.
Storage.
myPreparedStatement.setObject( … , instant ) ;
Retrieval.
Instant instant = myResultSet.getObject( … , Instant.class ) ;
JSON
The JSON spec defines very few data types, and none of them are date-time related. You are on your own there. Ditto for XML.
ISO 8601
When serializing date-time values as text, use the standard ISO 8601 formats. These are designed to be practical and useful, and to avoid ambiguities. They are designed to be easy to parse by machine, while also being easy to read by humans across cultures.
The java.time classes use these standard formats by default when parsing/generating date-time strings. Just call parse and toString on the various classes.
Instant instant = Instant.parse( "2018-01-23T01:23:45.123456Z" ) ;
String output = instant.toString() ;
The ISO 8601 format for a moment happen to be similar to the usual SQL format except that in SQL uses a SPACE in the middle rather than a T. That fact is largely irrelevant as you should be using objects rather than strings between Java and your database, as mentioned above.
Half-Open
Related to the topic of comparing… When working with spans of time, learn to consistently use the Half-Open approach where the beginning is inclusive while the ending is exclusive. Search Stack Overflow to learn more.
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.

You should use the java.time.LocalDateTime class. This is the new (Java 8) class for representing a date and time without any specific time zone or offset.
In other words, you can think of it as holding a year, month, day, hour, minute, second and millisecond. But because there's no time zone or offset specified, it doesn't actually correspond to a particular Instant - that is, a particular moment in time.
It seems to me that of all the Java 8 date/time related classes, this is the one that's closest in intent to what you'd store in a database's DateTime field.
Further reading: Basil Bourque's answer to this question

Thanks. I have used java.sql Timestamp and it works fine. I couldn't see LocalDatetime supported by Json Jackson library. – JEE_program Jul 3 at 21:47

Related

How to parse a String YYYYMMDD_HHMMSSZ in Java 8

I need to parse a UTC date and time string, e.g. 20180531_132001Z into a Java 8 date and time object. How do I go about doing this using Java 8's new date and time libraries? Most examples I see is for LocalDateTime, like this:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss'Z'");
LocalDateTime localDateTime = LocalDateTime.parse("20180531_132001Z", formatter);
System.out.println(localDateTime);
System.out.println(localDateTime.atOffset(ZoneOffset.UTC));
The code outputs:
2018-05-31T13:20:01
2018-05-31T13:20:01Z
Is this considered local time or UTC time? The string value I am parsing is based on UTC, so I am wondering if I need to do anything further before persisting to the database.
If the former, how do I convert that to UTC date and time?
I ultimately need to persist this to a SQL Server database table (column type is [datetime2](7), using [Spring] JDBC.
Update: Based on the comments and answers, I think my question is not well thought out. Putting it another way, if I get an input string and I parse it without factoring any zone or offset, I will get a LocalDateTime object. How do I take that object and convert the encapsulated value to UTC date and time?
LocalDateTime can be misleading. It doesn't represent your local date/time, it represents a local date/time.
It carries no time zone info at all.
That is, it just says for example "it's 13:20". It doesn't say where it's 13:20. It's up to you to interpret the where part.
Due to this LocalDateTime is usually not very useful for carrying timestamps, it's only useful for situations when the timezone is dependent on some context.1
When working with timestamps it's better to use ZonedDateTime or OffsetDateTime instead. These carry the date, time and offset.
So localDateTime.atOffset(ZoneOffset.UTC) will actually return an instance of OffsetDateTime, by interpreting localDateTime as UTC time.
One could argue that you can avoid the interpreting part by parsing with the timezone info in the first place (even though it's always Z):
String example = "20180531_132001Z";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd_HHmmssX");
OffsetDateTime dateTime = OffsetDateTime.parse(example, formatter);
System.out.println(dateTime); // look ma, no hardcoded UTC
Will print:
2018-05-31T13:20:01Z
The added value is that your code automatically supports timezones (e.g. "20180531_132001+05").
JDBC 4.2 compliant driver may be able to directly address java.time types by calling setObject.
For older JDBC drivers you can convert dateTime to a java.sql.Timestamp or java.util.Date:
java.sql.Timestamp.from(dateTime.toInstant());
java.util.Date.from(dateTime.toInstant());
1 There is almost always some context in which LocalDateTime operates. For example "Flight KL1302 arrives at airport X tomorrow at 13:20". Here the context of "tomorrow at 13:20" is the local time at airport X; it can be determined by looking up the time zone of X.
tl;dr
myPreparedStatement.setObject( // Pass java.time objects directly to database, as of JDBC 4.2.
… , // Indicate which placeholder in your SQL statement text.
OffsetDateTime.parse( // Parse input string as a `OffsetDateTime` as it indicates an offset-from-UTC but not a time zone.
"20180531_132001Z" , // Define a formatting pattern to match your particular input.
DateTimeFormatter.ofPattern( "uuuuMMdd_HHmmssX" ) // TIP: When exchanging date-time values as text, use use standard ISO 8601 formats rather than inventing your own.
) // Returns a `OffsetDateTime` object.
.toInstant() // Returns a `Instant` object, always in UTC by definition.
)
Details
There is some helpful information in the other Answers, but all of them have some misinformation which I tried to correct by posting comments.
Most importantly, your code is using the wrong Java class and the wrong database data type for that given input.
Below is explanation along with a complete code example, using the modern java.time classes with JDBC 4.2 or later.
Z = UTC
DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss'Z'")
Never put single-quotes around vital parts of your input such as you did here with Z. That Z means UTC and is pronounced “Zulu”. It tells us the text of the date and time-of-day should be interpreted as using the wall-clock time of UTC rather than, say, America/Montreal or Pacific/Auckland time zones.
Do not use the LocalDateTime for such inputs. That class lacks any concept of time zone or offset-from-UTC. As such, this class does not represent a moment, and is not a point on the timeline. A LocalDateTime represents the set of potential moments along a range of about 26-27 hours (across all time zones). Use LocalDateTime when you mean any or all time zones rather than one particular zone/offset. In contrast, the Z tells us this input uses the wall-clock time of UTC specifically.
Parsing
Define a formatting pattern to match all important parts of your input string.
String input = "20180531_132001Z" ;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuuMMdd_HHmmssX" ) ;
By the way, whenever possible, use standard ISO 8601 formats rather than a custom format as seen in your Question. Those formats are wisely designed to be easy to parse by machine and easy to read by humans across cultures while eliminating ambiguity.
Parse as a OffsetDateTime because your input indicates an offset-from-UTC (of zero hours). An offset-from-UTC is merely a number of hours and minutes, nothing more, nothing less.
Use the ZonedDateTime class only if the input string indicates a time zone. A time zone has a Contintent/Region name such as Africa/Tunis. A zone represents the history of past, present, and future changes in the offset used by the people of a particular region.
OffsetDateTime odt = OffsetDateTime.parse( input , f ) ;
odt.toString(): 2018-05-31T13:20:01Z
Database
To communicate this moment to a database using JDBC 4.2 and later, we can directly pass the java.time object.
myPreparedStatement.setObject( … , odt ) ;
If your JDBC driver does not accept the OffsetDateTime, extract the simpler class Instant. An Instant is in UTC always, by definition.
Instant instant = odt.toInstant() ;
myPreparedStatement.setObject( … , instant ) ;
And retrieval.
Instant instant = myResultSet.getObject( … , Instant.class ) ;
Beware - Wrong datatype in your database
I am not a MS SQL Server user, but according to this documentation, the column data type DATETIME2 is not appropriate to your input. That data type seems to be equivalent to the SQL-standard type DATETIME WITHOUT TIME ZONE. Such a type should never be used when recording a specific moment in history.
Lacking any concept of time zone or offset-from-UTC, that column type should only be used for three situations:
The zone or offset is unknown.This is bad. This is faulty data. Analogous to having a price/cost without knowing the currency. You should be rejecting such data, not storing it.
The intention is “everywhere”, as in, every time zone.Example, a corporate policy that states “All our factories will break for lunch at 12:30" means the factory in Delhi will break hours before the factory in Düsseldorf which breaks hours before the factory in Detroit.
A specific moment in the future is intended, but we are afraid of politicians redefining the time zone.Governments change the rules of their time zones with surprising frequency and with surprisingly little warning (even [no warning at all][10]). So if you want to book an appointment at 3 PM on a certain date, and you really mean 3 PM regardless of any crazy decision a government might make in the interim, then store a LocalDateTime. To print a report or display a calendar, dynamically apply a time zone (ZoneId) to generate a specific moment (ZonedDateTime or Instant). This must be done on-the-fly rather than storing the value.
Since your input is a specific moment, a certain point on the timeline, you should be storing it in the database using a column type akin to the SQL-standard type TIMESTAMP WITH TIME ZONE.
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.
Maybe this can help you.
public static void main(String... strings) {
OffsetDateTime utc = OffsetDateTime.now(ZoneOffset.UTC);
System.out.println(utc.toString());
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy mm dd hh:mm a");
System.out.println(utc.format(format));
}
While you certainly can use LocalDateTime and format it to look like a zoned date time using offset, it would be easier to use an Object designed to store time zone.
ZonedDateTime zonedDateTime = ZonedDateTime.parse("20180531_132001Z", DateTimeFormatter.ofPattern("yyyMMdd_HHmmssX"));
This gives you the option to use Instant to convert to SQL timestamp or any other format without having to hard-code the time zone, especially if time zone is added in the future or changes.
java.sql.Timestamp timestamp = new java.sql.Timestamp(zonedDateTime.toInstant().toEpochMilli());
You can view the timestamp's instant and compare it to the toString, which should be pegged to your timezone, and instant.toString, which pegs to UTC.
System.out.print(timestamp + " " + timestamp.toInstant().toString());
this should do the trick to parse string to LocalDateTime :
String example = "20180531_132001Z";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd_HHmmssX");
ZonedDateTime dateTime = ZonedDateTime.parse(example, formatter);
See that code run live in IdeOne.com.
dateTime.toString(): 2018-05-31T13:20:01Z
Timestamp timestamp = Timestamp.from(dateTime.toInstant());
Timestamp then is saved into db

SQL database (JDBC): A column of type date only stores date values and not time values

I have a database like this where lastEdited is a date field.
I connected this database to a Java web application by using "RESTFUL web-services from database"
This automatically generated a class called ThreadChat for my THREADCHAT column. Given here is the getter and setter for the lastEdited part.
lastEdited is a java.util.Date object.
public Date getLastedited() {
return lastedited;
}
public void setLastedited(Date lastedited) {
this.lastedited = lastedited;
}
Here, I am creating a new ThreadChat object and adding the data to the database. Argument for lastEdited is a java.util.Date object.
ThreadChat thread = new ThreadChat(threadName, new Date(), loginIdInt);
threadChatFacadeREST.create(thread);
This would update the table like this.
This method returns all the records in the THREADCHAT table.
List<ThreadChat> list = getAllThreads();
However, getLastEdited() returns a XMLGregorianCalender object instead of a Date object as in the getter method above.
If I print this object to the console, the date part is there but I get 00:00 for the minutes and hours part every time.
2018-04-10T00:00:00+05:30
How do I store Date + Time in a JDBC database and retrieve both?
The type of your field in your database is DATE so DATE only stores YYYY-MM-DD.
If you want to store also the time you must change the type of your field in your database to DATETIME. The representation of this is: YYYY-MM-DD HH:MI:SS
More information in: https://www.w3schools.com/sql/sql_datatypes.asp
tl;dr
You are using a date-only type to hold a date-time value – trying to fit a square peg into a round hole.
How do I store Date + Time in a JDBC database and retrieve both?
To store a moment, a date-time value, use a date-time type:
TIMESTAMP WITH TIME ZONE in your database.
Instant in Java.
You are using terribly confusing legacy classes. Use only java.time classes instead.
Databases vary
Databases vary widely in their date-time data types and their behavior. You do not specify your database, so we can only guess or abide by the SQL standard.
The SQL standard barely touches on the subject of date-time handling, unfortunately. The standard briefly defines:
DATE as a date-only value without time-of-day.
A TIMESTAMP WITHOUT TIME ZONE is a date and a time-of-day, but lacks any concept of time zone or offset-from-UTC, so it does not represent actual moments.
For actual moments, use TIMESTAMP WITH TIME ZONE. That type name can be misleading as some implementations such as Postgres do not store a zone with the value, but instead use any passed zone information to adjust into a UTC value for storage.
java.time
You are using terrible old date-time classes from the earliest versions of Java. Those were supplanted in Java 8 and later by the java.time classes. Never use Date or Calendar again.
Generally best to think, work, store, log, and exchange date-time values in UTC unless specifically required by the business logic or user-interface. So generally you should focus on the Instant class. The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction). This class replaces java.util.Date.
Capture the current moment in UTC.
Instant instant = Instant.now() ; // Capture the current moment in UTC.
Store this Instant in a database column of SQL-standard type TIMESTAMP WITH TIME ZONE or whatever is akin to that in your particular database.
JDBC 4.2
As of JDBC 4.2 and later, you can directly exchange java.time objects with your database.
myPreparedStatement.setObject( … , instant ) ;
Retrieval.
Instant instant = myResultSet.getObject( … , Instant.class ) ;
Converting
If handed an obsolete XMLGregorianCalendar, immediately convert into java.time ZonedDateTime by way of the obsolete GregorianCalendar class.
ZonedDateTime zdt = myXmlGregCal.toGregorianCalendar().toZonedDateTime() ; // Convert from legacy classes to modern java.time class.
If you want to see that same moment in UTC rather than the wall-clock time used by the people of that particular region (time zone), extract an Instant.
Instant instant = zdt.toInstant() ; // Adjust from zoned moment to UTC. Same moment, same point on the timeline, different wall-clock time.
If you must inter-operate with old code not yet updated to java.time, you can convert back and forth. Tip: Try to stay within java.time as much as possible. The legacy classes are an awful mess of poor design.
java.util.Date myJavaUtilDate = java.util.Date.from( instant ) ;
And, going the other direction.
Instant instant = myJavaUtilDate.toInstant() ;
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.
You are looking for a DATA_TYPE TIMESTAMP. You should change your Database if you can.

Recommended way to store java.time.OffsetDateTime in SQLite Database

I'm looking for the best way to store a java.time.OffsetDateTime in a SQLite database (on Android, if that helps).
The question arises since SQLite does not have a native data type for date+time.
The criteria are that I should be able to produce sensible results from:
ordering on the "date+time" column.
Not lose small time differences (milliseconds).
Be able to use the equivalent of BETWEEN, or range, in WHERE
Not lose time zone information (devices may be used globally and roam)
Hopefully retain some efficiency.
At the moment I'm storing the timestamp as an ISO formatted string. Not sure that is ideal either for efficiency or for comparisons.
Perhaps a conversion to UTC and then a long (Java) is an option, but I cannot find a function in OffsetDateTime that return time since epoch (as, for example, Instant.ofEpochMilli).
I should probably mention that the data is stored and used on an Android device. The application code uses the timestamp and performs simple arithmetic like "how many days passed since some event". So the data is being converted between the storage type and OffsetDateTime.
Store datetime as ISO 8601 string (e.g. 2017-06-11T17:21:05.370-02:00). SQLite has date and time functions, which operates on this kind of strings (time zone aware).
Class java.time.OffsetDateTime is available from API 26, so I would recommend for you to use ThreeTenABP library.
Below example:
private val formatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME
val datetime = OffsetDateTime.now()
//###### to ISO 8601 string (with time zone) - store this in DB
val datetimeAsText = datetime.format(formatter)
//###### from ISO 8601 string (with time zone) to OffsetDateTime
val datetime2 = formatter.parse(datetimeAsText, OffsetDateTime::from)
To make SQL queries time zone aware you need to use one of the date and time functions built in SQLite, for e.g.
if you want to sort by date and time you would use datetime() function:
SELECT * FROM cars ORDER BY datetime(registration_date)
SQLite may not have a DATE storage/column type. However SQLite does have relatively flexible DATE FUNCTIONS, which work quite effectively on a number of storage/column types.
I'd suggest reading SQL As Understood By SQLite - Date And Time Functions
For example, this column definition defines a column (MYCOLUMN) that will hold the datetime (to seconds not milliseconds) of when the row was inserted.
"CREATE TABLE....... mycolumn INTEGER DEFAULT (strftime('%s','now')), ......"
You may also want to have a read of Datatypes In SQLite Version 3 which explains the felxibity of data types. e.g. Section 3 Type Affinity asserts:
Any column can still store any type of data. It is just that some columns, given the choice, will prefer to use one storage class over
another. The preferred storage class for a column is called its
"affinity".
e.g.
"CREATE TABLE....... mycolumn BLOB DEFAULT (strftime('%s','now')), ......"
works fine. The following is output, using the Cursor methods getString, getLong and getDouble, for a row inserted using the above :-
For Column otherblob Type is STRING value as String is 1507757213 value as long is 1507757213 value as double is 1.507757213E9
Personally, I'd suggest, due to milliseconds, using a type of INTEGER and storing UTC and using the cursor getLong to retrieve from the cursor.
UTC
Generally, the best practice for storing or exchanging date-time values is to adjust them into UTC.
Programmers and sysadmins should learn to think in UTC rather than their own parochial time zone. Consider UTC as The One True Time, with all other offsets and zones being mere variations on that theme.
Adjust your OffsetDateTime into UTC.
OffsetDateTime odtUtc = myOdt.withOffsetSameInstant( ZoneOffset.UTC ) ;
odtUtc.toString(): 2007-12-03T10:15:30.783Z
Simplest approach is to convert to Instant, which is always in UTC.
Instant instant = myOdt.toInstant() ;
String instantText = instant.toString() ; // Generate text in standard ISO 8601 format.
…
myPreparedStatement.setString( instantText ) ;
ISO 8601
Given the limitations of SQLite, I suggest storing the values as text, in a format that when sorted alphabetically is also chronological.
You need not invent such a format. The ISO 8601 standard has already defined such formats. The standard formats are sensible, practical, easy to parse by machine, and easy to read by humans across various cultures.
Conveniently, the java.time classes use ISO 8601 formats by default when parsing or generating strings.
If your JDBC driver complies with JDBC 4.2 or later, you can exchange the java.time objects directly to the database via setObject and getObject.
myPreparedStatement.setObject( … , odtUtc ) ;
Resolution
You mentioned milliseconds. Know that java.time classes use a resolution of nanoseconds, for up to nine decimal digits of fractional second.
Calculating days
simple arithmetic like "how many days passed since some event".
Actually that is not so simple. Do you mean calendar days? If so, specify a time zone to determine the dates. Or do you mean periods of 24-hours?
// Count of generic 24-hour days
String fromDatabase = myResultSet.getString( … ) ;
Instant instant = Instant.parse( fromDatabase ) ;
Instant now = Instant.now() ;
long days = ChronoUnit.DAYS.between( instant , now ) ;
// Count of calendar days.
ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
ZonedDateTime zdtNow = now.atZone( z ) ;
long days = ChronoUnit.DAYS.between( zdt.toLocalDate() , zdtNow.toLocalDate() ).
Half-Open
Do not use BETWEEN predicate for date-time range searching. Generally the best practice is to use the Half-Open approach where the beginning is inclusive and the ending is exclusive. In contrast, BETWEEN is inclusive on both ends, also known as "fully closed".
Consider another database
Your database needs may be exceeding the limited purpose of SQLite. Consider moving up to a serious database engine if you need features such as extensive date-time handling or high performance.
Richard Hipp, the creator of SQLite, intended that product to be an alternative to plain text files, not be a competitor in the database arena. See What I learned about SQLite…at a PostgreSQL conference.
H2 Database
For Android, H2 Database is another possibility. For more info, see:
Tutorial
H2 Database vs SQLite on Android
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.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, 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
The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
See How to use ThreeTenABP….

java sql date time

When I insert a SQL DateTime to the database I get 2007-02-07 12:00:00.00
But I made the Date object like this : 2007-02-07 17:29:46.00
How to get the value of the seconds in the database. It always changes it back to 12:00:00.00
date.setYear(Integer.valueOf(parsedDate[2].replaceAll(" ", "")) - 1900);
date.setMonth(Integer.valueOf(parsedDate[0].replaceAll(" ", "")));
date.setDate(Integer.valueOf(parsedDate[1].replaceAll(" ", "")));
...
java.sql.Date sqlDate = new java.sql.Date(date.getTime());
Should I use any formatters?
java.sql.Date represents a date, not a date and time. From the docs:
To conform with the definition of SQL DATE, the millisecond values wrapped by a java.sql.Date instance must be 'normalized' by setting the hours, minutes, seconds, and milliseconds to zero in the particular time zone with which the instance is associated.
If you want to store a date and time, you should look for another type - e.g. java.sql.Timestamp. EDIT: That's not suggesting you use a TIMESTAMP column type - as paulsm4 says in the comments, that's a different thing. However, as far as I can see, JDBC only supports:
Date (no, you want a time too)
Time (no, you want a date too)
Timestamp (includes a date and time, but you don't want TIMESTAMP SQL semantics)
I would expect using the Java Timestamp type with a DATETIME column to work, although without the level of precision that Timestamp provides.
EDIT: After a bit more research, it looks like you may want to use the java.sql.Time type, but with special driver parameters - at least if you're using the Microsoft driver. See these docs on configuring JDBC for more information.
tl;dr
You are likely confused by not understanding that java.util.Date is a date-with-time type while its subclass java.sql.Date pretends to be a date-only class but actually has its time-of-day set to zero. Bloody awful design. Avoid both these classes entirely. Use java.time classes only.
For a date-only column in your database, define the column as the SQL-standard DATE type.
myPreparedStatement.setObject(
… ,
LocalDateTime.parse( "2007-02-07 17:29:46.00".replace( " " , "T" ) )
.toLocalDate()
)
java.time
The modern approach uses the java.time classes added to Java 8 and later.
When I insert a SQL DateTime to the database I get 2007-02-07 12:00:00.00
There is no such thing as a SQL-standard type as DateTime, nor any such class in Java. So I do not know your intention there.
As for the input string, 2007-02-07 17:29:46.00, parse that as a LocalDateTime because it lacks any indicator of time zone or offset-from-UTC.
That SQL-style format almost complies with the ISO 8601 standard. To fully comply, replace the SPACE in the middle with a T. The java.time classes use the ISO 8601 formats by default when parsing/generating strings.
String input = "2007-02-07 17:29:46.00".replace( " " , "T" ) ;
Parse.
LocalDateTime ldt = LocalDateTime.parse( input ) ;
A LocalDateTime does not represent a moment, is not a point on the timeline. It represents potential moments along a range of about 26-27 hours.
Standard SQL does offer a data type for such a value, TIMESTAMP WITHOUT TIME ZONE.
Smart objects, not dumb strings
Your entire approach is misguided, wrangling text and using the legacy date-time classes. Instead, exchange java.time objects.
As of JDBC 4.2, you need not ever use the troublesome old java.sql types such as java.sql.Date or java.sql.Timestamp. You can directly exchange java.time objects with your database via setObject/getObject methods.
myPreparedStatement.setObject( … , ldt ) ;
And retrieval.
LocalDateTime ldt = myResultSet.getObject( … , LocalDateTime.class ) ;
If you are trying to work with date-only values, use the SQL-standard type DATE and the Java class LocalDate.
LocalDate ld = ldt.toLocalDate() ;
myPreparedStatement.setObject( … , ld ) ;
How to get the value of the seconds in the database
Not sure what you mean by "value of the seconds".
Perhaps you want a count of seconds from the epoch reference of first moment of 1970 in UTC.
long secondsSinceEpoch = ldt.toEpochSecond() ;
If your goal was merely to instantiate a java.sql.Date, don’t bother. Never use that class again. But, FYI, your specific issue is likely a side-effect of the awful design used for that class. The java.sql.Date class inherits from java.util.Date which is a date-with-time type. The java.sql.Date class pretends to be a date-only value, but actually has its time-of-day set to 00:00:00. Even worse, the documentation tells us to ignore the fact of its being a subclass. Don’t bother trying to understand it; just use java.time instead.
If you are trying to work with the time-of-day alone, extract a LocalTime object.
LocalTime lt = ldt.toLocalTime() ;
If you want to set the time-of-day to zeros, then you likely want a date-only value. If so, use the LocalDate class for a date value without a time-of-day and without a time zone.
LocalDate ld = ldt.toLocalDate() :
If you do want the first moment of the day on that date, call LocalDate::atStartOfDay.
LocalDateTime ldtStart = ldt.toLocalDate().atStartOfDay() ;
BEWARE: If you are trying to track actual moments, specific points on the timeline, then all this code above is wrong. Search Stack Overflow to learn about Instant, ZoneId, and ZonedDateTime classes. Search both Stack Overflow and dba.StackExchange.com to learn about the SQL-standard type TIMESTAMP WITH TIME ZONE.
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.

What is the Best Practice for manipulating and storing dates in Java? [duplicate]

This question already has answers here:
Java Best Practice for Date Manipulation/Storage for Geographically Diverse Users
(2 answers)
Closed 1 year ago.
What is the best practice for manipulating and storing Dates e.g. using GregorianCalendar in an enterprise java application?
Looking for feedback and I will consolidate any great answers into a best practice that others can use.
The best practice is usually precisely NOT to think in term of heavy date objects but to store a point in time. This is typically done by storing a value that doesn't suffer from corner cases nor from potential parsing problems. To do this, people usually store the number of milliseconds (or seconds) elapsed since a fixed point that we call the epoch (1970-01-01). This is very common and any Java API will always allow you to convert any kind of date to/from the time expressed in ms since the epoch.
That's for storage. You can also store, for example, the user's preferred timezone, if there's such a need.
Now such a date in milliseconds, like:
System.out.println( System.currentTimeMillis() );
1264875453
ain't very useful when it's displayed to the end user, that's for granted.
Which is why you use, for example, the example Joda time to convert it to some user-friendly format before displaying it to the end-user.
You asked for best practice, here's my take on it: storing "date" objects in a DB instead of the time in milliseconds is right there with using floating point numbers to represent monetary amounts.
It's usually a huge code smell.
So Joda time in Java is the way to manipulate date, yes. But is Joda the way to go to store dates? CERTAINLY NOT.
Joda is the way to go. Why ?
it has a much more powerful and intuitive interface than the standard Date/Time API
there are no threading issues with date/time formatting. java.text.SimpleDateFormat is not thread-safe (not a lot of people know this!)
At some stage the Java Date/Time API is going to be superseded (by JSR-310). I believe this is going to be based upon the work done by those behind Joda, and as such you'll be learning an API that will influence a new standard Java API.
Joda time (100% interoperable with the JDK)
Joda-Time provides a quality replacement for the Java date and time classes. The design allows for multiple calendar systems, while still providing a simple API
UTC
Think, work, and store data in UTC rather than any time zone. Think of UTC as the One True Time, and all other time zones are mere variations. So while coding, forget all about your own time zone. Do your business logic, logging, data storage, and data exchange in UTC. I suggest every programmer keep a second clock on their desk set to UTC.
java.time
The modern way is the java.time classes.
The mentioned Joda-Time project provided the inspiration for the java.time classes, and the project is now in maintenance mode with the team advising migration to java.time classes.
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, & java.text.SimpleDateFormat.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Where to obtain the java.time classes?
Java SE 8 and SE 9 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 SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
See How to use….
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.
ISO 8601
When serializing a date-time value to text, use the ISO 8601 standard.
For example, a date-time in UTC is 2016-10-17T01:24:35Z where the Z is short for Zulu and means UTC. For other offset-from-UTC the offset of hours and minutes appears at the end such as 2016-01-23T12:34:56+05:30. The java.time classes extend this standard format to append the name of the time zone (if known) in square brackets, such as 2016-01-23T12:34:56+05:30[Asia/Kolkata].
The standard has many other handy formats as well including for durations, intervals, ordinals, and year-week.
Database
For database storage, use date-time types for date-time values, such as the SQL standard data types which are primarily DATE, TIME, and TIMESTAMP WITH TIME ZONE.
Let your JDBC driver do the heavy lifting. The driver handles the nitty-gritty details about mediating and adapting between the internals of how Java handles the data and how your database handles the data on its side. But be sure to practice with example data to learn the behaviors of your driver and your database. The SQL standard defines very little about date-time handling and so behaviors vary widely, surprisingly so.
If using a JDBC driver compliant with JDBC 4.2 and later, you can fetch and store java.time types directly via the ResultSet::getObject and PreparedStatement::setObject methods.
Instant instant = myResultSet.getObject( … );
myPreparedStatement.setObject( … , instant );
For older drivers, you will need to fall back to converting through the java.sql types. Look for new conversion methods added to the old classes. For example, java.sql.Timestamp.toInstant().
Instant instant = myResultSet.getTimestamp( … ).toInstant();
myPreparedStatement.setObject( … , java.sql.Timestamp.from( instant ) );
Use the java.sql types as briefly as possible. They are a badly designed hack, such as java.sql.Date masquerading as a date-only value but actually as a subclass of java.util.Date it does indeed have a time-of-day set to the 00:00:00 in UTC. And, oh, you are supposed to ignore the fact of that inheritance says the class doc. An ugly mess.
Example code
Get the current moment in UTC.
Instant instant = Instant.now();
Storing and fetching that Instant object to/from a database is shown above.
To generate an ISO 8601 string, merely call toString. The java.time classes all use ISO 8601 formats by default for parsing and generating strings of their various date-time values.
String output = instant.toString();
Adjust into any offset-from-UTC by applying a ZoneOffset to get an OffsetDateTime. Call toString to generate a String in ISO 8601 format.
ZoneOffset offset = ZoneOffset.ofHoursMinutes( 5 , 30 );
OffsetDateTime odt = instant.atOffset( offset );
A time zone is an offset plus a set of rules for handling anomalies such as Daylight Saving Time (DST). When you need to see that same moment through the lens of some region’s own wall-clock time, apply a time zone (ZoneId) to get a ZonedDateTime object.
Specify a proper time zone name in the format of continent/region. Never use the 3-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( "Asia/Kolkata" );
ZonedDateTime zdt = instant.atZone( z );
Going the other direction, you can extract an Instant from an OffsetDateTime or ZonedDateTime by calling toInstant.
Instant instant = zdt.toInstant();
Formatting
For presentation to the user as strings in formats other than ISO 8601, search Stack Overflow for use of the DateTimeFormatter class.
While you can specify an custom format, usually best to let java.time automatically localize. To localize, specify:
FormatStyle to determine how long or abbreviated should the string be.
Locale to determine (a) the human language for translation of name of day, name of month, and such, and (b) the cultural norms deciding issues of abbreviation, capitalization, punctuation, and such.
Example:
Locale l = Locale.CANADA_FRENCH ;
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( l );
String output = zdt.format( f );
Conversion
Best to avoid the legacy date-time types whenever possible. But if working with old code not yet updated for the java.time types, you can convert to/from the java.time types. For details, see the Question, Convert java.util.Date to what “java.time” type?.
Use objects
Use objects rather than mere coded primitives and simple strings. For example:
Do not use 1-7 to represent a day-of-week, use the DayOfWeek enum such as DayOfWeek.TUESDAY.
Rather than passing around a string as a date, pass around LocalDate objects.
Rather than pass around a pair of integers for a year-and-month, pass around YearMonth objects.
Instead of 1-12 for a month, use the much more readable Month enum such as Month.JANUARY.
Using such objects makes your code more self-documenting, ensures valid values, and provides type-safety.
To get the discussion started, here's been my experience:
When creating standards for a typical 3-tier Java Enterprise project, I would generally recommend that the project use GregorianCalendar for manipulating dates. Reason is GregorianCalendar is the de facto standard over any other Calendar instance e.g. Julian calendar etc. It's the recognized calendar in most countries and properly handles leap years, etc. On top of that, I would recommend that the application store its dates as UTC so that you can easily perform date calculations such as finding the difference between two dates (if it were stored as EST for example, you'd have to take day light savings time into account). The date can be then be localized to whatever timezone you need it to be displayed to the user as -- such as localizing it to EST if you are an east-coast US company and you want your time information shown in EST.

Categories

Resources