try {
String hql = "SELECT taskDate FROM TaskFutureDates t WHERE t.taskId= : taskId";
List<java.sql.Date> result = em.createQuery(hql).setParameter("taskId", taskId).getResultList();
java.sql.Date currentDate =new Date(new java.util.Date().getTime());
if (result.size() != 0) {
for(java.sql.Date date: result) {
if(date.compareTo(currentDate)>=0) {
System.err.println("CAST= "+(Date) date);
return (java.sql.Date) date;
}
}
}
} catch (Exception e) {
// TODO: handle exception
//System.err.println(e);
}
return null;
}
when I am comparing the two dates I am getting error scenarios
1.when I am comparing alternative days I am getting -1
eg
09/04/2020
10/04/2020
when the date is same I am getting -1
eg
10/04/2020
10/04/2020
in the 2nd scenario, I should get 0 why the result is -1?
from the compareTo doc:
a value less than 0 if this Date is before the Date argument
today() (= last midnight) or probably any date from your table is less than now() (which includes the current time)
tl;dr
Use modern java.time classes to retrieve and compare stored date values against today’s date.
myResultSet.getObject( … , LocalDate.class ).isAfter( LocalDate.now( "Africa/Tunis" ) )
Details
As the correct Answer by Rotteveel explained, you should not be using the terrible class java.sql.Date. That class was years ago supplanted by the modern java.time classes. Specifically, java.time.LocalDate.
As of JDBC 4.2, we can exchange java.time objects with the database. For columns of a type akin to the standard-SQL type DATE, use setObject, updateObject, and getObject to exchange LocalDate objects.
LocalDate ld = myResultSet.getObject( … , LocalDate.class ) ;
To get today’s date requires a time zone. For any given moment, the date varies around the globe by time zone. So while it may be “tomorrow” in Tokyo Japan, it may simultaneously be “yesterday” in Toledo Ohio US.
If you do not specify a time zone, the JVM’s current default time zone is applied implicitly.
ZoneId z = ZoneId.of( "Asia/Tokyo" ) ;
LocalDate today = LocalDate.now( z ) ;
Compare using isEqual, isBefore, and isAfter methods.
Boolean isFuture = ld.isAfter( today ) ;
Although java.sql.Date is supposed to be a date, it actually is still a thin wrapper around epoch milliseconds. It doesn't truncate them. So two java.sql.Date values that are the same date, can still have two different epoch milliseconds values (ie check the getTime() result), and as a result they won't compare identical.
The implementation of the java.sql.Date constructor (Date(long)) is:
public Date(long date) {
// If the millisecond date value contains time info, mask it out.
super(date);
}
Contrary to the comment, nothing is masked out. This is probably because java.sql.Date is sensitive to the default JVM time zone, and trying to mask it out would only complicate things.
In any case, since Java 8 / JDBC 4.2, it would be better to use java.time.LocalDate instead of java.sql.Date.
If you can't fully switch to using LocalDate, I would recommend at least using:
LocalDate currentDate = LocalDate.now();
//...
if (date.toLocalDate().compareTo(currentDate) >= 0) {
// ...
}
Or - as shown in the answer by Basil Bourque - use the specialized comparison methods like isAfter, isBefore and isEqual.
Related
I'm trying to check if a selected dates range by the user is within a range of dates exist in database.
e.g.
User select :
Start date : 24/09/2022
End date : 30/09/2022
Date range in database is :
Start date : 28/09/2022
End date : 30/09/2022
Imagine you have a reservation car between 28/09 → 30/09, if a user wants to reserve this car between 24/09 --> 30/09, then the app should notify them that the car is reserved in that date because it's already reserved between 28--> 30.
My situation is similar to this: Check if a date range is within a date range. Only that question is about C#, and I am coding Java.
My code so far :
boolean isFound = DateHelper.isWithinRange2Dates(
/*ENTERED BY USER*/
string2Date("24/09/2022"),
string2Date("30/09/2022"),
/*IN DATABASE*/
string2Date("28/09/2022"),
string2Date("30/09/2022"));
ToastUtils.showLong(isFound ? "FOUND" : "NOT FOUND");
Methods used :
public static boolean isWithinRange(Date selectedDate, Date startDate, Date endDate) {
return selectedDate.after(startDate) && (selectedDate.before(endDate) || DateUtils.isSameDay(selectedDate, endDate));
}
public static boolean isWithinRange2Dates(Date selectedStartDate, Date selectedEndDate, Date startDate, Date endDate) {
return isWithinRange(selectedStartDate, startDate, endDate) && isWithinRange(selectedEndDate, startDate, endDate);
}
#SuppressLint("SimpleDateFormat")
public static Date string2Date(String dateStr) {
try {
return new SimpleDateFormat("dd/MM/yyyy").parse(dateStr);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
Issue:
28/09 --> 30/09 is within the 24/09 --> 30/09 so the method should true
Question:
How I can check if a selected start and end date are within a date range or not?
tl;dr
org.threeten.extra.LocalDateRange.of
(
LocalDate.of( … ) ,
LocalDate.of( … )
)
.encloses
(
LocalDateRange.of
(
startJavaSqlDate.toLocalDate() ,
stopJavaSqlDate.toLocalDate()
)
)
Avoid legacy date-time classes
You are using terrible date-time classes that were years ago supplanted by the modern java.time classes defined in JSR 310.
One of the many design flaws in the Date class is that there are actually two Date classes:
java.util.Date
java.sql.Date
The first represents a moment as seen in UTC. The second pretends to represent a date-only, without a time-of-day and without an offset or time zone. But actually, in a case of extremely poor judgement, the second class extends from the first… so it does indeed internally represent a moment in UTC. Messy? Yes, a terrible mess.
LocalDate
You neglect to mention in your Question which class you are using. So I'll go with the second one, java.sql.Date.
When handed a java.sql.Date object, immediately convert to the modern replacement: LocalDate. Do so by calling the new conversion method added to the old class.
LocalDate ld = myJavaSqlDate.toLocalDate() ;
LocalDateRange
To compare date ranges, you could write the code yourself. But why bother? Add the ThreeTen-Extra library to your project. Doing so gives you access to the LocalDateRange class. That class provides several handy methods such as contains, abuts, encloses, overlaps, etc.
LocalDateRange target =
LocalDateRange.of(
LocalDate.of( … ) ,
LocalDate.of( … )
)
;
… and:
LocalDateRange selected =
LocalDateRange.of(
startJavaSqlDate.toLocalDate() ,
stopJavaSqlDate.toLocalDate()
)
;
Compare.
boolean enclosed = target.encloses( selected ) ;
Your isWithin range functions operator
Precedence is wrong.Also checking isSameDate for both end and start dates are missing. In your code it return false if user startDate is simmilar to your dateRange start date or if user end date simmilar to datarange end date. Correct implementation as follows of isWithinRange function.
return (selectedDate.after(startDate) || DateUtils.isSameDay(selectedDate, startDate)) && (selectedDate.before(endDate) || DateUtils.isSameDay(selectedDate, endDate));
Use || operator not && for isWithinRange2Dates function as follows.
return isWithinRange(selectedStartDate, startDate, endDate) || isWithinRange(selectedEndDate, startDate, endDate);
This question already has answers here:
How to check if a date is greater than another in Java? [duplicate]
(4 answers)
Closed 2 years ago.
My date time formatter is , "yyyy-MM-DD"
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-DD")
I want to check the date is later than today's date or not. I checked it using this validation.
if(dateFormatter.format(given_Date).compareTo(dateFormatter.format(new Date())) > 0){ ...}
But every time this returns false when the given date is later or not. Can anyone help with this me, please?
tl;dr
You asked:
check the date is later than today's date
LocalDate // Represent a date-only value, without time-of-day and without time zone or offset-from-UTC.
.parse( "2020-01-23" ) // No need to specify formatting pattern when parsing a string in standard ISO 8601 format. Returns a `LocalDate` object.
.isAfter // Compare one `LocalDate` object to another.
(
LocalDate.now // Capture the current date as seen in a particular time zone.
(
ZoneId.of( "Africa/Tunis" ) // or: ZoneId.systemDefault()
) // Returns a `LocalDate` object.
) // Returns `boolean`.
Details
Modern solution uses java.time classes, specifically java.time.LocalDate. Compare with isAfter method. You are using terrible date-time classes that were years ago supplanted by java.time.
No need to specify a formatting pattern. Your input strings comply with the ISO 8601 standard used by default in java.time.
By the way, formatting codes are case-sensitive, and day-of-month is dd rather than the DD you used. So the formatting pattern used here by default is akin to uuuu-MM-dd.
boolean isFuture = LocalDate.parse( "2020-01-23" ).isAfter( LocalDate.now() ) ;
Better to explicitly specify desired/expected time by which to determine today’s date. If omitted, the JVM’s current default time zone is implicitly applied.
boolean isFuture = LocalDate.parse( "2020-01-23" ).isAfter( LocalDate.now( ZoneId.of( "America/Edmonton" ) ) ) ;
If you can work with the variable givenDate as a String there is another way. Check out my code:
import java.util.Calendar;
public class compareDates {
public static void main(String[] args){
Calendar c = Calendar.getInstance();
String givenDate = "2021-01-10";
boolean later = false;
int yr_now = c.get(Calendar.YEAR);
int m_now = c.get(Calendar.MONTH) + 1;
int day_now = c.get(Calendar.DAY_OF_MONTH);
int given_yr = Integer.parseInt(givenDate.substring(0,4));
int given_m = Integer.parseInt(givenDate.substring(5,7));
int given_day = Integer.parseInt(givenDate.substring(8,10));
//is "given date" later than today's date?
if(yr_now > given_yr) {
System.out.print(later);
}
else if (yr_now == given_yr && m_now > given_m){
System.out.print(later);
}
else if (m_now == given_m && day_now >= given_day){
System.out.print(later);
}
else {later = true; System.out.print(later);}
}}
At the moment I got a class 'Flight' with Date datatypes; departure and arrival datetime.
The adding of flights happens by user input. The day should be the current date automatically and the time is the user's choice. Which means a person only has to input HH:mm.
At the moment it is a bit confusing with all the choices; Timestamp, Date, Localtime etc.
How can I make a simple user input with a scanner for this problem?
It should take todays date, add the user input containing the time and add it together to fit into my Date datatype.
Anyone has a clue how to do this or could provide some tips / best practices?
Since you said that you are developing a desktop app and you need the current date (on the pc) you can use a combination of LocalDate and LocalTime to achieve your goal.
Here is the code:
public static void main(String[] args) {
LocalDate currentDate = LocalDate.now();
LocalTime userInputTime = null;
Scanner sc = new Scanner(System.in);
String dateTimeLine = sc.nextLine();
sc.close();
DateTimeFormatter dt = DateTimeFormatter.ofPattern("HH:mm");
userInputTime = LocalTime.parse(dateTimeLine,dtf);
System.err.println(LocalDateTime.of(currentDate, userInputTime));
}
First, you use LocalDate.now() in order to generate the current date (only the date, without hours, minutes and seconds).
Next we use Scanner in order to read a string entered by the user.
In order to convert the string to a LocalTime (this class contains info only about time in a day, so it has values for hours,minutes,seconds and nanoseconds), we have to define a DateTimeFormatter. The DateTimeFormatter defines how the string will be converted into LocalTime instance.
In the code I just wrote, I said that the string input will be of type "hours:minutes". For example, possible values are:
"10:25" - 10 hours and 25 minutes,
"23:00" - 23 hours and 0 minutes,
"02:13" - 2 hours and 13 minutes.
After we create the LocalTime object, all we have to do is to join the date and time objects in order to create a LocalDateTime object which is done in this line:
LocalDateTime.of(currentDate, userInputTime)
So lets say that the date on your current PC is 2018-05-06. If you run the program and enter 10:50 in the console, the output should be a LocalDateTime object that has 2018-05-06 as a date and 10 hours and 50 minutes as time of the day.
It is important to note that this line:
userInputTime = LocalTime.parse(dateTimeLine,dtf);
will throw an java.time.format.DateTimeParseException if the entered string by the user does not satisfy the required format.
tl;dr
LocalDateTime.of( // A `LocalDateTime` represents a set of *potential* moments along a range of about 26-27 hours. Not an actual moment, not a point on the timeline.
LocalDate.systemDefault() , // Get the JVM’s current default time zone. Can change at any moment *during* runtime. When crucial, always confirm with the user.
LocalTime.parse( "14:57" ) // Parse a string in standard ISO 8601 format as a time-of-day without regard for time zone or offset-from-UTC.
) // Returns a `LocalDateTime` object.
.atZone( // Determine an actual moment, a point on the timeline.
ZoneId( "Africa/Tunis" ) // Specify a time zone as `Continent/Region`, never as 3-4 letter pseudo-zones such as `PST`, `CST`, or `IST`.
) // Returns a `ZonedDateTime` object.
.toInstant() // Extracts a `Instant` object from the `ZonedDateTime` object, always in UTC by default.
Details
At the moment it is a bit confusing
Date-time handling is very confusing work.
Tips:
Forget about your own time zone. Think in terms of UTC rather than your own parochial time zone.
Learn the difference between real moments (points on the timeline), and date-time approximations that are not on the timeline, often-called “local” values.
Be careful when reading Stack Overflow or other places on the internet about date-time. You will encounter poor advice and many wrong solutions.
with all the choices; Timestamp, Date, Localtime etc.
Never use the troublesome old legacy date-time classes bundled with the earliest versions of Java. Never use java.sql.Timestamp, java.util.Date, java.util.Calendar, and so on.
➡ Use only classes in the java.time package.
The java.time classes are an industry-leading date-time framework. Extremely well-designed and thought-through, with lessons learned from the Joda-Time project it succeeds.
Anyone has a clue how to do this or could provide some tips / best practices?
You might be sorry you asked. Read on.
At the moment I got a class 'Flight' with Date datatypes; departure and arrival datetime.
So define a Flight class.
In real-life, flights happen far enough out in the future that we risk politicians changing the definition of the time zone. Most commonly these changes are adopting/dropping/altering Daylight Saving Time (DST). But arbitrary changes are made periodically for all kinds of reasons. We could debate the wisdom/sanity of such changes, but the fact is they happen. They happen quite frequently as politicians seemly oddly prone to making these changes around the world in many countries. And nearly all of them do so with little forewarning, sometimes just weeks. Or even with no warning at all, as North Korea did this week.
I have no understanding of how airlines actually work, but from poking around airline schedules and various readings, it seems they try to maintain their schedules using the zoned time of the departing locality. So if a flight is scheduled to depart LAX at 6 AM, they keep that flight schedule on the day before, the day of, and the day after a DST change-over. If this is indeed the general intent, that means sitting-around killing time on one DST cut-over while trying to save an hour on the opposite DST cut-over. Apparently, Amtrak adopts this practice for its trains. Let’s proceed with this approach.
Using this “imaginary” schedule approach means we cannot determine for certain the exact moment when 6 AM will occur in the future. So we need to record our desire for that date and that time-of-day without applying a time zone. But we must record the desired time zone so we know in what context we can later determine the exact moment, when close enough in time that we needn’t worry about zone changes.
So we use LocalDate and LocalTime types, as they purposely lack any concept of time zone (a name in Continent/Region format) or offset-from-UTC (a number of hours-minutes-seconds).
The ZoneId class represents a time zone.
I am using the word Unzoned in the names to remind us that these values do not represent actual moments on the timeline. The word “local” tends to confuse beginners.
public class Flight {
private String flightNumber;
private LocalDate departureDateUnzoned;
private LocalTime departureTimeUnzoned;
private ZoneId departureZoneId ;
}
As for arrival, store the span-of-time expected for that flight rather than the arrival date-time. You can calculate the arrival, so no need to store it. The Duration class tracks a number of hours, minutes, seconds, and fractional second.
To calculate the arrival, let’s return a single value using the LocalDateTime class, which simply combines a LocalDate with a LocalTime. We could have used this type to make a single departureUnzoned member variable in our class definition. I went with separate LocalDate and LocalTime as building blocks so you would understand the pieces. So many programmers use their intuition rather than the documentation to assume that LocalDateTime means a specific moment in a locality when actually it means just the opposite. (You will find many incorrect Answers on Stack Overflow advising LocalDateTime when actually Instant or ZonedDateTime should be used.)
Let's add a method to calculate that arrival.
public class Flight {
private String flightNumber;
private LocalDate departureDateUnzoned;
private LocalTime departureTimeUnzoned;
private ZoneId departureZoneId;
private Duration duration;
public LocalDateTime arrivalDateTimeUnzoned () {
LocalDateTime departureUnzoned = LocalDateTime.of( this.departureDateUnzoned , this.departureTimeUnzoned );
LocalDateTime ldt = departureUnzoned.plus( this.duration );
return ldt;
}
}
But this returned LocalDateTime fails to account for time zone. Usually, airlines and train report to customers the expected arrival time adjusted into the time zone of that region. So we need an arrival time zone. And we can use that zone when calculating the arrival, thereby producing a ZonedDateTime. A ZonedDateTime is a specific moment, it is a point on the timeline, unlike LocalDateTime. But remember, if we are scheduling flights out into the future, the calculated ZonedDateTime will change if our code is run after politicians redefine the time zone.
public class Flight {
private String flightNumber;
private LocalDate departureDateUnzoned;
private LocalTime departureTimeUnzoned;
private ZoneId departureZoneId;
private Duration duration;
private ZoneId arrivalZoneId;
public ZonedDateTime arrivalDateTimeZoned () {
ZonedDateTime departureZoned = ZonedDateTime.of( this.departureDateUnzoned , this.departureTimeUnzoned , this.departureZoneId );
ZonedDateTime zdt = departureZoned.plus( this.duration );
return zdt;
}
}
Back to the part of your Question about determining the date automatically. That requires a time zone. For any given moment, the date varies around the globe. Think about that. A few minutes after midnight in Paris France is a new day, while still “yesterday” in Montréal Québec.
We can ask for the JVM’s current default time zone.
ZoneId userZoneId = ZoneId.systemDefault() ;
But when crucial, you must confirm with the user.
ZoneId userZoneId = ZoneId.of( "America/Montreal" ) ;
So now we can add the constructor you asked for, passing the time-of-day (a LocalTime, and guessing the time zone by using the JVM’s current default.
But we still need all the other pieces. So defaulting the date does not save us much.
public class Flight {
private String flightNumber;
private LocalDate departureDateUnzoned;
private LocalTime departureTimeUnzoned;
private ZoneId departureZoneId;
private Duration duration;
private ZoneId arrivalZoneId;
// Constructor
public Flight ( String flightNumber , LocalTime departureTimeUnzoned , ZoneId departureZoneId , Duration duration , ZoneId arrivalZoneId ) {
this.flightNumber = flightNumber;
this.departureTimeUnzoned = departureTimeUnzoned;
this.departureZoneId = departureZoneId;
this.duration = duration;
this.arrivalZoneId = arrivalZoneId;
// Determine today’s date using JVM’s current default time zone. Not advisable in many business scenarios, but specified by our Question at hand.
ZoneId z = ZoneId.systemDefault();
LocalDate today = LocalDate.now( z );
this.departureDateUnzoned = today;
}
public ZonedDateTime arrivalDateTimeZoned () {
ZonedDateTime departureZoned = ZonedDateTime.of( this.departureDateUnzoned , this.departureTimeUnzoned , this.departureZoneId );
ZonedDateTime zdt = departureZoned.plus( this.duration );
return zdt;
}
}
Let’s add a toString method for reporting.
We represent the date-time values as strings in standard ISO 8601 formats. The java.time classes use these standard formats when parsing/generating strings. The Z on the end is pronounced Zulu and means UTC.
While airlines and trains report date-times to their customers in the regions’ time zones, we can assume they use only UTC internally. The Instant class represents values in UTC specifically. So our toString extracts Instant objects from the ZonedDateTime objects.
And we add a main method for demonstration. Here is the complete class, with import etc.
package com.basilbourque.example;
import java.time.*;
public class Flight {
private String flightNumber;
private LocalDate departureDateUnzoned;
private LocalTime departureTimeUnzoned;
private ZoneId departureZoneId;
private Duration duration;
private ZoneId arrivalZoneId;
// Constructor
public Flight ( String flightNumber , LocalTime departureTimeUnzoned , ZoneId departureZoneId , Duration duration , ZoneId arrivalZoneId ) {
this.flightNumber = flightNumber;
this.departureTimeUnzoned = departureTimeUnzoned;
this.departureZoneId = departureZoneId;
this.duration = duration;
this.arrivalZoneId = arrivalZoneId;
// Determine today’s date using JVM’s current default time zone. Not advisable in many business scenarios, but specified by our Question at hand.
ZoneId z = ZoneId.systemDefault();
LocalDate today = LocalDate.now( z );
this.departureDateUnzoned = today;
}
public ZonedDateTime arrivalDateTimeZoned () {
ZonedDateTime departureZoned = ZonedDateTime.of( this.departureDateUnzoned , this.departureTimeUnzoned , this.departureZoneId );
ZonedDateTime zdt = departureZoned.plus( this.duration );
return zdt;
}
#Override
public String toString () {
ZonedDateTime departureZoned = ZonedDateTime.of( this.departureDateUnzoned , this.departureTimeUnzoned , this.departureZoneId );
String flightInUtc = departureZoned.toInstant().toString() + "/" + this.arrivalDateTimeZoned().toInstant().toString();
return "Flight{ " +
"flightNumber='" + this.flightNumber + '\'' +
" | departureDateUnzoned=" + this.departureDateUnzoned +
" | departureTimeUnzoned=" + this.departureTimeUnzoned +
" | departureZoneId=" + this.departureZoneId +
" | departureZoned=" + departureZoned +
" | duration=" + this.duration +
" | arrivalZoneId=" + this.arrivalZoneId +
" | calculatedArrival=" + this.arrivalDateTimeZoned() +
" | flightInUtc=" + flightInUtc +
" }";
}
public static void main ( String[] args ) {
LocalTime lt = LocalTime.of( 6 , 0 ); // 6 AM.
Flight f = new Flight( "A472" , lt , ZoneId.of( "America/Los_Angeles" ) , Duration.parse( "PT6H37M" ) , ZoneId.of( "America/Montreal" ) );
String output = f.toString();
System.out.println( output );
}
}
When run.
Flight{ flightNumber='A472' | departureDateUnzoned=2018-05-06 | departureTimeUnzoned=06:00 | departureZoneId=America/Los_Angeles | departureZoned=2018-05-06T06:00-07:00[America/Los_Angeles] | duration=PT6H37M | arrivalZoneId=America/Montreal | calculatedArrival=2018-05-06T12:37-07:00[America/Los_Angeles] | flightInUtc=2018-05-06T13:00:00Z/2018-05-06T19:37:00Z }
To use this from the console, ask the user for the time-of-day in 24-hour clock. Parse the input string.
String input = "14:56" ; // 24-hour clock.
LocalTime lt = LocalTime.parse( input ) ;
This is far from complete for real-world work. But hopefully it makes for an educational example.
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.
I have two instances of the Instant class from java.time such as this:
Instant instant1 = Instant.now();
Instant instant2 = Instant.now().plus(5, ChronoUnit.HOURS);
Now I would like to check if the two instances of Instant are actually on the same date (day, month and year match). Easy I thought, let's just use the shiny new LocalDate and the universal from static method:
LocalDate localdate1 = LocalDate.from(instant1);
LocalDate localdate2 = LocalDate.from(instant2);
if (localdate1.equals(localdate2)) {
// All the awesome
}
Except that universal from method is not so universal and Java complains at runtime with an exception:
java.time.DateTimeException: Unable to obtain LocalDate from TemporalAccessor: 2014-11-04T18:18:12Z of type java.time.Instant
Which leaves me back at square 1.
What is the recommended/fastest way check if two instances of Instant actually have the same date (have the same day, month, and year)?
The Instant class does not work with human units of time, such as
years, months, or days. If you want to perform calculations in those
units, you can convert an Instant to another class, such as
LocalDateTime or ZonedDateTime, by binding the Instant with a time
zone. You can then access the value in the desired units.
http://docs.oracle.com/javase/tutorial/datetime/iso/instant.html
Therefore I suggest the following code:
LocalDate ld1 = LocalDateTime.ofInstant(instant1, ZoneId.systemDefault()).toLocalDate();
LocalDate ld2 = LocalDateTime.ofInstant(instant2, ZoneId.systemDefault()).toLocalDate();
if (ld1.isEqual(ld2)) {
System.out.println("blubb");
}
Alternatively you could use
instant.atOffset(ZoneOffset.UTC).toLocalDate();
I am storing current date in SQLite DB as
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
When I try to compare Calendar objects, its always shows objects as not equal.
Here is my code.
Creating Calendar from Database string
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Calendar calendarDB = Calendar.getInstance();
String date = "extracted only date (2014-03-03 for ex) from DB value ignoring time";
calendarDB.setTime(sdf.parse(date));
Current Calendar instance
Calendar calendarCurrent = Calendar.getInstance();
Comparison... I see not equal for all the instances.
if(calendarDB.equals(calendarCurrent))
Log.i(TAG, "equal!!!");
else
Log.i(TAG, "Not equal!!!");
I can see both Calendar instance values like day, month, year equal in Log.
What's wrong with it?
Calendar.getInstance() is not singleton. It every time creates a new instance of different implementations of java.util.Calendar based on Locale
Secondly, if you check equals method of Calendar, it checks lot more, than just the date
public boolean equals(Object obj) {
if (this == obj)
return true;
try {
Calendar that = (Calendar)obj;
return compareTo(getMillisOf(that)) == 0 &&
lenient == that.lenient &&
firstDayOfWeek == that.firstDayOfWeek &&
minimalDaysInFirstWeek == that.minimalDaysInFirstWeek &&
zone.equals(that.zone);
} catch (Exception e) {
// Note: GregorianCalendar.computeTime throws
// IllegalArgumentException if the ERA value is invalid
// even it's in lenient mode.
}
return false;
}
If you want to compare 2 dates then, you can do
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date one = new Date(); // one = calOne.getTime();
Date two = new Date(); //two = calTwo.getTime();
sdf.format(one).equals(sdf.format(two));
That's happens because a Calendar equals method compare to next fields :
#Override
public boolean equals(Object object) {
if (this == object) {
return true;
}
if (!(object instanceof Calendar)) {
return false;
}
Calendar cal = (Calendar) object;
return getTimeInMillis() == cal.getTimeInMillis()
&& isLenient() == cal.isLenient()
&& getFirstDayOfWeek() == cal.getFirstDayOfWeek()
&& getMinimalDaysInFirstWeek() == cal.getMinimalDaysInFirstWeek()
&& getTimeZone().equals(cal.getTimeZone());
}
So you need to check :
millis
isLenient
first day of week
minimal days in first week
and time zone
As you can see equals method need a same TimeZone in comaprable object.
tl;dr
LocalDate.now( ZoneId( "Pacific/Auckland" ) ) // Get today’s date in a particular time zone.
.isEqual( // Test for equality against a `LocalDate` object to be retrieved from database.
myResultSet.getObject( … , Instant.class ) // Retrieve a moment in UTC from the database, an `Instant` object.
.atZone( ZoneId( "Pacific/Auckland" ) ) // Produce a `ZonedDateTime` to represent the same moment in time but with the wall-clock time of a particular region’s time zone.
.toLocalDate() // Extract a date-only value, without time-of-day and without time zone.
)
java.time
The modern approach uses the java.time classes.
With JDBC 4.2 and later, you may directly exchange java.time objects with your database. No need for the troublesome Calendar class, no need for mere strings.
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.getObject( … , Instant.class ) ;
A time zone is crucial in determining a date. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris France is a new day while still “yesterday” in Montréal Québec.
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" ) ;
Apply the ZoneId to your Instant to get a ZonedDateTime.
ZonedDateTime zdt = instant.atZone( z ) ;
If you care about only the date portion, and not the time-of-day, extract a LocalDate.
LocalDate ld = zdt.toLocalDate() ;
Compare to the current date.
LocalDate today = LocalDate.now( z ) ;
Boolean isSameDateAsToday = ld.isEqual( today ) ;
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
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….