Java is not storing accurate date to mysql database - java

I was writing a program to convert string to java.util.Date object and then store the same in the database, the program is running correctly with no errors. But in the MySql the date is not stored correctly, java is storing date which is a yesterday date with respect to date written in the string.
Example- If I write "2018-11-10", it stores "2018-11-09".
My code-
import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class Demo {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Connection con;
Class.forName("com.mysql.cj.jdbc.Driver");
Date date = Date.valueOf("2018-11-20");
con = DriverManager.getConnection("jdbc:mysql://localhost:9090/ProjectScheduler", "root", "tiger");
PreparedStatement prepare = con.prepareStatement("insert into SchedulerDB(Date) values(?)");
prepare.setDate(1, date);
prepare.executeUpdate();
}
}
In MySql workbench, I created table as
create table SchedulerDB(Date date)
when I run select query to see data in table using
select * from SchedulerDB
Then under the column "Date" in the table- "SchedulerDB", I got 2018-11-19. But I want 2018-11-20 as this is what I wrote in java code. Please help me in solving this problem.

tl;dr
myPreparedStatement.setObject(
… ,
LocalDate.parse( "2018-11-20")
) ;
Details
You are using the terribly designed java.sql.Date class. This class unfortunately is a subclass of java.util.Date though the documentation strangely tells us to ignore that fact of inheritance. So while java.sql.Date pretends to represent a date only, it is in fact a moment, a date with a time-of-day set to midnight in some zone and then adjusted to UTC. This is a wretched design, and is one of many reasons to never use the legacy date-time classes.
For a DATE column in SQL, use the modern LocalDate class instead.
LocalDate
The LocalDate class truly represents a date-only value, without time-of-day and without time zone or offset-from-UTC.
For database column of a type akin to the SQL-standard DATE type, use the LocalDate class in Java.
LocalDate ld = LocalDate.parse( "2018-11-20" );
JDBC 4.2
As of JDBC 4.2, we can directly exchange java.time objects with the database.
myPreparedStatement.setObject( … , ld ) ;
Retrieval:
LocalDate ld = myResultSet.getObject( … , LocalDate.class ) ;
With no time zone involved, your retrieved value will be the same 2018-11-20 that you stored.
Example app
Here is a complete example app using the H2 Database Engine. As a demo, I have it set to write to an in-memory database rather than persisting to actual storage.
We create a database with a single table, with two columns:
a sequential number primary key named pkey_
a DATE column named when_
We insert a couple LocalDate objects, and then retrieve the rows to dump to console.
package com.basilbourque.example;
import java.sql.*;
import java.time.LocalDate;
import java.util.List;
public class EventDate {
public static void main ( String[] args ) {
EventDate app = new EventDate();
app.doIt();
}
private void doIt ( ) {
final String driverName = "org.h2.Driver";
final String catalogName = "event_demo_db";
final String jdbcPath = "jdbc:h2:mem:" + catalogName + ";DB_CLOSE_DELAY=-1"; // Set delay to keep in-memory database even after last connection closed.
// Verify JDBC driver.
try {
Class.forName( driverName );
} catch ( ClassNotFoundException e ) {
e.printStackTrace();
}
// Connect, and create database.
try (
Connection conn = DriverManager.getConnection( jdbcPath ) ;
) {
String sql = null;
// Create table.
try ( Statement stmt = conn.createStatement() ; ) {
sql = "CREATE TABLE " + "event_" + " ( \n" +
" pkey_ IDENTITY PRIMARY KEY , \n" +
" when_ DATE NOT NULL \n" +
") ; \n";
System.out.println( "TRACE - SQL:\n" + sql );
stmt.execute( sql );
}
System.out.println( "TRACE - Created table `event_`." );
// Add rows
sql = "INSERT INTO event_ ( when_ ) \n" +
"VALUES ( ? ) " +
"; ";
List < LocalDate > dates = List.of( LocalDate.parse( "2018-11-10" ) , LocalDate.parse( "2018-12-31" ) );
System.out.println( "Inserting list of LocalDate objects: " + dates );
try (
PreparedStatement ps = conn.prepareStatement( sql ) ;
) {
for ( LocalDate localDate : dates ) {
ps.setObject( 1 , localDate );
ps.executeUpdate();
}
}
// Retrieve rows
sql = "SELECT * FROM " + "event_" + " ;";
try (
Statement stmt = conn.createStatement() ;
ResultSet rs = stmt.executeQuery( sql ) ;
) {
while ( rs.next() ) {
int pkey = rs.getInt( "pkey_" );
LocalDate when = rs.getObject( "when_" , LocalDate.class );
System.out.println( "Row pkey_: " + pkey + " when_: " + when );
}
}
} catch ( SQLException e ) {
e.printStackTrace();
}
}
}
When run.
Inserting list of LocalDate objects: [2018-11-10, 2018-12-31]
Row pkey_: 1 when_: 2018-11-10
Row pkey_: 2 when_: 2018-12-31
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.

Related

Split a time period into hourly intervals

