1

I'm looking to see if there is a better way in obtaining the same result as the following code:

Calendar date = Calendar.getInstance();
date.setTimeInMillis(System.currentTimeMillis());
date.set(Calendar.HOUR_OF_DAY, 0);
date.set(Calendar.MINUTE, 0);
date.set(Calendar.SECOND, 0);
date.set(Calendar.MILLISECOND, 0);

I'm using this to be able to compare the difference in days between two dates. I am currently coding for target API 24 and am not interested in using Joda Time for such a simple task.

I've come up with the following function, but would love to hear if there is a simpler, perhaps built in, method for either zeroing out the date or an entire different method for getting the amount of days between two dates.

private long getFlatDateInMillis() {
    Calendar currentDate = Calendar.getInstance();
    currentDate.setTimeInMillis(System.currentTimeMillis());
    currentDate.set(Calendar.HOUR_OF_DAY, 0);
    currentDate.set(Calendar.MINUTE, 0);
    currentDate.set(Calendar.SECOND, 0);
    currentDate.set(Calendar.MILLISECOND, 0);

    return currentDate.getTimeInMillis();
}

That way, I could quickly use:

Calendar date = getFlatDateInMillis();

I just want to make sure I'm not missing anything that is simpler, already pre-defined.

Thank you!

  • Why do you need it. If it works. in this way the question is off-topic. – Roman C Mar 19 '18 at 01:15
  • Thanks for replying. "I just want to make sure I'm not missing anything that is simpler, already pre-defined." – Bridger Burt Mar 19 '18 at 01:17
  • you can't ask such questions on SO because you didn't tell what do you think is simpler, already pre-defined – Roman C Mar 19 '18 at 01:18
  • Possible this discussion will help: https://stackoverflow.com/questions/5050170/how-do-i-get-a-date-without-time-in-java – Shobhit Puri Mar 19 '18 at 01:23
  • `currentDate.setTimeInMillis(System.currentTimeMillis());` can be removed. Otherwise, this could be done cleaner with Joda Time or [ThreeTen](http://www.threeten.org/threetenbp/). If you don't want to use those, then this is fine. – Elliott Frisch Mar 19 '18 at 01:24
  • Thank you @Shobhit – Bridger Burt Mar 19 '18 at 01:28
  • So, I only need to use `currentDate.setTimeInMillis(System.currentTimeMillis());` when setting a date _back_ to the current time, correct? – Bridger Burt Mar 19 '18 at 01:31
  • Or to set a calendar date to midnight of that day currentDate.setTimeInMillis((currentDate.getTimeInMillis()/86400000)*86400000) –  Mar 19 '18 at 01:37
  • @Andy that only works if the timezone is UTC. – Dawood ibn Kareem Mar 19 '18 at 02:30
  • FYI, the troublesome old date-time classes such as `java.util.Date`, `java.util.Calendar`, and `java.text.SimpleDateFormat` are now legacy, supplanted by the [*java.time*](https://docs.oracle.com/javase/9/docs/api/java/time/package-summary.html) classes. Much of the *java.time* functionality is back-ported to Java 6 & Java 7 in the [***ThreeTen-Backport***](http://www.threeten.org/threetenbp/) project. Further adapted for earlier Android in the [***ThreeTenABP***](https://github.com/JakeWharton/ThreeTenABP) project. See [*How to use ThreeTenABP…*](http://stackoverflow.com/q/38922754/642706). – Basil Bourque Mar 21 '18 at 23:24

3 Answers3

2

The correct way to do this is with the java.time.LocalDate class. It stores only the date, not the time, and it has a now() static method, which returns the current day.

LocalDate today = LocalDate.now();

If you're looking at Android, this was added at API level 26, but there are other ways of using the "new style" date classes with Android, such as the ThreeTen-Backport library.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
Dawood ibn Kareem
  • 77,785
  • 15
  • 98
  • 110
  • 1
    I like this answer. Will have to heavily consider this as it is future maintainable. Thank you very much. – Bridger Burt Mar 19 '18 at 03:01
  • For use on pre-26 Android, see [How to use ThreeTenABP in Android Project](https://stackoverflow.com/questions/38922754/how-to-use-threetenabp-in-android-project). – Ole V.V. Mar 19 '18 at 08:20
  • 1
    I wanted to use java.time really badly (so much easier to use), but had no idea of ThreeTen backport. Thank you to the both of you. – Bridger Burt Mar 19 '18 at 21:28
0

EDIT: Thanks to Basil and Kareem, I've updated to the following code (so, so much easier):

Added to gradle.build:

compile 'com.jakewharton.threetenabp:threetenabp:1.0.5'

Then, in my activity, etc,

AndroidThreeTen.init(this);

LocalDate today = LocalDate.now();
LocalDate anotherDay = LocalDate.of(2019, 3, 25);
long dayDifference = ChronoUnit.DAYS.between(today, anotherDay); //dayDifference = 365

One thing of note is that Calendar references months starting at 0 index, whereas LocalDate references months starting at 1 index.

0

tl;dr

ChronoUnit.DAYS.between(                    // Calculate elapsed time between a pair of `LocalDate` date-only objects. Returns a total number of elapsed days.
    ( (GregorianCalendar) myJavaUtilCal )   // Cast your legacy `java.util.Calendar` object to the subclass `java.util.GregorianCalendar`, also legacy. 
        .toZonedDateTime()                  // Convert from legacy `GregorianCalendar` to modern `ZonedDateTime` class.
        .toLocalDate()  ,                   // Extract the date-only value, a `LocalDate`, lacking time-of-day and lacking time zone.
    otherLocalDate                          // Compare to some other `LocalDate` object.
)                                           // Returns a `long` number of days. Uses Half-Open approach where the beginning is *inclusive* while the ending is *exclusive*. 

Details

The Answer by Kareem is correct. Some more thoughts here.

Is there a better way to zero out Calendar date?

Yes, there is a better way: don’t.

  • Trying to clear out the time-of-day on a date+time types is the wrong approach; use a date-only type instead (LocalDate).
  • And don’t use the troublesome old legacy classes such as Calendar, Date, SimpleDateFormat as they are now supplanted by the java.time classes.

the difference in days between two dates

First convert your legacy Calendar object to the modern ZonedDateTime class. To convert, call new methods added to the old classes.

GregorianCalendar myGregCal = (GregorianCalendar) myJavaUtilCal ; // Cast from superclass to subclass. 
ZonedDateTime zdt = myGregCal.toZonedDateTime() ; // Convert from legacy class to modern class.

Extract the date-only value.

LocalDate ld = zdt.toLocalDate() ;  // Extract date-only object from date-time object.

Calculate elapsed time in days

long days = ChronoUnit.DAYS.between( ld , otherLd ) ;

Or represent the elapsed time as a Period.

Period p = Period.between( ld , otherLd ) ;

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?

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.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154