I am creating a calendar in my Android application. The first day of the calendar is Sunday or Monday. It depends on the locale. Strange behavior of the java.util.GregorianCalendar class in different android versions:
public class CurrentMonth extends AbstractCurrentMonth implements InterfaceCurrentMonth {
public CurrentMonth(GregorianCalendar calendar, int firstDayOfWeek) {
super(calendar, firstDayOfWeek);
}
#Override
public List<ContentAbstract> getListContent() {
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
GregorianCalendar currentCalendar = new GregorianCalendar(year, month, 1);
List<ContentAbstract> list = new ArrayList<>();
int weekDay = getDayOfWeek(currentCalendar);
currentCalendar.add(Calendar.DAY_OF_WEEK, - (weekDay - 1));
while (currentCalendar.get(Calendar.MONTH) != month) {
list.add(getContent(currentCalendar));
currentCalendar.add(Calendar.DAY_OF_MONTH, 1);
}
while (currentCalendar.get(Calendar.MONTH) == month) {
list.add(getContent(currentCalendar));
currentCalendar.add(Calendar.DAY_OF_MONTH, 1);
}
currentCalendar.add(Calendar.DAY_OF_MONTH, - 1);
while (getDayOfWeek(currentCalendar) != 7) {
currentCalendar.add(Calendar.DAY_OF_MONTH, 1);
list.add(getContent(currentCalendar));
}
Log.i("text", "yaer: " + list.get(0).getYear());
Log.i("text", "month: " + list.get(0).getMonth());
Log.i("text", "day of month: " + list.get(0).getDay());
Log.i("text", "day of week: " + list.get(0).getDayOfWeek());
return list;
}
private int getDayOfWeek(GregorianCalendar currentCalendar) {
int weekDay;
if (firstDayOfWeek == Calendar.MONDAY) {
weekDay = 7 - (8 - currentCalendar.get(Calendar.DAY_OF_WEEK)) % 7;
}
else weekDay = currentCalendar.get(Calendar.DAY_OF_WEEK);
return weekDay;
}
private GraphicContent getContent(GregorianCalendar cal) {
GraphicContent content = new GraphicContent();
content.setYear(cal.get(Calendar.YEAR));
content.setMonth(cal.get(Calendar.MONTH));
content.setDay(cal.get(Calendar.DAY_OF_MONTH));
content.setDayOfWeek(cal.get(Calendar.DAY_OF_WEEK));
return content;
}
}
public class GraphicContent extends ContentAbstract {
private int year;
private int month;
private int day;
private int dayOfWeek;
#Override
public int getYear() {
return year;
}
#Override
public void setYear(int year) {
this.year = year;
}
#Override
public int getMonth() {
return month;
}
#Override
public void setMonth(int month) {
this.month = month;
}
#Override
public int getDay() {
return day;
}
#Override
public void setDay(int day) {
this.day = day;
}
#Override
public int getDayOfWeek() {
return dayOfWeek;
}
#Override
public void setDayOfWeek(int dayOfWeek) {
this.dayOfWeek = dayOfWeek;
}
}
Set the class constructor (new GregorianCalendar(1994, 3, 1), Calendar.SUNDAY). In android 4.4, 5.0 Logcat result:
10-12 14:32:28.332 27739-27739/*** I/text: yaer: 1994
10-12 14:32:28.332 27739-27739/*** I/text: month: 2
10-12 14:32:28.332 27739-27739/*** I/text: day of month: 26
10-12 14:32:28.332 27739-27739/*** I/text: day of week: 7
In android 8.0 Logcat result:
2018-10-12 11:50:59.549 6565-6565/*** I/text: yaer: 1994
2018-10-12 11:50:59.549 6565-6565/*** I/text: month: 2
2018-10-12 11:50:59.549 6565-6565/*** I/text: day of month: 27
2018-10-12 11:50:59.549 6565-6565/*** I/text: day of week: 1
As you can see the result - different days (26 and 27), which corresponds to different days of the week. BUT IF YOU CHANGE THE INITIALIZATION of the calendar object:
#Override
public List<ContentAbstract> getListContent() {
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
GregorianCalendar currentCalendar = (GregorianCalendar) Calendar.getInstance();
currentCalendar.set(year, month, 1);
The RESULT WILL BE TRUE on all versions of android:
10-12 15:12:56.400 28914-28914/*** I/text: yaer: 1994
10-12 15:12:56.400 28914-28914/*** I/text: month: 2
10-12 15:12:56.400 28914-28914/*** I/text: day of month: 27
10-12 15:12:56.400 28914-28914/*** I/text: week day: 1
In junit tests the result is correct in all cases (27 and SUNDAY). Delete the logs from the code and check:
public class TestCurrentMonth {
#Test
public void testGetListContent() {
GregorianCalendar calendar = new GregorianCalendar(1994, 3, 1);
int firstDay = Calendar.SUNDAY;
CurrentMonth currentMonth = new CurrentMonth(calendar, firstDay);
List<ContentAbstract> list = currentMonth.getListContent();
Assert.assertEquals(27, list.get(0).getDay());
Assert.assertEquals(Calendar.SUNDAY, list.get(0).getDayOfWeek());
}
}
Also behavior for April 1993, 1992. Why? I already broke my brains.
java.time
The good solution is to skip the Calendar and GregorianCalendar classes and use LocalDate from java.time, the modern Java date and time API, instead. Calendar and GregorianCalendar are long outdated and poorly designed. The modern API is so much nicer to work with. And LocalDate is a date without time and without time zone, so if the suspicion that I am airing below is correct, it will guarantee to leave your time zone/summer time issue behind. To use it on older Android, see further down.
What went wrong? Speculative explanation
The following explanation is purely theoretical, but the best I have been able to think of. It relies on a couple of assumptions that I have not been able to verify:
You are (or one of your devices is) in a time zone where summer time (DST) began in the last days of March 1994.
There might be a bug in GregorianCalendar in Android 4.4 and 5.0 so that currentCalendar.add(Calendar.DAY_OF_WEEK, - (weekDay - 1)); just adds that many times 24 hours.
It’s pure speculation, but if there is such a bug, your GregorianCalendar will end up at 23:00 on the evening before the target date, which would explain your results. Countries in EU, for example, begin summer time on the last Sunday of March. This was also the case in 1994. This would fit your target date of Sunday, March 27, 1994 very nicely, and would also explain your wrong results for 1992 and 1993. I have made a brief Internet search for mention of such a bug in Android GregorianCalendar and didn’t find anything to support it.
For my suspicion to explain your observations, we need a couple of pieces more:
The bug I am suspecting would be only in some Android versions (4.4, 5.0) and fixed in later versions (8.0) (alternatively you Android 8.0 device would be running a different time zone). Also the enviroment where you run your tests either doesn’t have the bug or has a different default time zone (either would explain why the tests pass).
The GregorianCalendar you get from getInstance has time of day in it. And keeps it after you set the date. To spell out the difference between the two ways you set the date: Say you run your code at 9:05. new GregorianCalendar(1994, Calendar.APRIL, 1) will give you April 1, 1994 at 00:00. Calendar.getInstance() followed by currentCalendar.set(year, month, 1); gives you April 1, 1994 at 09:05. There’s a little over 9 hours difference between the two. In the latter case the suspected bug will cause you to hit 8:05 on 27 March, which is still on the correct date, so you don’t see the bug. If you ran your code at, say, 0:35 in the night, you’d hit 23:35 on 26 March, so you’d see the bug at that case too.
As I already said, LocalDate, java.time and the ThreeTenABP would form the good solution. If you choose not to rely on an external library but rather fight your way through with the outdated classes, I believe that the following would help:
GregorianCalendar currentCalendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
currentCalendar.set(year, month, 1);
TimeZone is yet one more old and poorly designed classes, in particular the getTimeZone method that I am using has some nasty surprises to it, but I believe the above works (fingers crossed). The idea is to tell the Calendar to use UTC time. UTC does not have summer time, which evades the problem.
Another and more hacky thing you might try, would be:
currentCalendar.set(year, month, 1, 6, 0);
This sets the hour of day to 6, meaning that when you go back across the summer time transition, you will hit 5:00 in the morning, which will still be on the correct date (the call above does not set the seconds and milliseconds; in one run I got April 1, 1994 at 06:00:40.213 UTC).
Question: Can I use java.time on Android?
Yes, java.time works nicely on older and newer Android devices. It just requires at least Java 6.
In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.
In Java 6 and 7 get the ThreeTen Backport, the backport of the new classes (ThreeTen for JSR 310; see the links at the bottom).
On (older) Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.time to Java 6 and 7 (ThreeTen for JSR-310).
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
Nothing strange here. getInstance will return data based on your locale and time zone, unlike conststructor. Not sure about newer Android versions, maybe something changed here or you tested with different time zones/locales?
I have a date class and it has the following
public class Date {
public int month;
public int day;
public int year;
public Date(int m, int d, int y)
{
month = m;
day = d;
year = y;
}
public Date increase(int numberOfDays)
{
day += numberOfDays;
return this;
}
My question is what is the easiest way to do increasing of number of days to that given instance of Date? Like for example I have a created an instance of new Date(4,20,2016).increase(30); which would increase the given date addition 30 days. That would be sometime in May 19 I think. The method above should work if it's less than the max day of the month. But I haven't figure out how to do the calculation including the month and year. Like I added 365 days to that date would be 4/20/2017. Just an idea would be helpful. Thanks
use Java Calendar object instead. https://docs.oracle.com/javase/7/docs/api/java/util/Calendar.html
Date date = new Date();
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.add(Calendar.DATE, 30); // add 30 days
date = cal.getTime();
using jcalendar you can add the dates try this example
Implementing this yourself is a suprisingly tricky task. More so since you are storing your Date as a separate month, year and day. You would have to store information about the number of days in every month, along with information about leap years. In short, trying to re-implement Date is not easy.
One solution to storing a "day, month, year" date before Java 8 came along was to use Joda. Using Joda's LocalDate class, you can do:
LocalDate date = LocalDate.now();
date = date.plusDays(30);
This functionality is now available in Java 8's java.time package, using the same LocalDate class name. Take a look at the source code for either package to see how it's implemented.
In short, LocalDate.plusDays() first converts the "month, day, year" date to a single number of days since the "epoch", using an algorithm that's around twenty lines long. Then, it adds the requested number of days to that number. Finally, it converts that number back to a "day, month, year" using another algorithm that's even longer.
I would like to have a compareTo method that ignores the time portion of a java.util.Date. I guess there are a number of ways to solve this. What's the simplest way?
Update: while Joda Time was a fine recommendation at the time, use the java.time library from Java 8+ instead where possible.
My preference is to use Joda Time which makes this incredibly easy:
DateTime first = ...;
DateTime second = ...;
LocalDate firstDate = first.toLocalDate();
LocalDate secondDate = second.toLocalDate();
return firstDate.compareTo(secondDate);
EDIT: As noted in comments, if you use DateTimeComparator.getDateOnlyInstance() it's even simpler :)
// TODO: consider extracting the comparator to a field.
return DateTimeComparator.getDateOnlyInstance().compare(first, second);
("Use Joda Time" is the basis of almost all SO questions which ask about java.util.Date or java.util.Calendar. It's a thoroughly superior API. If you're doing anything significant with dates/times, you should really use it if you possibly can.)
If you're absolutely forced to use the built in API, you should create an instance of Calendar with the appropriate date and using the appropriate time zone. You could then set each field in each calendar out of hour, minute, second and millisecond to 0, and compare the resulting times. Definitely icky compared with the Joda solution though :)
The time zone part is important: java.util.Date is always based on UTC. In most cases where I've been interested in a date, that's been a date in a specific time zone. That on its own will force you to use Calendar or Joda Time (unless you want to account for the time zone yourself, which I don't recommend.)
Quick reference for android developers
//Add joda library dependency to your build.gradle file
dependencies {
...
implementation 'joda-time:joda-time:2.9.9'
}
Sample code (example)
DateTimeComparator dateTimeComparator = DateTimeComparator.getDateOnlyInstance();
Date myDateOne = ...;
Date myDateTwo = ...;
int retVal = dateTimeComparator.compare(myDateOne, myDateTwo);
if(retVal == 0)
//both dates are equal
else if(retVal < 0)
//myDateOne is before myDateTwo
else if(retVal > 0)
//myDateOne is after myDateTwo
Apache commons-lang is almost ubiquitous. So what about this?
if (DateUtils.isSameDay(date1, date2)) {
// it's same
} else if (date1.before(date2)) {
// it's before
} else {
// it's after
}
If you really want to use the java.util.Date, you would do something like this:
public class TimeIgnoringComparator implements Comparator<Date> {
public int compare(Date d1, Date d2) {
if (d1.getYear() != d2.getYear())
return d1.getYear() - d2.getYear();
if (d1.getMonth() != d2.getMonth())
return d1.getMonth() - d2.getMonth();
return d1.getDate() - d2.getDate();
}
}
or, using a Calendar instead (preferred, since getYear() and such are deprecated)
public class TimeIgnoringComparator implements Comparator<Calendar> {
public int compare(Calendar c1, Calendar c2) {
if (c1.get(Calendar.YEAR) != c2.get(Calendar.YEAR))
return c1.get(Calendar.YEAR) - c2.get(Calendar.YEAR);
if (c1.get(Calendar.MONTH) != c2.get(Calendar.MONTH))
return c1.get(Calendar.MONTH) - c2.get(Calendar.MONTH);
return c1.get(Calendar.DAY_OF_MONTH) - c2.get(Calendar.DAY_OF_MONTH);
}
}
My preference would be to use the Joda library insetad of java.util.Date directly, as Joda makes a distinction between date and time (see YearMonthDay and DateTime classes).
However, if you do wish to use java.util.Date I would suggest writing a utility method; e.g.
public static Date setTimeToMidnight(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime( date );
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
return calendar.getTime();
}
Any opinions on this alternative?
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
sdf.format(date1).equals(sdf.format(date2));
If you want to compare only the month, day and year of two dates, following code works for me:
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
sdf.format(date1).equals(sdf.format(date2));
Thanks Rob.
tl;dr
myJavaUtilDate1.toInstant()
.atZone( ZoneId.of( "America/Montreal" ) )
.toLocalDate()
.isEqual (
myJavaUtilDate2.toInstant()
.atZone( ZoneId.of( "America/Montreal" ) )
.toLocalDate()
)
Avoid legacy date-time classes
Avoid the troublesome old legacy date-time classes such as Date & Calendar, now supplanted by the java.time classes.
Using java.time
A java.util.Date represents a moment on the timeline in UTC. The equivalent in java.time is Instant. You may convert using new methods added to the legacy class.
Instant instant1 = myJavaUtilDate1.toInstant();
Instant instant2 = myJavaUtilDate2.toInstant();
You want to compare by date. 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 the Instant to get a ZonedDateTime.
ZonedDateTime zdt1 = instant1.atZone( z );
ZonedDateTime zdt2 = instant2.atZone( z );
The LocalDate class represents a date-only value without time-of-day and without time zone. We can extract a LocalDate from a ZonedDateTime, effectively eliminating the time-of-day portion.
LocalDate localDate1 = zdt1.toLocalDate();
LocalDate localDate2 = zdt2.toLocalDate();
Now compare, using methods such as isEqual, isBefore, and isAfter.
Boolean sameDate = localDate1.isEqual( localDate2 );
See this code run live at IdeOne.com.
instant1: 2017-03-25T04:13:10.971Z | instant2: 2017-03-24T22:13:10.972Z
zdt1: 2017-03-25T00:13:10.971-04:00[America/Montreal] | zdt2: 2017-03-24T18:13:10.972-04:00[America/Montreal]
localDate1: 2017-03-25 | localDate2: 2017-03-24
sameDate: false
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 and SE 9 and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
See How to use 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 too prefer Joda Time, but here's an alternative:
long oneDay = 24 * 60 * 60 * 1000
long d1 = first.getTime() / oneDay
long d2 = second.getTime() / oneDay
d1 == d2
EDIT
I put the UTC thingy below in case you need to compare dates for a specific timezone other than UTC. If you do have such a need, though, then I really advise going for Joda.
long oneDay = 24 * 60 * 60 * 1000
long hoursFromUTC = -4 * 60 * 60 * 1000 // EST with Daylight Time Savings
long d1 = (first.getTime() + hoursFromUTC) / oneDay
long d2 = (second.getTime() + hoursFromUTC) / oneDay
d1 == d2
Already mentioned apache commons-utils:
org.apache.commons.lang.time.DateUtils.truncate(date, Calendar.DAY_OF_MONTH)
gives you Date object containing only date, without time, and you can compare it with Date.compareTo
If you're using Java 8, you should use the java.time.* classes to compare dates - it's preferred to the various java.util.* classes
eg; https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html
LocalDate date1 = LocalDate.of(2016, 2, 14);
LocalDate date2 = LocalDate.of(2015, 5, 23);
date1.isAfter(date2);
I am afraid there is no method of comparing two dates that could be called "easy" or "simple".
When comparing two time instances with any sort of reduced precision (e.g. just comparing dates), you must always take into account how time zone affects the comparison.
If date1 is specifying an event that occurred in +2 timezone and date2 is specifying an event that occurred in EST, for example, you must take care to properly understand the implications of the comparison.
Is your purpose to figure out if the two events occurred in the same calendar date in their own respective time zones? Or do You need to know if the two dates fall into the same calendar date in a specific time zone (UTC or your local TZ, for example).
Once you figure out what it is actually that You are trying to compare, it is just a matter of getting the year-month-date triple in an appropriate time zone and do the comparison.
Joda time might make the actual comparison operation look much cleaner, but the semantics of the comparison are still something You need to figure out yourself.
Simply Check DAY_OF_YEAR in combination with YEAR property
boolean isSameDay =
firstCal.get(Calendar.YEAR) == secondCal.get(Calendar.YEAR) &&
firstCal.get(Calendar.DAY_OF_YEAR) == secondCal.get(Calendar.DAY_OF_YEAR)
EDIT:
Now we can use the power of Kotlin extension functions
fun Calendar.isSameDay(second: Calendar): Boolean {
return this[Calendar.YEAR] == second[Calendar.YEAR] && this[Calendar.DAY_OF_YEAR] == second[Calendar.DAY_OF_YEAR]
}
fun Calendar.compareDatesOnly(other: Calendar): Int {
return when {
isSameDay(other) -> 0
before(other) -> -1
else -> 1
}
}
If you just want to compare only two dates without time, then following code might help you:
final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
Date dLastUpdateDate = dateFormat.parse(20111116);
Date dCurrentDate = dateFormat.parse(dateFormat.format(new Date()));
if (dCurrentDate.after(dLastUpdateDate))
{
add your logic
}
I don't know it is new think or else, but i show you as i done
SimpleDateFormat dtf = new SimpleDateFormat("dd/MM/yyyy");
Date td_date = new Date();
String first_date = dtf.format(td_date); //First seted in String
String second_date = "30/11/2020"; //Second date you can set hear in String
String result = (first_date.equals(second_date)) ? "Yes, Its Equals":"No, It is not Equals";
System.out.println(result);
Here is a solution from this blog: http://brigitzblog.blogspot.com/2011/10/java-compare-dates.html
long milliseconds1 = calendar1.getTimeInMillis();
long milliseconds2 = calendar2.getTimeInMillis();
long diff = milliseconds2 - milliseconds1;
long diffDays = diff / (24 * 60 * 60 * 1000);
System.out.println("Time in days: " + diffDays + " days.");
i.e. you can see if the time difference in milliseconds is less than the length of one day.
`
SimpleDateFormat sdf= new SimpleDateFormat("MM/dd/yyyy")
Date date1=sdf.parse("03/25/2015");
Date currentDate= sdf.parse(sdf.format(new Date()));
return date1.compareTo(currentDate);
`
Using http://mvnrepository.com/artifact/commons-lang/commons-lang
Date date1 = new Date();
Date date2 = new Date();
if (DateUtils.truncatedCompareTo(date1, date2, Calendar.DAY_OF_MONTH) == 0)
// TRUE
else
// FALSE
In Java 8 you can use LocalDate which is very similar to the one from Joda Time.
public Date saveDateWithoutTime(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime( date );
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.HOUR, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
return calendar.getTime();
}
This will help you to compare dates without considering the time.
Using the getDateInstance of SimpleDateFormat, we can compare only two date object without time. Execute the below code.
public static void main(String[] args) {
Date date1 = new Date();
Date date2 = new Date();
DateFormat dfg = SimpleDateFormat.getDateInstance(DateFormat.DATE_FIELD);
String dateDtr1 = dfg.format(date1);
String dateDtr2 = dfg.format(date2);
System.out.println(dateDtr1+" : "+dateDtr2);
System.out.println(dateDtr1.equals(dateDtr2));
}
Another Simple compare method based on the answers here and my mentor guidance
public static int compare(Date d1, Date d2) {
Calendar c1 = Calendar.getInstance();
Calendar c2 = Calendar.getInstance();
c1.setTime(d1);
c1.set(Calendar.MILLISECOND, 0);
c1.set(Calendar.SECOND, 0);
c1.set(Calendar.MINUTE, 0);
c1.set(Calendar.HOUR_OF_DAY, 0);
c2.setTime(d2);
c2.set(Calendar.MILLISECOND, 0);
c2.set(Calendar.SECOND, 0);
c2.set(Calendar.MINUTE, 0);
c2.set(Calendar.HOUR_OF_DAY, 0);
return c1.getTime().compareTo(c2.getTime());
}
EDIT:
According to #Jonathan Drapeau, the code above fail some cases (I would like to see those cases, please) and he suggested the following as I understand:
public static int compare2(Date d1, Date d2) {
Calendar c1 = Calendar.getInstance();
Calendar c2 = Calendar.getInstance();
c1.clear();
c2.clear();
c1.set(Calendar.YEAR, d1.getYear());
c1.set(Calendar.MONTH, d1.getMonth());
c1.set(Calendar.DAY_OF_MONTH, d1.getDay());
c2.set(Calendar.YEAR, d2.getYear());
c2.set(Calendar.MONTH, d2.getMonth());
c2.set(Calendar.DAY_OF_MONTH, d2.getDay());
return c1.getTime().compareTo(c2.getTime());
}
Please notice that, the Date class is deprecated cause it was not amenable to internationalization. The Calendar class is used instead!
First, be aware that this operation depends on the time zone. So choose whether you want to do it in UTC, in the computer’s time zone, in your own favourite time zone or where. If you are not yet convinced it matters, see my example at the bottom of this answer.
Since your question isn’t quite clear about this, I am assuming that you have a class with an instance field representing a point in time and implementing Comparable, and you want the natural ordering of your objects to be by the date, but not the time, of that field. For example:
public class ArnesClass implements Comparable<ArnesClass> {
private static final ZoneId arnesTimeZone = ZoneId.systemDefault();
private Instant when;
#Override
public int compareTo(ArnesClass o) {
// question is what to put here
}
}
Java 8 java.time classes
I have taken the freedom of changing the type of your instance field from Date to Instant, the corresponding class in Java 8. I promise to return to the treatment of Date below. I have also added a time zone constant. You may set it to ZoneOffset.UTC or ZoneId.of("Europe/Stockholm") or what you find appropriate (setting it to a ZoneOffset works because ZoneOffset is a subclass of ZoneId).
I have chosen to show the solution using the Java 8 classes. You asked for the simplest way, right? :-) Here’s the compareTo method you asked for:
public int compareTo(ArnesClass o) {
LocalDate dateWithoutTime = when.atZone(arnesTimeZone).toLocalDate();
LocalDate otherDateWithoutTime = o.when.atZone(arnesTimeZone).toLocalDate();
return dateWithoutTime.compareTo(otherDateWithoutTime);
}
If you never need the time part of when, it is of course easier to declare when a LocalDate and skip all conversions. Then we don’t have to worry about the time zone anymore either.
Now suppose that for some reason you cannot declare your when field an Instant or you want to keep it an old-fashioned Date. If you can still use Java 8, just convert it to Instant, then do as before:
LocalDate dateWithoutTime = when.toInstant().atZone(arnesTimeZone).toLocalDate();
Similarly for o.when.
No Java 8?
If you cannot use java 8, there are two options:
Solve it using one of the old classes, either Calendar or SimpleDateFormat.
Use the backport of the Java 8 date and time classes to Java 6 and 7, then just do as above. I include a link at the bottom. Do not use JodaTime. JodaTime was probably a good suggestion when the answers recommending it were written; but JodaTime is now in maintenance mode, so the ThreeTen backport is a better and more futureproof option.
The old-fashioned ways
Adamski’s answer shows you how to strip the time part off a Date using the Calendar class. I suggest you use getInstance(TimeZone) to obtain the Calendar instance for the time zone you want. As an alternative you may use the idea from the second half of Jorn’s answer.
Using SimpleDateFormat is really an indirect way of using Calendar since a SimpleDateFormat contains a Calendar object. However, you may find it less troublesome than using Calendar directly:
private static final TimeZone arnesTimeZone = TimeZone.getTimeZone("Europe/Stockholm");
private static final DateFormat formatter = new SimpleDateFormat("yyyyMMdd");
static {
formatter.setTimeZone(arnesTimeZone);
}
private Date when;
#Override
public int compareTo(ArnesClass o) {
return formatter.format(when).compareTo(formatter.format(o.when));
}
This was inspired by Rob’s answer.
Time zone dependency
Why do we have to pick a specific time zone? Say that we want to compare two times that in UTC are March 24 0:00 (midnight) and 12:00 (noon). If you do that in CET (say, Europe/Paris), they are 1 am and 1 pm on March 24, that is, the same date. In New York (Eastern Daylight Time), they are 20:00 on March 23 and 8:00 on March 24, that is, not the same date. So it makes a difference which time zone you pick. If you just rely on the computer’s default, you may be in for surprises when someone tries to run your code on a computer in another place in this globalized world.
Link
Link to ThreeTen Backport, the backport of the Java 8 date and time classes to Java 6 and 7: http://www.threeten.org/threetenbp/.
My proposition:
Calendar cal = Calendar.getInstance();
cal.set(1999,10,01); // nov 1st, 1999
cal.set(Calendar.AM_PM,Calendar.AM);
cal.set(Calendar.HOUR,0);
cal.set(Calendar.MINUTE,0);
cal.set(Calendar.SECOND,0);
cal.set(Calendar.MILLISECOND,0);
// date column in the Thought table is of type sql date
Thought thought = thoughtDao.getThought(date, language);
Assert.assertEquals(cal.getTime(), thought.getDate());
Using Apache commons you can do:
import org.apache.commons.lang3.time.DateUtils
DateUtils.truncatedEquals(first, second, Calendar.DAY_OF_MONTH)
public static Date getZeroTimeDate(Date fecha) {
Date res = fecha;
Calendar calendar = Calendar.getInstance();
calendar.setTime( fecha );
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
res = calendar.getTime();
return res;
}
Date currentDate = getZeroTimeDate(new Date());// get current date
this is the simplest way to solve this problem.
I solved this by comparing by timestamp:
Calendar last = Calendar.getInstance();
last.setTimeInMillis(firstTimeInMillis);
Calendar current = Calendar.getInstance();
if (last.get(Calendar.DAY_OF_MONTH) != current.get(Calendar.DAY_OF_MONTH)) {
//not the same day
}
I avoid to use Joda Time because on Android uses a huge space. Size matters. ;)
Another solution using Java 8 and Instant, is using the truncatedTo method
Returns a copy of this Instant truncated to the specified unit.
Example:
#Test
public void dateTruncate() throws InterruptedException {
Instant now = Instant.now();
Thread.sleep(1000*5);
Instant later = Instant.now();
assertThat(now, not(equalTo(later)));
assertThat(now.truncatedTo(ChronoUnit.DAYS), equalTo(later.truncatedTo(ChronoUnit.DAYS)));
}
// Create one day 00:00:00 calendar
int oneDayTimeStamp = 1523017440;
Calendar oneDayCal = Calendar.getInstance();
oneDayCal.setTimeInMillis(oneDayTimeStamp * 1000L);
oneDayCal.set(Calendar.HOUR_OF_DAY, 0);
oneDayCal.set(Calendar.MINUTE, 0);
oneDayCal.set(Calendar.SECOND, 0);
oneDayCal.set(Calendar.MILLISECOND, 0);
// Create current day 00:00:00 calendar
Calendar currentCal = Calendar.getInstance();
currentCal.set(Calendar.HOUR_OF_DAY, 0);
currentCal.set(Calendar.MINUTE, 0);
currentCal.set(Calendar.SECOND, 0);
currentCal.set(Calendar.MILLISECOND, 0);
if (oneDayCal.compareTo(currentCal) == 0) {
// Same day (excluding time)
}
If you strictly want to use Date ( java.util.Date ), or without any use of external Library. Use this :
public Boolean compareDateWithoutTime(Date d1, Date d2) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
return sdf.format(d1).equals(sdf.format(d2));
}
Date today = new Date();
Date endDate = new Date();//this
endDate.setTime(endDate.getTime() - ((endDate.getHours()*60*60*1000) + (endDate.getMinutes()*60*1000) + (endDate.getSeconds()*1000)));
today.setTime(today.getTime() - ((today.getHours()*60*60*1000) + (today.getMinutes()*60*1000) + (today.getSeconds()*1000)));
System.out.println(endDate.compareTo(today) <= 0);
I am simply setting hours/minutes/second to 0 so no issue with the time as time will be same now for both dates. now you simply use compareTo. This method helped to find "if dueDate is today" where true means Yes.
Let me explain myself. By knowing the week number and the year of a date:
Date curr = new Date();
Calendar cal = Calendar.getInstance();
cal.setTime(curr);
int nweek = cal.WEEK_OF_YEAR;
int year = cal.YEAR;
But now I don't know how to get the date of the first day of that week. I've been looking in Calendar, Date, DateFormat but nothing that may be useful...
Any suggestion? (working in Java)
Those fields does not return the values. Those are constants which identifies the fields in the Calendar object which you can get/set/add. To achieve what you want, you first need to get a Calendar, clear it and set the known values. It will automatically set the date to first day of that week.
// We know week number and year.
int week = 3;
int year = 2010;
// Get calendar, clear it and set week number and year.
Calendar calendar = Calendar.getInstance();
calendar.clear();
calendar.set(Calendar.WEEK_OF_YEAR, week);
calendar.set(Calendar.YEAR, year);
// Now get the first day of week.
Date date = calendar.getTime();
Please learn to read the javadocs to learn how to use classes/methods/fields and do not try to poke random in your IDE ;)
That said, the java.util.Date and java.util.Calendar are epic failures. If you can, consider switching to Joda Time.
Try this:
public static Calendar setWeekStart(Calendar calendar) {
while (calendar.get(Calendar.DAY_OF_WEEK) != Calendar.MONDAY) {
calendar.add(Calendar.DATE, -1);
}
setDayStart(calendar); // method which sets H:M:S:ms to 0
return calendar;
}
java.time
The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*.
Also, quoted below is a notice from the home page of Joda-Time:
Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.
Solution using java.time, the modern Date-Time API:
import java.time.LocalDate;
import java.time.temporal.WeekFields;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
// Test
int weekNumber = 34;
int year = 2021;
System.out.println(getFirstDayOfWeek(year, weekNumber, Locale.UK));
System.out.println(getFirstDayOfWeek(year, weekNumber, Locale.US));
}
static LocalDate getFirstDayOfWeek(int year, int weekNumber, Locale locale) {
return LocalDate
.of(year, 2, 1)
.with(WeekFields.of(locale).getFirstDayOfWeek())
.with(WeekFields.of(locale).weekOfWeekBasedYear(), weekNumber);
}
}
Output:
2021-08-23
2021-08-15
ONLINE DEMO
Note that the first day of the week is Locale-dependent e.g. it is Monday in the UK while Sunday in the US. As per the ISO 8601 standards, it is Monday. For comparison, check the US calendar and the UK calendar.
Learn more about the modern Date-Time API* from Trail: Date Time.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.
I haven't done much Date stuff in java but a solution might be:
cal.set(Calendar.DAY_OF_YEAR, cal.get(Calendar.DAY_OF_YEAR) - cal.get(Calendar.DAY_OF_WEEK));
Logic:
Get the day of the week and substract it from the current date (might need -1, depending on wether you need monday to be first day of the week or sunday)
Yet another way...
GregorianCalendar cal = new GregorianCalendar();
cal.clearTime();
Integer correction = 1-cal.get(GregorianCalendar.DAY_OF_WEEK)
cal.add(Calendar.DATE, correction);
cal is now the first day of the week
1-cal.get(GregorianCalendar.DAY_OF_WEEK)
evaluates to 1-1 for Sunday (first day of week in my Locale) and 1-2 for Monday, so this will give you the correction needed to rewind the clock back to Sunday
Be cautious with those, calendar.get(Calendar.WEEK_OF_YEAR) returns 1 if it is end of December and already a week that ends in the next year.
Using
// cal2.set(Calendar.WEEK_OF_YEAR, cal.get(Calendar.WEEK_OF_YEAR));
// cal2.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
sets the cal2 date to e.g. end of 2009 on 29/12/2010 !!
I used this:
cal2.set(Calendar.DAY_OF_YEAR, cal.get(Calendar.DAY_OF_YEAR)); //to round at the start of day
cal2.set(Calendar.YEAR, cal.get(Calendar.YEAR));
cal2.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY); //to round at the start of week
I also make sure that weeks in my calendars, no matter what locale they are in, are starting on Mondays:
cal.setFirstDayOfWeek(Calendar.MONDAY);
cal2.setFirstDayOfWeek(Calendar.MONDAY);
Try the Gregorian Calendar algorithm:
public int getFirstDay(int m, int year)
{
int k=1;
int c, y, w, M=0;
if(m>2 && m<=12) M=m-2;
else if(m>0 && M<=2)
{
M=m+10;
year-=1;
}
c=year/100;
y=year%100;
w=(int)((k+(Math.floor(2.6*M - 0.2))-2*c+y+(Math.floor(y/4))+(Math.floor(c/4)))%7);//a fantastic formula
if(w<0) w+=7;
return w;//thus the day of the week is obtained!
}
Here's some quick and dirty code to do this. This code creates a calendar object with the date of the current day, calculates the current day of the week, and subtracts the day of the week so you're on the first one (Sunday). Although I'm using DAY_OF_YEAR it goes across years fine (on 1/2/10 it'll return 12/27/09 which is right).
import java.text.Format;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
public class DOW {
public static void main(String[] args) {
DOW dow = new DOW();
dow.doIt();
System.exit(0);
}
private void doIt() {
Date curr = new Date();
Calendar cal = Calendar.getInstance();
cal.setTime(curr);
int currentDOW = cal.get(Calendar.DAY_OF_WEEK);
cal.add(Calendar.DAY_OF_YEAR, (currentDOW * -1)+1);
Format formatter = new SimpleDateFormat("MM/dd/yy");
System.out.println("First day of week="+formatter.format(cal.getTime()));
}
}