How do I divide a time period (10:00:00PM - 20:30:00PM) into hourly intervals using java to get the following result?
10:00:00 - 11:00:00
11:00:00 - 12:00:00
12:00:00 - 13:00:00
13:00:00 - 14:00:00
15:00:00 - 16:00:00
16:00:00 - 17:00:00
17:00:00 - 18:00:00
19:00:00 - 20:00:00
20:00:00 - 20:30:00
Make a LocalTime of the start and stop.
Add an hour to the start.
LocalTime lt = start.plusHours( 1 ) ;
Notice the immutable objects. Rather than alter the original object, we get a fresh new LocalTime object.
Compare to the stop by calling the isBefore, isAfter, and isEqual methods. If not yet past the stop, add another hour. If going past the stop, then use the stop itself rather than the next hour.
Collect into a List < LocalTime>.
If you want to track each entry as pair of LocalTime objects, define a class named something like TimeSlot with a pair of LocalTime member fields. The new Records feature previewed in Java 14 would do nicely here.
All this has been covered many times already on Stack Overflow. Search to learn more.
Example app
Here is a working example app. This uses the new Records feature defined in JEP 359: Records (Preview), previewed in Java 14, working in IntelliJ 2020.1 IDE.
package work.basil.example;
import java.time.Duration;
import java.time.LocalTime;
public record LocalTimeRange(LocalTime start , LocalTime stop)
{
}
We can fancy that up a bit.
We override toString to produce text in one of the four standard ISO 8601 format: HH:MM/HH:MM. We define an enum for the four types of formats specified by ISO 8601 for time intervals. Our format method takes one of those flags to produce text in one of the four standard formats.
We produce a Duration object if asked. This class represents a span-of-time not attached to the timeline on a scale of hours-minutes-seconds.
Because this is a record, we need not override equals & hashCode. Nor do we need getter methods for the parts of start and end LocalTime objects.
package work.basil.example;
import java.time.Duration;
import java.time.LocalTime;
public record LocalTimeRange(LocalTime start , LocalTime end)
{
public enum Format
{ START_AND_END, START_AND_DURATION, DURATION_AND_END, DURATION_ONLY } // Per ISO 8601 standard.
#Override
public String toString ( ) { return this.format( Format.START_AND_END ); } // Per ISO 8601 standard.
public Duration toDuration ( ) { return Duration.between( this.start , this.end ); }
public String format ( LocalTimeRange.Format format )
{
return switch ( format )
{
case START_AND_END -> this.start + "/" + this.end;
case START_AND_DURATION -> this.start.toString() + "/" + this.toDuration().toString();
case DURATION_AND_END -> this.toDuration().toString() + "/" + this.end.toString();
case DURATION_ONLY -> this.toDuration().toString();
};
}
}
We need a method to create the hourly time ranges.
private List < LocalTimeRange > hourlyRanges ( final LocalTime start , final LocalTime stop )
{
// Verify arguments
Objects.requireNonNull( start , "Received null time-of-day for start. Message # 51521a5c-5f49-4c74-98e3-fce2587edf77." );
Objects.requireNonNull( stop , "Received null time-of-day for stop. Message # 41b98429-4edb-4209-a12f-e266dcae4a90." );
// Logic
int initialCapacity = java.lang.Math.toIntExact( Duration.between( start , stop ).toHours() + 1 ); // Returns the value of the long argument; throwing an exception if the value overflows an int.
ArrayList < LocalTimeRange > ranges = new ArrayList <>( initialCapacity );
LocalTime localTime = start;
while ( ! localTime.isAfter( stop ) )
{
LocalTimeRange range = null;
LocalTime hourLater = localTime.plusHours( 1 );
if ( ! hourLater.isAfter( stop ) )
{
range = new LocalTimeRange( localTime , hourLater );
} else
{
range = new LocalTimeRange( localTime , stop );
}
Objects.requireNonNull( range );
ranges.add( range );
// Prepare for next loop.
localTime = hourLater;
}
ranges.trimToSize();
return Objects.requireNonNull( ranges );
}
And some code to exercise it.
LocalTime start = LocalTime.parse( "10:00:00" );
LocalTime end = LocalTime.parse( "20:30:00" );
List < LocalTimeRange > ranges = this.hourlyRanges( start , end );
System.out.println( "ranges = " + ranges );
System.out.println( ranges.stream().map( range -> range.toDuration() ).collect( Collectors.toList() ) );
System.out.println( ranges.stream().map( range -> range.format( LocalTimeRange.Format.START_AND_END ) ).collect( Collectors.toList() ) );
System.out.println( ranges.stream().map( range -> range.format( LocalTimeRange.Format.START_AND_DURATION ) ).collect( Collectors.toList() ) );
System.out.println( ranges.stream().map( range -> range.format( LocalTimeRange.Format.DURATION_AND_END ) ).collect( Collectors.toList() ) );
System.out.println( ranges.stream().map( range -> range.format( LocalTimeRange.Format.DURATION_ONLY ) ).collect( Collectors.toList() ) );
When run:
ranges = [10:00/11:00, 11:00/12:00, 12:00/13:00, 13:00/14:00, 14:00/15:00, 15:00/16:00, 16:00/17:00, 17:00/18:00, 18:00/19:00, 19:00/20:00, 20:00/20:30]
[PT1H, PT1H, PT1H, PT1H, PT1H, PT1H, PT1H, PT1H, PT1H, PT1H, PT30M]
[10:00/11:00, 11:00/12:00, 12:00/13:00, 13:00/14:00, 14:00/15:00, 15:00/16:00, 16:00/17:00, 17:00/18:00, 18:00/19:00, 19:00/20:00, 20:00/20:30]
[10:00/PT1H, 11:00/PT1H, 12:00/PT1H, 13:00/PT1H, 14:00/PT1H, 15:00/PT1H, 16:00/PT1H, 17:00/PT1H, 18:00/PT1H, 19:00/PT1H, 20:00/PT30M]
[PT1H/11:00, PT1H/12:00, PT1H/13:00, PT1H/14:00, PT1H/15:00, PT1H/16:00, PT1H/17:00, PT1H/18:00, PT1H/19:00, PT1H/20:00, PT30M/20:30]
[PT1H, PT1H, PT1H, PT1H, PT1H, PT1H, PT1H, PT1H, PT1H, PT1H, PT30M]
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 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….
This solved part of my problem:
private ArrayList<String> setInterval(String start, String stop) throws ParseException {
String strStart;
String strEnd;
ArrayList<String> arrayList = new ArrayList<>();
SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss", Locale.getDefault());
Date dStart = df.parse(start);
Date dStop = df.parse(stop);
Calendar cal = Calendar.getInstance();
cal.setTime(dStart);
cal.add(Calendar.HOUR, 1); //minus number would decrement the days
while (cal.getTime().before(dStop)) {
strStart = df.format(cal.getTime());
cal.add(Calendar.HOUR, 1);
strEnd = df.format(cal.getTime());
arrayList.add(strStart + " - " + strEnd);
}
return arrayList;
}

How does JDBC/Postgres compare a timezone-less java.util.Date with a Timestamp?

