This question already has answers here:
Compare two dates in Java
(13 answers)
Closed 4 years ago.
From java class Date docs:
before(Date when) Tests if this date is before the specified date.
When I use this method to test whether selected date is equal to today, I get wrong output message.
public class JavaApplication28 {
/**
* #param args the command line arguments
*/
public static void main(String[] args) throws NoSuchAlgorithmException, ParseException {
Date date1;
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
String statusDT ="2018-04-08";
date1 = formatter.parse(statusDT);
if (date1.equals(new Date())) {
System.out.println("today");
} else if (date1.before(new Date())) {
System.out.println("wrong");
}
}
}
This is date1, which is today date
Sun Apr 08 00:00:00 MYT 2018
The equal method look not functiong as well
equals(Object obj) Compares two dates for equality.
The given date date1 represent today but with midnight time : Sun Apr 08 00:00:00 MYT 2018
the date used for comparison new Date() represents also today but the actual time (about 15h10) : Sun Apr 08 15:10:00 MYT 2018
So date1 if before actual Date() and it goes in the good if section
As the Java8 introduce a new Date API, it's easier to use in most case :
LocalDateTime which holds Date (day/month/year) and Time (sec/min/hour)
LocalDate which holds the Date part and can be given from a LocalDateTime.toLocalDate()
LocalTime which holds the Time part and can be given from a LocalDateTime.toLocalTime()
So if you don't matter of the time, and just want to check the day/month/year you can use only the LocalDate part from the LocalDateTime :
if (date1.toLocalDate().equals(LocalDate.now())) {
System.out.println("today"); //< ---
} else if (date1.toLocalDate().isBefore(LocalDate.now())) {
System.out.println("before now");
} else if (date1.toLocalDate().isAfter(LocalDate.now())) {
System.out.println("after now");
}
Try this :
long l1 = date1.getTime();
long l2 = (new Date()).getTime();
Output
1523142000000
1523192849177
The doc said :
Compares two dates for equality. The result is true if and only if the
argument is not null and is a Date object that represents the same
point in time, to the millisecond, as this object. Thus, two Date
objects are equal if and only if the getTime method returns the same
long value for both.
Your get wrong because you thing that equal compare only the date part, but NO, it also compare the time part
Another Solution
Because you are using Java 8 why not using java.time instead like this :
String statusDT = "2018-04-08";
LocalDate date = LocalDate.parse(statusDT, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
if (date.isEqual(LocalDate.now())) {
System.out.println("today");
} else if (date.isBefore(LocalDate.now())) {
System.out.println("before");
} else {
System.out.println("after");
}
Class java.util.Date contains both a date and a time-of-day - as can be seen in the output of your program. The Date you obtain by parsing the String has no time-of-day, only a date. In other words, its time-of-day is 00:00 (i.e. midnight). Hence the two Dates are not equeal.
And by the way, the link you provided for the javadoc of the Date class is the Java 8 documentation. If this means you are using Java 8, then there is a new Date-Time API. There is a tutorial at
https://docs.oracle.com/javase/tutorial/datetime/index.html
Related
This question already has answers here:
Convert day of the year to a date in java
(2 answers)
Closed 3 years ago.
In the below Java class, I need to write the logic of converting an int to Date as explained below. And this program is not related to adding number of days to current date.
If endDay value is 1, then date should print as Jan 1st 2020.
If endDay value is 28, then date should print as Jan 28th 2020.
If endDay value is 35, then date should print as Feb 4th 2020.
If endDay value is 60, then date should print as Feb 29th 2020.
If endDay value is 70, then date should print as March 10th 2020.
Note: value of endDay (1) always starts from January 1st of every year.
import java.util.Date;
public class TestDate
{
public void startEndDate(int endDay)
{
Date date=new Date();
//logic to print the date here
System.out.println("For the given end day of "+endDay+" the date returned is : "+date);
}
public static void main(String[] args)
{
startEndDate(35);
startEndDate(49);
startEndDate(70);
}
}
Can any one suggest me the ideas on how to write the logic for above one ?
java.time and Year.atDay()
public static void startEndDate(int endDay)
{
LocalDate date = Year.of(2020).atDay(endDay);
System.out.println("For the given end day of " + endDay
+ " the date returned is : " + date);
}
Let’s try it out:
startEndDate(35);
startEndDate(49);
startEndDate(70);
Output is:
For the given end day of 35 the date returned is : 2020-02-04
For the given end day of 49 the date returned is : 2020-02-18
For the given end day of 70 the date returned is : 2020-03-10
The documentation of Year.atDay() explains:
Combines this year with a day-of-year to create a LocalDate.
Please fill in your desired year where I put 2020.
I recommend you don’t use Date. That class is poorly designed and long outdated. Instead I am using Year and LocalDate, both from java.time, the modern Java date and time API.
A comment suggested regarding your question as a question of adding a number of days to December 31 of the previous year. IMO regarding it as finding a date from the number of the day-of-year gives a somewhat more elegant solution.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Documentation of Year.atDay(int dayOfYear)
Documentation of LocalDate.ofYearDay(), a good alternative
I am using the below code to retrieve the last day in the previous month - Ex: May. But it is returning 30 days instead of 31.
The code given below
package net.vcmg.date;
import java.util.Calendar;
import java.util.Date;
import org.apache.commons.lang.time.DateUtils;
public class LastDayPreviousMonth {
public static void main(String[] args) {
Date lastDateOfPreviousMonth = addMonths(lastDayOfTheMonth(today()), -1);
System.out.println("lastDateOfPreviousMonth: "+lastDateOfPreviousMonth);
}
//the below method is from Utils.java
public static Date lastDayOfTheMonth(Date d) {
Calendar cal = Calendar.getInstance();
cal.setTime(d);
int actualMax = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
cal.set(Calendar.DAY_OF_MONTH, actualMax);
return cal.getTime();
}
public static Date addMonths(Date date, int numMonths)
{
return DateUtils.addMonths(date, numMonths);
}
public static Date today()
{
return truncDate(now());
}
public static Date now()
{
// will cut-off milliseconds
return new Date( (System.currentTimeMillis()/1000) * 1000);
}
public static Date truncDate (Date date) {
return DateUtils.truncate(date, Calendar.DATE);
}
}
Here, when i call the lastDateOfPreviousMonth in the main method, it is returning 30 days alone. Not the 31 , May contains 31 days actually. Please help.
Java 8
If you are not constraint to use the old Date it will be better to use the new java.time.LocalDate
LocalDate previousMonth = LocalDate.now().minusMonths(1);
LocalDate start = previousMonth.withDayOfMonth(1);
LocalDate end = previousMonth.withDayOfMonth(previousMonth.lengthOfMonth());
System.out.println(start);
System.out.println(end);
Output
2019-05-01
2019-05-31
Edit
For your implementation, change the order of methods
addMonths - get the current date and provide the previous month addMonths(new Date(), -1)
lastDayOfTheMonth - get the last day of the previous month lastDayOfTheMonth(addMonths(new Date(), -1))
Date lastDateOfPreviousMonth = lastDayOfTheMonth(addMonths(new Date(), -1));
Output
lastDateOfPreviousMonth: Fri May 31 10:46:13 EEST 2019
Try this:
public static void main(String[] args) {
Date lastDateOfPreviousMonth = lastDayOfTheMonth(addMonths(today(), -1));
System.out.println("lastDateOfPreviousMonth: " + lastDateOfPreviousMonth);
}
When you call lastDayOfTheMonth for today() day will be 30. And after minus one month result expected will be 30, not 31.
It’s a logical error in the way you have thought out your program/algorithm. You are first finding the last day of the month, in this case June 30. You are then subtracting 1 month. That gives May 30 regardless of the fact that there are 31 days in May (it’s not explicit from the documentation of DateUtils.addMonths that it works this way, but it uses the poorly designed and outdated Calendar class internally, so this is what we should expect).
Instead do things in the opposite order. First find the previous month:
YearMonth lastMonth = YearMonth.now(ZoneId.of("Asia/Kolkata")).minusMonths(1);
2019-05
Since the new month doesn’t begin at the same point in time in all time zones, I recommend that you state your desired time zone as shown.
Only then find the last day of the month:
LocalDate lastDayOfLastMonth = lastMonth.atEndOfMonth();
2019-05-31
Avoid Date and Calendar
I recommend you don’t use Date and Calendar. Those classes are poorly designed and long outdated. Instead use LocalDate and other classes from java.time, the modern Java date and time API. This will also save you from the external dependency on Apache DateUtils since its functionality is generally built into the modern classes.
Links
Documentation of org.apache.commons.lang3.time.DateUtils.addMonths
Oracle tutorial: Date Time explaining how to use java.time.
I am trying to compare dates in two different formats:
Tue Jul 01 00:12:14 EST 2014
which is created using the function:
private Date getDate (int day, int month, int year){
Calendar calendar = Calendar.getInstance();
calendar.setLenient(false);
calendar.set(year, month-1, day);
Date date = calendar.getTime();
return date;
}
and
2014-07-01
After comparing these two dates, I would like the output to show that they are equal. However I BELIEVE, because of the timestamp in the 1st Date, they are not being determined as equal.
Is my assumption correct?
If so, is there a way that I could convert the first date into the second? The second Date is being retrieved from an SQL database where the variable is DATE.
Thank you for your help.
It sounds like you are comparing a java.util.Date (an instant in time) with a java.sql.Date (an instant in time whose time of day is midnight).
Arithmetic rounding must deal with the local timezones, making it more complex than you might first think.
The simplest way to compare the two would be to use a data formatter and compare the output:
SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd");
if (f.format(date1).equals(f.format(date2))) {
// the two dates are on the same "day"
}
java.sql.Date Has Zero Time
The documentation explains that a java.sql.Date has its time portion set to zero (UTC), meaning midnight.
So when comparing to a java.util.Date with a non-zero time-of-day, the two will not be equal.
LocalDate
So much easier using Joda-Time of the new java.time package in Java 8. Both offer a LocalDate class that ignores time-of-day.
LocalDate x = new LocalDate( 2014, 5, 6 );
LocalDate y = new LocalDate( 2014, 5, 6 );
boolean same = x.equals( y );
To convert your java.sql.Date to a Joda-Time LocalDate, pass it to the constructor of New LocalDate. You may need to also pass DateTimeZone.UTC to be sure it is not interpreted by your JVM's default time zone.
Is my assumption correct?
Yes, your assumption is correct. Two Date instances are correct if both their getTime() results are the same
from Date.java
public boolean equals(Object obj) {
return obj instanceof Date && getTime() == ((Date) obj).getTime();
}
Converting just assumes you need to set the hours,minutes and seconds to 0:
calendar.set(Calendar.HOUR_OF_DAY,0);
calendar.set(Calendar.MINUTE,0);
calendar.set(Calendar.SECOND,0);
Assuming that both dates are in the same timezone and also assuming that the date equality criteria here is the day of the year, I believe you can just compare the date as strings.
To do that, you can use SimpleDateFormat to ensure both are in the same format.
I would suggest you convert both of them to one particular format and compare them using a Comparator.
If you need to check whether two dates are equal, the best way is to use compareTo method.
if(yesterday.compareTo(today) == 0) {
System.out.println("Given dates are same");
} else {
System.out.println("Given dates are different ");
}
Read more: https://www.java67.com/2016/09/how-to-compare-two-dates-in-java.html#ixzz6uH5r1xE2
Why doesn't the set remove duplicates from the sorted list ? I have sorted the dates in ascending order which the first printed line shows but the set isn't removing the duplicates. Why is that ?
The program prints:
[Mon Apr 20 12:27:47 CDT 2009, Mon Apr 20 12:27:47 CDT 2009, Sun Dec 20 12:27:47 CST 2009]
[Sun Dec 20 12:27:47 CST 2009, Mon Apr 20 12:27:47 CDT 2009, Mon Apr 20 12:27:47 CDT 2009]
Shouldn't creating a set remove the duplicate date from the collection ?
def void testLoadDoc()
{
Date date1 = getCurrentDate(3,20,2009)
Date date2 = getCurrentDate(11,20,2009)
Date date3 = getCurrentDate(3,20,2009)
List<Date> dates = new ArrayList<Date>();
dates.add(date2);
dates.add(date1);
dates.add(date3);
Collections.sort(dates, new CurrencyDateComparator());
Set uniqueDates = new HashSet(dates)
println dates
println uniqueDates
}
private Date getCurrentDate(int month, int day, int year)
{
Calendar cal = Calendar.getInstance();
cal.set(YEAR, year);
cal.set(MONTH, month);
cal.set(DAY_OF_MONTH, day);
return cal.getTime();
}
}
class CurrencyDateComparator implements Comparator
{
/* (non-Javadoc)
* #see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
*/
public int compare(Object arg0, Object arg1)
{
Date p = (Date) arg0;
Date q = (Date) arg1;
if (p.before(q))
{
return -1;
}
else if (p.after(q))
{
return 1;
}
else
{
return 0;
}
}
public boolean equals(Object o)
{
if (o instanceof CurrencyDateComparator)
{
CurrencyDateComparator c = (CurrencyDateComparator) o;
return this.equals(o);
}
else
{
return false;
}
}
All your dates have different millisecond values, that are not printed in your traces. Set the milliseconds to 0.
First
java.util.Date carries time information with it, you need to zero out the time information then set what you want to be set or exclude the time portion from the comparison inside your custom Comparator.
Second
Your custom Comparator is buggy and redundant. java.util.Date already implements Comparable so you don't need to compare dates again, just called .compare() on the first Date instance with the second one as an argument.
Third
Also remember that MONTHS are ZERO based in Caledar. January == 0 not 1.
Fourth
Never rely on the default toString() on java.util.Date, always use a SimpleDateFormatter instance that displays the entire time stamp down to the milliseconds including a TimeZone ( yyyy-MM-dd'T'HH:mm:ssZ ), preferably ISO-8601 and UTC TimeZone for deterministic behavior.
When you use Calendar.getInstance() it returns "now" to millisecond precision. Changing the Y-M-D fields does not clear any of that out, so your two dates are likely off by a millisecond or twenty, which is not included in the default toString() implementation that you're seeing output from.
If you want to set a calendar to a specific time, it is simplest to clear() it first before starting to set fields.
When you call Calendar.getInstance(), you get a Calendar initialized with the current time. This includes hours, minutes, seconds, and milliseconds. Call clearTime() on it to zero them out.
You can use this collection instead
Set<Date> dates = new TreeSet<Date>(CurrencyDateComparator.INSTANCE);
dates.add(date2);
dates.add(date1);
dates.add(date3);
enum CurrencyDateComparator implements Comparator<Date> {
INSTANCE;
static final long MILLI_PER_DAY = 86400000L;
public int compare(Date d1, Date d2) {
// older versions of Java can use Double.compare()
return Long.compare(d1.getTime() / MILLIS_PER_DAY, d2.getTime() / MILLIS_PER_DAY);
}
}
This question already has answers here:
Java Date cut off time information
(20 answers)
Closed 8 years ago.
I want to implement a thread-safe function to remove the time part from java.util.Date.
I tried this way
private static final DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
public static Date removeTimeFromDate(Date date) {
Date returnDate = date;
if (date == null) {
return returnDate;
}
//just have the date remove the time
String targetDateStr = df.format(date);
try {
returnDate = df.parse(targetDateStr);
} catch (ParseException e) {
}
return returnDate;
}
and use synchronized or threadLocal to make it thread-safe.
But it there any better way to implement it in Java. It seems this way is a bit verbose.
I am not satisfied with it.
A Date object holds a variable wich represents the time as the number of milliseconds since epoch. So, you can't "remove" the time part. What you can do is set the time of that day to zero, which means it will be 00:00:00 000 of that day. This is done by using a GregorianCalendar:
GregorianCalendar gc = new GregorianCalendar();
gc.setTime(date);
gc.set(Calendar.HOUR_OF_DAY, 0);
gc.set(Calendar.MINUTE, 0);
gc.set(Calendar.SECOND, 0);
gc.set(Calendar.MILLISECOND, 0);
Date returnDate = gc.getTime();
A Date holds an instant in time - that means it doesn't unambiguously specify a particular date. So you need to specify a time zone as well, in order to work out what date something falls on. You then need to work out how you want to represent the result - as a Date with a value of "midnight on that date in UTC" for example?
You should also note that midnight itself doesn't occur on all days in all time zones, due to DST transitions which can occur at midnight. (Brazil is a common example of this.)
Unless you're really wedded to Date and Calendar, I'd recommend that you start using Joda Time instead, as that allows you to have a value of type LocalDate which gets rid of most of these problems.