7

I ran into a problem where I wanted to compare two dates. However, I only wanted to compare Year, Month and Day. And this is what I can up with:

 private Date trim(Date date) {

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.MILLISECOND, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.HOUR, 0);
        return calendar.getTime();
    }

I user this function to trim all units but days, months and years.

Now, the question is what do you think about it? Do you know any other way to do so?

Thanks

Ran Eldan
  • 1,350
  • 11
  • 25
Adelin
  • 18,144
  • 26
  • 115
  • 175
  • 2
    i really dont understand where the problem stands ?? – Hussain Akhtar Wahid 'Ghouri' Jul 05 '13 at 23:41
  • seems like clean code, any other code accessing the Date class would be larger most likely why would you change really lol. – SSpoke Jul 05 '13 at 23:45
  • 1
    Is the timezone of the user you're generating output for the same as the timzeone of the platform JVM is running on? :) – Affe Jul 05 '13 at 23:46
  • The non-accepted answers in the question I marked as a duplicate refer to other libraries and classes that you can use to more cleanly work with `Date`s, in addition to the accepted answer essentially having the same code as yours. – Robert Rouhani Jul 05 '13 at 23:47
  • I'd also name the function something else. Trim doesn't really say anything when used together with dates. Maybe something like `trimTimeOfDayInformation` could be a bit more explicit. – Andrei Bârsan Jul 05 '13 at 23:49
  • @AndreiBârsan, I think `toMidnightLocalTZ` would be a more appropriate method name (where `LocalTZ` refers to the local timezone). – SimonC Jul 06 '13 at 00:18
  • Thank you for all comments. There is no problem with the code. However, I thought there might be some cleaner or better way to do that :) – Adelin Jul 06 '13 at 19:36
  • FYI, the old date-time classes are now legacy, supplanted by the java.time classes. Look for the `truncatedTo` method on some of those java.time classes. – Basil Bourque Jan 06 '17 at 09:22

5 Answers5

8

Do you really need to use java.util.Date ? If you can switch to joda time, you'll find very nice features like:

dateTime.dayOfMonth().roundFloorCopy()

which does exactly what you need.

Costi Ciudatu
  • 37,042
  • 7
  • 56
  • 92
  • This is a kind of answers I was looking for, however my project is small and I don't need to add more dependencies :) – Adelin Jul 06 '13 at 19:39
  • Joda is sort of mainstream nowadays, so it's not like you should be worried about using some obscure library... No matter how small the project is, if you want to do any logging, you should use slf4j, if you're writing tests -- testng, and if you're concerned about date/time, you need Joda (or their alternatives, of course -- don't want to start a religious war here). – Costi Ciudatu Jul 06 '13 at 21:46
  • You are right may be in the future I will add Joda – Adelin Jul 06 '13 at 22:50
6

Your code works and is easy to read. I don't see any problem or reason for changing it.

4

Now, the question is what do you thing of doing this ?

It looks straightforward and reasonable. You are creating a new Date and a temporary Calendar object, but that's only a minor overhead. (... unless you are using this to sort / order a large data structure ...)

IMO, there's probably no need to change it.

Do you know any other way to do so ?

  1. Develop / use a Comparator<Date> that only uses the fields you are interested in, using a Calendar to extract them.

    Whether this will help depends on how you are currently doing the comparisons. A comparator may be neater. But the flip-side is that you may end up repeatedly doing the conversions, and Comparator<Date> doesn't give you any scope for caching the converted dates.

  2. Do the calculation using the values returned by Date.getTime(). Roughly like this:

    long val = date.getTime(); // milliseconds since 'epoch' in UTC 
    val = val + /* local timezone offset in milliseconds */  
    long day = val / (1000 * 60 * 60 * 24); // days since "local" epoch.
    
    // repeat for other Date, and compare the 'day' numbers as integers
    

    Explanation, it should be more efficient to do some simple arithmetic than use a Calendar (or whatever). The code is a bit more obscure, but it should be obvious to someone with reasonable maths skills.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • The second suggestion doesn't take into account any changes for daylight savings, or leap seconds. It would just tell you if the two dates were within 24 hours of each other, which you could much more simply by calculating the number of milliseconds in 24 hours. Unless, that's specifically what you want, then just use your existing code which is *much* more obvious to the reader as to it's intentions. – SimonC Jul 07 '13 at 03:06
  • @SimonC - the relevant "code" is actually a comment. Whether it takes account of daylight savings time (or not) depends on how you implement it. (But yes, this does complicate things.) I'm pretty sure that leap-seconds are irrelevant. They work by adjusting the UTC baseline time ... – Stephen C Jul 07 '13 at 05:42
  • @StephenC, the formula you have given does not give the number of calendar days since the epoch, it gives the number of 24 hour periods. You would need to know the number of hours of daylight savings that been added/removed in the local calendar since the epoch. From what I understand, leap seconds are inserted into the current day, so there are some calendar days with `24 * 60 * 60 + 1` seconds in them. That would further skew your calculation. Unless there's a *really* good reason not, time calculations should always be done by a library (that has been tested by many people). – SimonC Jul 07 '13 at 09:12
  • @SimonC - I don't understand your point about the calculation. The number of hours added and removed due to daylight saving will balance ... modulo a number that can be calculated from the current DST state and amount. You are incorrect about leap seconds. As I said, they are handled by adjusting the UTC baseline time. The actual time as reported by the time servers CHANGES ... and all of the synced clocks CHANGE when there is a leap second. This is ignored for normal calendrical purposes. – Stephen C Jul 07 '13 at 10:48
  • Look, I'm not saying that it is simple to take account of DST. But I'm saying that you can do it efficiently, and if you do it efficiently then that gives you the most efficient way to compare dates per the OP's requirement. – Stephen C Jul 07 '13 at 10:51
2

I assume you want to compare two dates where in you want to compare only the year, month and day.

What you have done is fine i.e. removing the hour, minute, second and millisecond. You will have to do this with both the dates.

Once the trimming is done you will have to use the compareTo method in the Date class.

You can use the following code -

if(date1.compareTo(date2) < 0) {
  // date1 is earlier
} else if(date1.compareTo(date2) > 0) {
  // date 2 is earlier
} else {
  // both dates are equal
}      
JHS
  • 7,761
  • 2
  • 29
  • 53
0

You can try this, because the formats of the dates stay fixed:

    String first = date1.toString().substring(4,10) + " " + date.toString().substring(24, 28);
    String second = date2.toString().substring(4,10) + " " + date.toString().substring(24, 28);

which will output

Dec 31 1969

Jan 06 1969

And then compare the results.

return (first.equals(second));

I don't know if it is any better than your idea, but you get the same result.

Community
  • 1
  • 1
Ran Eldan
  • 1,350
  • 11
  • 25
  • 1
    This only works if you want to compare the dates for equality. And it is really inefficient ... and NON-PORTABLE, because if depends on the default string formatting which is locale specific. – Stephen C Jul 06 '13 at 00:15
  • Thanks for the answer but, I wont be able to user if(date1.before(date2)) ... :) – Adelin Jul 06 '13 at 19:38