We have a Postgres table that has two TIMESTAMP WITHOUT TIME ZONE columns, prc_sta_dt and prc_end_dt. We check to see whether a java.util.Date falls in between the start and end dates.
Here is some of the Java code, which is simplified but gets the point across.
// This format expects a String such as 2018-12-03T10:00:00
// With a date and a time, but no time zone
String timestamp = "2018-12-03T10:00:00";
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
Date searchDate = formatter.parse(timestamp);
// Here's the Postgres query
String query = "select promotion_cd from promotions " +
"where prc_sta_dt <= :srch_dt and prc_end_dt >= :srch_dt";
Map<String, Object> map = new HashMap<String, Object>();
map.put("srch_dt", searchDate);
List<Promotion> promotions = jdbcTemplate.query(query, map, promotionMapper);
In our Postgres table, we have promotions that start at 9am on 12/3/2018 and end at 3pm on the same day. The prc_sta_dt and prc_end_dt colums in our database for these rows are 2018-12-03 09:00:00.0 and 2018-12-03 15:00:00.0
Question: When JDBC/Postgres accepts our searchDate and compares it to these timestamps, will it accept the given search date of 10am (2018-12-03T10:00:00) or will it treat this time as being under the time zone that the server is running on, and then convert that to UTC?
For example, if the server is running in Chicago, then will it interpret 10 am as 10am CST and then convert that to 4pm UTC before doing the comparison in the database? If so then we're out of luck!
I doubt this would happen, but I just want to make sure so there are no surprises.
Wrong data type, Date is not a date
A java.util.Date object represents a moment in UTC, a specific point on the timeline. So it represents the combination of a date, a time-of-day, and an offset-from-UTC of zero (for UTC itself). Among the many poor design choices in this terrible class is its misleading name that has confused countless Java programmers.
TIMESTAMP WITHOUT TIME ZONE
If you care about moments, then your database column should not be of type TIMESTAMP WITHOUT TIME ZONE. That data type represents a date and a time-of-day without any concept of time zone or offset-from-UTC. As such, by definition, that type cannot represent a moment, is not a point on the timeline. This type should only be used when you mean a date-with-time anywhere or everywhere.
Examples:
“Christmas starts after stroke of midnight at beginning of December 25, 2018” where Christmas in Kiribati comes first, India later, and Africa even later.
“Company-wide memo: Each of our factories in Delhi, Düsseldorf, and Detroit will close one hour early at 16:00 on January 21st” where 4 PM at each factory is three different moments, each several hours apart.
TIMESTAMP WITH TIME ZONE
When tracking specific a specific moment, a single point on the timeline, use a column of type TIMESTAMP WITH TIME ZONE. In Postgres, such values are stored in UTC. Any time zone or offset info submitted with an input is used to adjust into UTC, then the zone/offset info is discarded.
BEWARE: Some tools may have the well-intentioned but unfortunate anti-feature of injecting a time zone after retrieving the value in UTC, thereby misrepresenting what was actually stored.
Comparing a moment to values of TIMESTAMP WITHOUT TIME ZONE
As for comparing a moment to values in your column of type TIMESTAMP WITHOUT TIME ZONE, doing so would generally not make sense.
But if you are clear-headed and educated about date-time handling, and making this comparison is sensible in your business logic, let's forge on.
Wrong classes
You are using lousy, terrible, awful date-time classes (Date, SimpleDateFormat, etc.) that were supplanted years ago by the java.time classes. Do yourself a favor: Stop using the legacy date-time classes. Use only java.time.
If given a moment as a java.util.Date, use the new methods added to the old classes to convert. In particular, java.util.Date is replaced by Instant.
Instant instant = myJavaUtilDate.toInstant() ; // Convert from legacy class to modern class.
Specify the time zone in which you want to adjust your Instant moment in UTC for comparison. For example, if your database was built by someone who did not understand proper date-time handling, and has been using the TIMESTAMP WITHOUT TIME ZONE column to store date-with-time values that were taken from the wall-clock time of Québec, then use the time zone America/Montreal.
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( "America/Montreal" ) ;
Apply that zone to our Instant to get a ZonedDateTime object.
ZonedDateTime zdt = instant.atZone( z ) ;
Our resulting ZonedDateTime object represents the same moment as the Instant object, same point on the timeline, but viewed with a different wall-clock time.
To hammer a square-peg into a round-hole, let's convert that ZonedDateTime object to a LocalDateTime object, thereby stripping away the time zone information and leaving only a date-with-time-of-day value.
LocalDateTime ldt = zdt.toLocalDateTime() ;
Half-Open
where prc_sta_dt <= :srch_dt and prc_end_dt >= :srch_dt
That logic is prone to failure. Generally, the best practice in date-time handling when defining a span-of-time to use Half-Open, where the beginning is inclusive while the ending is exclusive.
So use this:
WHERE instant >= start_col AND instant < stop_col ;
For a PreparedStatement, we would have placeholders.
WHERE ? >= start_col AND ? < stop_col ;
On the Java side, as of JDBC 4.2 we can directly exchange java.time objects with the database via getObject and setObject methods.
You might be able to pass an Instant depending on your JDBC driver. Support for Instant is not required by the JDBC spec. So try it, or read the doc for your driver.
myPreparedStatement.setObject( 1 , instant ) ;
myPreparedStatement.setObject( 2 , instant ) ;
If Instant is not supported, convert from Instant to an OffsetDateTime set to UTC. Support for OffsetDateTime is required by the spec.
myPreparedStatement.setObject( 1 , instant.atOffset( ZoneOffset.UTC ) ) ;
myPreparedStatement.setObject( 2 , instant.atOffset( ZoneOffset.UTC ) ) ;
Retrieval.
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
Always specify time zone
For example, if the server is running in Chicago, then will it interpret 10 am as 10am CST and then convert that to 4pm UTC before doing the comparison in the database?
A programmer should never depend on the time zone (or locale, by the way) currently set as the default on the host OS or JVM. Both are out of your control. And both can change at any moment during runtime!
Always specify the time zone by passing the optional argument to various date-time methods. Making those optional was a design flaw in java.time in my opinion, as programmers all too often ignore the issue of time zone, at their own peril. But that is one of very few design flaws in an amazingly useful and elegant framework.
Notice in our code above we specified the desired/expected time zone. The current default time zone of our host OS, our Postgres database connection, and our JVM will not alter the behavior of our code.
Current moment
If you want the current moment use any of these:
Instant.now()Always in UTC, by definition.
OffsetDateTime.now( someZoneOffset )Current moment as seen in the wall-clock time of a particular offset-from-UTC.
ZonedDateTime.now( someZoneId )Current moment as seen in the wall-clock time used by the people living in a particular region.
Java 7 and ThreeTen-Backport
If you are using Java 7, then you have no java.time classes built-in. Fortunately, the inventor of JSR 310 and java.time, Stephen Colebourne, also led the ThreeTen-Backport project to produce a library providing most of the java.time functionality to Java 6 & 7.
Here is a complete example app in a single .java file showing the use of back-port in Java 7 with the H2 Database Engine.
In Java 7, JDBC 4.2 is not available, so we cannot directly use the modern classes. We fall back to using java.sql.Timestamp which actually represents a moment in UTC, but which H2 stores into a column of TIMESTAMP WITHOUT TIME ZONE taking the date and the time-of-day as-is (using the wall-clock time of UTC) while ignoring the UTC aspect. I have not tried this in Postgres, but I expect you will see the same behavior.
package com.basilbourque.example;
import java.sql.*;
import org.threeten.bp.*;
public class App {
static final public String databaseConnectionString = "jdbc:h2:mem:localdatetime_example;DB_CLOSE_DELAY=-1"; // The `DB_CLOSE_DELAY=-1` keeps the in-memory database around for multiple connections.
public static void main ( String[] args ) {
App app = new App();
app.doIt();
}
private void doIt () {
System.out.println( "Bonjour tout le monde!" );
// java.sql.Timestamp ts = DateTimeUtils.toSqlTimestamp( ZonedDateTime.of( 2018 , 1 , 23 , 12 , 30 , 0 , 0 , ZoneId.of( "America/Montreal" ) ).toLocalDateTime() );
// System.out.println( ts );
this.makeDatabase();
java.util.Date d = new java.util.Date(); // Capture the current moment using terrible old date-time class that is now legacy, supplanted years ago by the class `java.time.Instant`.
this.fetchRowsContainingMoment( d );
}
private void makeDatabase () {
try {
Class.forName( "org.h2.Driver" );
} catch ( ClassNotFoundException e ) {
e.printStackTrace();
}
try (
Connection conn = DriverManager.getConnection( databaseConnectionString ) ; // The `mem` means “In-Memory”, as in “Not persisted to disk”, good for a demo.
Statement stmt = conn.createStatement() ;
) {
String sql = "CREATE TABLE event_ ( \n" +
" pkey_ IDENTITY NOT NULL PRIMARY KEY , \n" +
" name_ VARCHAR NOT NULL , \n" +
" start_ TIMESTAMP WITHOUT TIME ZONE NOT NULL , \n" +
" stop_ TIMESTAMP WITHOUT TIME ZONE NOT NULL \n" +
");";
stmt.execute( sql );
// Insert row.
sql = "INSERT INTO event_ ( name_ , start_ , stop_ ) VALUES ( ? , ? , ? ) ;";
try (
PreparedStatement preparedStatement = conn.prepareStatement( sql ) ;
) {
preparedStatement.setObject( 1 , "Alpha" );
// We have to “fake it until we make it”, using a `java.sql.Timestamp` with its value in UTC while pretending it is not in a zone or offset.
// The legacy date-time classes lack a way to represent a date with time-of-day without any time zone or offset-from-UTC.
// The legacy classes have no counterpart to `TIMESTAMP WITHOUT TIME ZONE` in SQL, and have no counterpart to `java.time.LocalDateTime` in Java.
preparedStatement.setObject( 2 , DateTimeUtils.toSqlTimestamp( ZonedDateTime.of( 2018 , 1 , 23 , 12 , 30 , 0 , 0 , ZoneId.of( "America/Montreal" ) ).toLocalDateTime() ) );
preparedStatement.setObject( 3 , DateTimeUtils.toSqlTimestamp( ZonedDateTime.of( 2018 , 2 , 23 , 12 , 30 , 0 , 0 , ZoneId.of( "America/Montreal" ) ).toLocalDateTime() ) );
preparedStatement.executeUpdate();
preparedStatement.setString( 1 , "Beta" );
preparedStatement.setObject( 2 , DateTimeUtils.toSqlTimestamp( ZonedDateTime.of( 2018 , 4 , 23 , 14 , 30 , 0 , 0 , ZoneId.of( "America/Montreal" ) ).toLocalDateTime() ) );
preparedStatement.setObject( 3 , DateTimeUtils.toSqlTimestamp( ZonedDateTime.of( 2018 , 5 , 23 , 14 , 30 , 0 , 0 , ZoneId.of( "America/Montreal" ) ).toLocalDateTime() ) );
preparedStatement.executeUpdate();
preparedStatement.setString( 1 , "Gamma" );
preparedStatement.setObject( 2 , DateTimeUtils.toSqlTimestamp( ZonedDateTime.of( 2018 , 11 , 23 , 16 , 30 , 0 , 0 , ZoneId.of( "America/Montreal" ) ).toLocalDateTime() ) );
preparedStatement.setObject( 3 , DateTimeUtils.toSqlTimestamp( ZonedDateTime.of( 2018 , 12 , 23 , 16 , 30 , 0 , 0 , ZoneId.of( "America/Montreal" ) ).toLocalDateTime() ) );
preparedStatement.executeUpdate();
}
} catch ( SQLException e ) {
e.printStackTrace();
}
}
private void fetchRowsContainingMoment ( java.util.Date moment ) {
// Immediately convert the legacy class `java.util.Date` to a modern `java.time.Instant`.
Instant instant = DateTimeUtils.toInstant( moment );
System.out.println( "instant.toString(): " + instant );
String sql = "SELECT * FROM event_ WHERE ? >= start_ AND ? < stop_ ORDER BY start_ ;";
try (
Connection conn = DriverManager.getConnection( databaseConnectionString ) ;
PreparedStatement pstmt = conn.prepareStatement( sql ) ;
) {
java.sql.Timestamp ts = DateTimeUtils.toSqlTimestamp( instant );
pstmt.setTimestamp( 1 , ts );
pstmt.setTimestamp( 2 , ts );
try ( ResultSet rs = pstmt.executeQuery() ; ) {
while ( rs.next() ) {
//Retrieve by column name
Integer pkey = rs.getInt( "pkey_" );
String name = rs.getString( "name_" );
java.sql.Timestamp start = rs.getTimestamp( "start_" );
java.sql.Timestamp stop = rs.getTimestamp( "stop_" );
// Instantiate a `Course` object for this data.
System.out.println( "Event pkey: " + pkey + " | name: " + name + " | start: " + start + " | stop: " + stop );
}
}
} catch ( SQLException e ) {
e.printStackTrace();
}
}
}
When run.
instant.toString(): 2018-12-04T05:06:02.573Z
Event pkey: 3 | name: Gamma | start: 2018-11-23 16:30:00.0 | stop: 2018-12-23 16:30:00.0
Java 8 without ThreeTen-Backport
And here is that same example, conceptually, but in Java 8 or later where we can use the java.time classes built-in without the ThreeTen-Backport library.
package com.basilbourque.example;
import java.sql.*;
import java.time.*;
public class App {
static final public String databaseConnectionString = "jdbc:h2:mem:localdatetime_example;DB_CLOSE_DELAY=-1"; // The `DB_CLOSE_DELAY=-1` keeps the in-memory database around for multiple connections.
public static void main ( String[] args ) {
App app = new App();
app.doIt();
}
private void doIt ( ) {
System.out.println( "Bonjour tout le monde!" );
this.makeDatabase();
java.util.Date d = new java.util.Date(); // Capture the current moment using terrible old date-time class that is now legacy, supplanted years ago by the class `java.time.Instant`.
this.fetchRowsContainingMoment( d );
}
private void makeDatabase ( ) {
try {
Class.forName( "org.h2.Driver" );
} catch ( ClassNotFoundException e ) {
e.printStackTrace();
}
try (
Connection conn = DriverManager.getConnection( databaseConnectionString ) ; // The `mem` means “In-Memory”, as in “Not persisted to disk”, good for a demo.
Statement stmt = conn.createStatement() ;
) {
String sql = "CREATE TABLE event_ ( \n" +
" pkey_ IDENTITY NOT NULL PRIMARY KEY , \n" +
" name_ VARCHAR NOT NULL , \n" +
" start_ TIMESTAMP WITHOUT TIME ZONE NOT NULL , \n" +
" stop_ TIMESTAMP WITHOUT TIME ZONE NOT NULL \n" +
");";
stmt.execute( sql );
// Insert row.
sql = "INSERT INTO event_ ( name_ , start_ , stop_ ) VALUES ( ? , ? , ? ) ;";
try (
PreparedStatement preparedStatement = conn.prepareStatement( sql ) ;
) {
preparedStatement.setObject( 1 , "Alpha" );
// We have to “fake it until we make it”, using a `java.sql.Timestamp` with its value in UTC while pretending it is not in a zone or offset.
// The legacy date-time classes lack a way to represent a date with time-of-day without any time zone or offset-from-UTC.
// The legacy classes have no counterpart to `TIMESTAMP WITHOUT TIME ZONE` in SQL, and have no counterpart to `java.time.LocalDateTime` in Java.
preparedStatement.setObject( 2 , ZonedDateTime.of( 2018 , 1 , 23 , 12 , 30 , 0 , 0 , ZoneId.of( "America/Montreal" ) ).toLocalDateTime() );
;
preparedStatement.setObject( 3 , ZonedDateTime.of( 2018 , 2 , 23 , 12 , 30 , 0 , 0 , ZoneId.of( "America/Montreal" ) ).toLocalDateTime() );
preparedStatement.executeUpdate();
preparedStatement.setString( 1 , "Beta" );
preparedStatement.setObject( 2 , ZonedDateTime.of( 2018 , 4 , 23 , 14 , 30 , 0 , 0 , ZoneId.of( "America/Montreal" ) ).toLocalDateTime() );
preparedStatement.setObject( 3 , ZonedDateTime.of( 2018 , 5 , 23 , 14 , 30 , 0 , 0 , ZoneId.of( "America/Montreal" ) ).toLocalDateTime() );
preparedStatement.executeUpdate();
preparedStatement.setString( 1 , "Gamma" );
preparedStatement.setObject( 2 , ZonedDateTime.of( 2018 , 11 , 23 , 16 , 30 , 0 , 0 , ZoneId.of( "America/Montreal" ) ).toLocalDateTime() );
preparedStatement.setObject( 3 , ZonedDateTime.of( 2018 , 12 , 23 , 16 , 30 , 0 , 0 , ZoneId.of( "America/Montreal" ) ).toLocalDateTime() );
preparedStatement.executeUpdate();
}
} catch ( SQLException e ) {
e.printStackTrace();
}
}
private void fetchRowsContainingMoment ( java.util.Date moment ) {
// Immediately convert the legacy class `java.util.Date` to a modern `java.time.Instant`.
Instant instant = moment.toInstant();
System.out.println( "instant.toString(): " + instant );
String sql = "SELECT * FROM event_ WHERE ? >= start_ AND ? < stop_ ORDER BY start_ ;";
try (
Connection conn = DriverManager.getConnection( databaseConnectionString ) ;
PreparedStatement pstmt = conn.prepareStatement( sql ) ;
) {
pstmt.setObject( 1 , instant );
pstmt.setObject( 2 , instant );
try ( ResultSet rs = pstmt.executeQuery() ; ) {
while ( rs.next() ) {
//Retrieve by column name
Integer pkey = rs.getInt( "pkey_" );
String name = rs.getString( "name_" );
Instant start = rs.getObject( "start_" , OffsetDateTime.class ).toInstant();
Instant stop = rs.getObject( "stop_" , OffsetDateTime.class ).toInstant();
// Instantiate a `Course` object for this data.
System.out.println( "Event pkey: " + pkey + " | name: " + name + " | start: " + start + " | stop: " + stop );
}
}
} catch ( SQLException e ) {
e.printStackTrace();
}
}
}
When run.
instant.toString(): 2018-12-04T05:10:54.635Z
Event pkey: 3 | name: Gamma | start: 2018-11-24T00:30:00Z | stop: 2018-12-24T00:30:00Z
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.

Java compareTo Dates cannot be equal

I am trying to compare 2 dates, the first date is from the MySQL database, and the second is from the current date.
as you can see below, there are different dates in the database
But the problem is that I got 3 if statements, which should tell my program if the Database date is before, after or equal the current date. The Before and After statements should work, but it can see the date 2018-06-12 should be equal to the current date so it ends in the "before statement".
Hope you can see what I have done wrong.
private static void Resetter() throws ParseException, SQLException {
String host = "****";
String username = "root";
String mysqlpassword = "";
//Querys
String query = "select * from accounts";
String queryy = "update accounts set daily_search_count = 0 where id = ?";
Connection con = DriverManager.getConnection(host, username, mysqlpassword);
Statement st = con.createStatement();
ResultSet rs = st.executeQuery(query);
DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
dateFormat.setTimeZone( TimeZone.getTimeZone( "UTC" ));
Date currentDate = new Date();
while(rs.next()){
System.out.println(dateFormat.format(currentDate));
if (rs.getDate(5).compareTo(currentDate) > 0) {
// System.out.println("Database-date is after currentDate");
} else if (rs.getDate(5).compareTo(currentDate) < 0) {
// System.out.println("Database-date is before currentDate");
PreparedStatement updatexdd = con.prepareStatement(queryy);
updatexdd.setInt(1, rs.getInt(1));
int updatexdd_done = updatexdd.executeUpdate();
} else if (rs.getDate(5).compareTo(currentDate) == 0) {
// System.out.println("Database-date is equal to currentDate");
} else {
System.out.println("Any other");
}
}
}
tl;dr
LocalDate today = LocalDate.now( ZoneOffset.UTC ) ;
Instant instant = myResultSet.getObject( … , Instant.class ) ; // Retrieve a `TIMESTAMP WITH TIME ZONE` value in database as an `Instant` for a date with time-of-day in UTC with a resolution as fine as nanoseconds.
LocalDate ld = instant.atOffset( ZoneOffset.UTC ).toLocalDate() ; // Extract a date-only value without time-of-day and without time zone.
if ( ld.isBefore( today ) ) { … } // Compare `LocalDate` objects.
else if ( ld.isEqual( today ) ) { … }
else if ( ld.isAfter( today ) ) { … }
else { … handle error }
java.time
You are using, and misusing, troublesome old date-time classes.
As others pointed out:
A SQL-standard DATE type holds only a date without a time-of-day and without a timezone
The legacy java.util.Date class is misnamed, holding both a date and a time-of-day in UTC.
The legacy java.sql.Date class pretends to hold only a date but actually has a time-of-day because this class inherits from the one above, while the documentation tells us to ignore that fact in our usage. (Yes, this is confusing, and is a bad design, a clumsy hack.)
Never use the java.util.Date, java.util.Calendar, java.sql.Timestamp, java.sql.Date, and related classes. Instead, use only the sane java.time classes. They lead the industry in clean-design and depth of understanding of date-time handling gleaned from the experience of their predecessor, the Joda-Time project.
For date-only value, stored in SQL-standard database type of DATE, use java.time.LocalDate.
LocalDate ld = myResultSet.get( … , LocalDate.class ) ; // Retrieving from database.
myPreparedStatement.setObject( … , ld ) ; // Storing in database.
For a date with time-of-day in UTC value, stored in a SQL-standard database type of TIMESTAMP WITH TIME ZONE, use java.time.Instant. 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).
Instant instant = myResultSet.get( … , Instant.class ) ; // Retrieving from database.
myPreparedStatement.setObject( … , instant ) ; // Storing in database.
For comparing in Java, use the isEqual, isBefore, isAfter, equals, or compare methods.
Boolean overdue = someLocalDate.isAfter( otherLocalDate ) ;
Time zone
Time zone is crucial in determining a date and a time-of-day from a moment (Instant/TIMESTAMP WITH TIME ZONE).
After retrieving your TIMESTAMP WITH TIME ZONE value from the database as an Instant, adjust into the time zone or offset-from-UTC whose wall-clock time you want to use in perceiving a date & time-of-day. For a time zone, apply a ZoneId to get a ZonedDateTime object. For an offset-from-UTC, apply a ZoneOffset to get a OffsetDateTime object. In either case, extract a date-only value by calling toLocalDate to get a LocalDate object.
In your case, you apparently want to perceive the date as UTC. So apply the constant, ZoneOffset.UTC to get an OffsetDateTime
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
LocalDate ld = odt.toLocalDate() ; // Extract a date-only value without time-of-day and without time zone.
We want to compare with current date in UTC.
LocalDate today = LocalDate.now( ZoneOffset.UTC ) ; // Specify the offset/zone by which you want to perceive the current date.
Compare.
if ( ld.isBefore( today ) ) { … }
else if ( ld.isEqual( today ) ) { … }
else if ( ld.isAfter( today ) ) { … }
else { … handle error }
ISO 8601
Avoid unnecessarily using custom formats such as "yyyy/MM/dd". Use standard ISO 8601 formats whenever possible.
For a date-only value, that would be YYYY-MM-DD.
String output = LocalDate.now().toString() ; // Ex: 2018-01-23
Example with H2
Here is a full example of writing, querying, and reading LocalDate objects from a database column of SQL-standard DATE type.
Using the H2 Database Engine, as I am not a MySQL user. Creating an in-memory database rather than writing to storage. I assume the code would be nearly the same for MySQL.
try (
Connection conn = DriverManager.getConnection( "jdbc:h2:mem:trashme" )
) {
String sql = "CREATE TABLE " + "tbl_" + " (\n" +
" uuid_ UUID DEFAULT random_uuid() , \n" + // Every table should have a primary key.
" when_ DATE \n" + // Three columns per the Question.
" );";
try (
Statement stmt = conn.createStatement() ;
) {
stmt.execute( sql );
}
sql = "INSERT INTO tbl_ ( when_ ) VALUES ( ? ) ;";
LocalDate start = LocalDate.of( 2018 , Month.JANUARY , 23 );
LocalDate ld = start; // Keep the `start` object for use later.
try (
PreparedStatement ps = conn.prepareStatement( sql )
) {
for ( int i = 1 ; i <= 10 ; i++ ) {
ps.setObject( 1 , ld );
ps.executeUpdate();
// Prepare for next loop.
int randomNumber = ThreadLocalRandom.current().nextInt( 1 , 5 + 1 ); // Pass minimum & ( maximum + 1 ).
ld = ld.plusDays( randomNumber ); // Add a few days, an arbitrary number.
}
}
// Dump all rows, to verify our populating of table.
System.out.println( "Dumping all rows: uuid_ & when_ columns." );
sql = "SELECT uuid_ , when_ FROM tbl_ ; ";
int rowCount = 0;
try (
Statement stmt = conn.createStatement() ;
ResultSet rs = stmt.executeQuery( sql ) ;
) {
while ( rs.next() ) {
rowCount++;
UUID uuid = rs.getObject( 1 , UUID.class );
LocalDate localDate = rs.getObject( 2 , LocalDate.class );
System.out.println( uuid + " " + localDate );
}
}
System.out.println( "Done dumping " + rowCount + " rows." );
// Dump all rows, to verify our populating of table.
System.out.println( "Dumping rows where `when_` is after " + start + ": uuid_ & when_ columns." );
sql = "SELECT uuid_ , when_ FROM tbl_ WHERE when_ > ? ; ";
rowCount = 0; // Reset count.
final PreparedStatement ps = conn.prepareStatement( sql );
ps.setObject( 1 , start );
try (
ps ;
ResultSet rs = ps.executeQuery() ;
) {
while ( rs.next() ) {
rowCount++;
UUID uuid = rs.getObject( 1 , UUID.class );
LocalDate localDate = rs.getObject( 2 , LocalDate.class );
System.out.println( uuid + " " + localDate );
}
}
System.out.println( "Done dumping " + rowCount + " rows." );
} catch ( SQLException eArg ) {
eArg.printStackTrace();
}
When run.
Dumping all rows: uuid_ & when_ columns.
e9c75998-cd67-4ef9-9dce-6c1eed170387 2018-01-23
741c1452-e224-4e5e-95bc-904d8db58b39 2018-01-27
413de43c-a1be-40b6-9ccf-a9b7d9ba873c 2018-01-31
e2aa148f-48b6-4be6-a0fe-f2881b6b5a63 2018-02-03
f498003c-2d8b-446e-ac55-6d7568ce61c3 2018-02-06
c41606d7-8c05-4bba-9f8e-2a0d1f1bb31a 2018-02-09
3df3abe3-1865-4632-99c4-6cd74883c1ee 2018-02-10
914153fe-34f2-4e4f-a91b-944314994839 2018-02-13
96436bdf-80ee-4afe-b55d-f240140ace6a 2018-02-16
82b43f7b-077d-45c1-8c4f-f5b30dfdd44a 2018-02-19
Done dumping 10 rows.
Dumping rows where `when_` is after 2018-01-23: uuid_ & when_ columns.
741c1452-e224-4e5e-95bc-904d8db58b39 2018-01-27
413de43c-a1be-40b6-9ccf-a9b7d9ba873c 2018-01-31
e2aa148f-48b6-4be6-a0fe-f2881b6b5a63 2018-02-03
f498003c-2d8b-446e-ac55-6d7568ce61c3 2018-02-06
c41606d7-8c05-4bba-9f8e-2a0d1f1bb31a 2018-02-09
3df3abe3-1865-4632-99c4-6cd74883c1ee 2018-02-10
914153fe-34f2-4e4f-a91b-944314994839 2018-02-13
96436bdf-80ee-4afe-b55d-f240140ace6a 2018-02-16
82b43f7b-077d-45c1-8c4f-f5b30dfdd44a 2018-02-19
Done dumping 9 rows.
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.
ResultSet#getDate returns a date with the time part removed. Instantiating a new Date object does contain the time, so you'll have to remove it yourself. E.g.:
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
Date currentDate = cal.getTime();
It all depends on the Java version that you are using. If you are using Java 6 or Java 7 then this approach will be the easiest:
As you are dealing with java.sql.Date anyways, you can use this quick approach to get Date without time part and compare java.sql.Date to java.sql.Date:
Date currentDate = new java.sql.Date(System.currentTimeMillis());
You can also use java.util.Date#before and java.util.Date#after methods for the better code readability:
while(rs.next()){
System.out.println(dateFormat.format(currentDate));
if (rs.getDate(5).after(currentDate)) {
// System.out.println("Database-date is after currentDate");
} else if (rs.getDate(5).before(currentDate)) {
// System.out.println("Database-date is before currentDate");
PreparedStatement updatexdd = con.prepareStatement(queryy);
updatexdd.setInt(1, rs.getInt(1));
int updatexdd_done = updatexdd.executeUpdate();
} else {
// System.out.println("Database-date is equal to currentDate");
}
}
If you are using Java 8 then you can use new Java time API.

Date difference in different timezones in java

I am pragmatically building a nested JSON from a table. Json looks something like this:
{"date":"03-16-2018 06:57:02",
"details":
[
{
"motorstate":0,
"startTime":"03-16-2018 20:41:57",
},
{
"motorstate":0,
"startTime":"03-16-2018 06:57:02",
}
]
},
{"date":"03-15-2018 08:08:48",
"details":
[
{
"motorstate":0,
"startTime":"03-16-2018 03:53:30",
}
]
}
If you look into the above example, the second record:
{"date":"03-15-2018 08:08:48",
"details":
[
{
"motorstate":0,
"startTime":"03-16-2018 03:53:30",
}
]
}
The dates are mismatching. This is because the date shown here is in IST but actually stored in UTC in my Google Datastore. In UTC, its still 03-15-2018 and not 03-16-2018.
My question is how can we perform a date difference in different timezones other than UTC in Java? The Date.getTime() method always give the difference in UTC and not in local Timezone.
tl;dr
Date difference in different timezones in java
Period.between(
LocalDateTime.parse(
"03-15-2018 08:08:48" ,
DateTimeFormatter.ofPattern( “MM-dd-uuuu HH:mm:ss” )
)
.atZone( ZoneId.of( ”Asia/Kolkata" ) )
.toLocalDate()
,
LocalDate.now( ZoneId.of( ”Asia/Kolkata" ) )
)
Details
The modern approach uses the java.time classes rather than the troublesome old me old legacy date-time classes such as Date and Calendar.
Tip: Avoid custom formatting patterns when serializing date-time values to text. Use standard ISO 8601 formats only.
Tip: when exchanging date-time values as text, always include an indicator of the offset-from-UTC and the time zone name.
First, parse your input strings as LocalDateTime because they lack any indication of offset or zone.
Define a formatting pattern to match input.
DateTimeFormatter f = DateTimeFormatter.ofPattern( “MM-dd-uuuu HH:mm:ss” ) ;
Parse.
String input = "03-15-2018 08:08:48" ;
LocalDateTime ldt = LocalDateTime.parse( input , f ) ;
You claim to know that these inputs were intended to represent a moment in India time. Apply a ZoneId to get a ZonedDateTime.
ZoneId z = ZoneId.of( ”Asia/Kolkata" ) ;
ZonedDateTime zdt = ldt.atZone( z ) ;
To get the date-only value, extract a LocalDate.
LocalDate ld = zdt.toLocalDate() ;
To represent the delta between dates as a number of years, months, and days unattached to the timeline, use Period.
Period p = Period.between( ldt , LocalDate.now( z ) ) ;
For a count of total days.
long days = ChronoUnit.DAYS.between( start , stop ) ;
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, 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.
public String getSummary(String deviceGuid)
{
Query<com.google.cloud.datastore.Entity> query
= Query.newEntityQueryBuilder()
.setKind("sensordata")
.setFilter(PropertyFilter.eq("deviceguid", deviceGuid))
.setOrderBy(OrderBy.desc("startTime"))
.build();
QueryResults<com.google.cloud.datastore.Entity> resultList =
datastore.run(query);
if(!resultList.hasNext())
{
log.warning("No record found..");
return "No record found";
}
com.google.cloud.datastore.Entity e =null;
com.google.cloud.datastore.Entity pe =null;
SensorDataOut sensorDataOut = new SensorDataOut();
SensorSummaryDataOut summary = new SensorSummaryDataOut();
TotalSummaryDataOut totalSummary = new TotalSummaryDataOut();
Calendar calendar = Calendar.getInstance();
calendar.setTimeZone(TimeZone.getTimeZone("IST"));
Calendar calendar1 = Calendar.getInstance();
calendar1.setTimeZone(TimeZone.getTimeZone("IST"));
SimpleDateFormat sdf = new SimpleDateFormat("MM-dd-yyyy HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("IST"));
SimpleDateFormat sdf1 = new SimpleDateFormat("MM-dd-yyyy");
//sdf.setTimeZone(TimeZone.getTimeZone("IST"));
long stopTime;
long startTime;
long pStartTime;
long diffTime;
long diffDay;
Date pDateWithoutTime;
Date eDateWithoutTime;
while(resultList.hasNext())
{
e = resultList.next();
startTime = (e.contains("startTime"))?e.getTimestamp("startTime").toSqlTimestamp().getTime():0;
stopTime = (e.contains("stopTime"))?e.getTimestamp("stopTime").toSqlTimestamp().getTime():0;
//log.info("Start Date : " + e.getTimestamp("startTime").toString() + " - " + String.valueOf(startTime));
//log.info("Stop Date : " + e.getTimestamp("stopTime").toString() + " - " + String.valueOf(stopTime));
//log.info("Usage Volume :" + String.valueOf(e.getLong("usageVolume")));
sensorDataOut = new SensorDataOut();
calendar.setTimeInMillis(stopTime);
sensorDataOut.stopTime = sdf.format(calendar.getTime());
calendar.setTimeInMillis(startTime);
sensorDataOut.startTime = sdf.format(calendar.getTime());
sensorDataOut.motorstate = (e.contains("motorstate"))?(int)e.getLong("motorstate"):-1;
sensorDataOut.startVolume = (e.contains("startVolume"))?(int)e.getLong("startVolume"):-1;
sensorDataOut.stopVolume = (e.contains("stopVolume"))?(int)e.getLong("stopVolume"):-1;
sensorDataOut.usageTime = (e.contains("usageTime"))?e.getLong("usageTime"):-1;
sensorDataOut.usageVolume = (e.contains("usageVolume"))?(int)e.getLong("usageVolume"):-1;
if(pe!=null)
{
//Get the date difference in terms of days. If it is same day then add the volume consumed
pStartTime= pe.getTimestamp("startTime").toSqlTimestamp().getTime();
try{
calendar.setTimeInMillis(pStartTime);
pDateWithoutTime = sdf1.parse(sdf1.format(calendar.getTime()));
calendar1.setTimeInMillis(e.getTimestamp("startTime").toSqlTimestamp().getTime());
eDateWithoutTime = sdf1.parse(sdf1.format(calendar1.getTime()));
}
catch(Exception ex){
log.info("Exception while parsing date");
continue;
}
diffTime = Math.abs(pDateWithoutTime.getTime() - eDateWithoutTime.getTime());
diffDay = TimeUnit.DAYS.convert(diffTime, TimeUnit.MILLISECONDS);
//log.info("pDateWithoutTime: " + pDateWithoutTime + ", eDateWithoutTime: " + eDateWithoutTime + ", consumedVolume: "
// + sensorDataOut.usageVolume;
if(diffDay!=0) //If not same day
{
totalSummary.totVolume = totalSummary.totVolume + summary.totVolume;
totalSummary.totDuration = totalSummary.totDuration + summary.totDuration;
totalSummary.details.add(summary);
summary = new SensorSummaryDataOut();
}
}
summary.date = sensorDataOut.startTime;
summary.totVolume = summary.totVolume + sensorDataOut.usageVolume;
summary.totDuration = summary.totDuration + sensorDataOut.usageTime;
summary.details.add(sensorDataOut);
pe = e;
}
if(summary.details.size()>0)
{
totalSummary.totVolume = totalSummary.totVolume + summary.totVolume;
totalSummary.totDuration = totalSummary.totDuration + summary.totDuration;
totalSummary.details.add(summary);
summary = new SensorSummaryDataOut();
}
totalSummary.avgVolume = totalSummary.totVolume/totalSummary.details.size();
totalSummary.deviceguid = deviceGuid;
String json = "";
Gson gson = new Gson();
json = gson.toJson(totalSummary);
return json;
} //End of Function
Below method will return you your UTC time to current Timezone and this worked for me
public static Date getLocalDateObjFromUTC(String date, String time) throws ParseException {
String dateAndTimeInUTC = date + " " + time;
SimpleDateFormat localDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
localDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
Date dateInLocalTimeZone = localDateFormat.parse(dateAndTimeInUTC);
return dateInLocalTimeZone;
}

Joda Time: How to get dates of weekdays on some date interval?

I have two LocalDates that represent some time interval. Now i have to get LocalDates of all fridays, that this interval contains.
Easiest way to do it?
package org.life.java.so.questions;
import org.joda.time.DateTime;
import org.joda.time.DateTimeConstants;
/**
*
* #author Jigar
*/
public class JodaTimeDateTraverseQuestion {
public static void main(String[] args) {
DateTime startDt = new DateTime(2010,12,1,0,0,0,0);//1st Dec 2010
DateTime endDt = new DateTime(2010,12,31,0,0,0,0);//31st Dec 2010
DateTime tempDate = new DateTime(startDt.getMillis());
while(tempDate.compareTo(endDt) <=0 ){
if(tempDate.getDayOfWeek() != DateTimeConstants.SATURDAY && tempDate.getDayOfWeek() != DateTimeConstants.SUNDAY){
System.out.println(""+tempDate);
}
tempDate = tempDate.plusDays(1);
}
}
}
Solution: lazily step by one week.
import org.joda.time.LocalDate;
import java.util.Iterator;
public class DayOfWeekIterator implements Iterator<LocalDate>{
private final LocalDate end;
private LocalDate nextDate;
public DayOfWeekIterator(LocalDate start, LocalDate end, int dayOfWeekToIterate){
this.end = end;
nextDate = start.withDayOfWeek(dayOfWeekToIterate);
if (start.getDayOfWeek() > dayOfWeekToIterate) {
nextDate = nextDate.plusWeeks(1);
}
}
public boolean hasNext() {
return !nextDate.isAfter(end);
}
public LocalDate next() {
LocalDate result = nextDate;
nextDate = nextDate.plusWeeks(1);
return result;
}
public void remove() {
throw new UnsupportedOperationException();
}
}
Test
import org.joda.time.DateTimeConstants;
import org.joda.time.LocalDate;
public class DayOfWeekIteratorTest {
public static void main(String[] args) {
LocalDate startDate = new LocalDate(2010, 12, 1);//1st Dec 2010
LocalDate endDate = new LocalDate(2010, 12, 31);//31st Dec 2010
DayOfWeekIterator it = new DayOfWeekIterator(startDate, endDate, DateTimeConstants.FRIDAY);
while (it.hasNext()) {
System.out.println(it.next());
}
}
}
tl;dr
java.time.LocalDate.of( 2018 , Month.JANUARY , 23 ) // A date-only class in the modern *java.time* classes that supplant both Joda-Time and the troublesome old date-time classes.
.with(
TemporalAdjusters.next( DayOfWeek.FRIDAY ) // Nifty `TemporalAdjuster` implementation for moving to another date. Immutable Objects pattern means a new object is returned based on the original which remains unmodified.
)
.isBefore( // Compare `LocalDate` objects with `isBefore`, `isAfter`, and `isEqual`.
LocalDate.of( 2018 , Month.FEBRUARY , 27 );
)
java.time
FYI, the Joda-Time project is now in maintenance mode, with the team advising migration to the java.time classes.
Define your stop & start LocalDate objects.
LocalDate start = LocalDate.of( 2018 , Month.JANUARY , 23 );
LocalDate stop = LocalDate.of( 2018 , Month.FEBRUARY , 27 );
// TODO: Verify start.isBefore( stop ).
Collect the Friday dates we find. You might optimize a bit by sizing the collection.
// Pre-size the collection.
int initialCapacity = ( int ) ( ChronoUnit.WEEKS.between( start , stop ) + 2 ); // Adding two for good measure.
List < LocalDate > fridays = new ArrayList <>( initialCapacity );
Determine the first Friday, using the start date if it is itself a Friday. Use a pair of TemporalAdjuster implementations offered in the TemporalAdjusters class: next​(DayOfWeek) & nextOrSame​(DayOfWeek). Pass the desired day-of-week via the DayOfWeek enum, seven pre-defined objects, one for each day of the week Monday-Sunday.
LocalDate friday = start.with( TemporalAdjusters.nextOrSame( DayOfWeek.FRIDAY ) );
while ( friday.isBefore( stop ) )
{
fridays.add( friday ); // Remember this Friday date.
// Setup next loop.
friday = friday.with( TemporalAdjusters.next( DayOfWeek.FRIDAY ) );
}
System.out.println( "From " + start + " to " + stop + " = " + fridays );
From 2018-01-23 to 2018-02-27 = [2018-01-26, 2018-02-02, 2018-02-09, 2018-02-16, 2018-02-23]
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, 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, 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.

Categories

Resources