简体   繁体   中英

Java calculating past date from today is going into the future

I'm having an issue in Java calculating the current date minus a certain amount of days.

I have:

Date pastDate = new Date(new Date().getTime() - (1000 * 60 * 60 * 24 * 25));

This is returning Tue Feb 16 09:04:18 EST 2016 when it should actually return Tue Dec 28 16:06:11 EST 2015 (25 days into the past).

What's very strange is that for any number under 25 days works completely fine:

Date pastDate = new Date(new Date().getTime() - (1000 * 60 * 60 * 24 * 24));

As in 24 days into the past returns a predictable Tue Dec 29 16:06:11 EST 2015 .

Any help would be appreciated.

With 24 days, the product remains just below the maximum possible int value, Integer.MAX_VALUE , which is 2,147,483,647. The 24 days product is 2,073,600,000. The 25 days product is 2,160,000,000. The result is overflow and a negative number, resulting in a date in the future.

For such values, use a long literal for the first value (or cast it to a long ) to avoid the overflow that comes with exceeding Integer.MAX_VALUE . Note the L appended to 1000L :

(1000L * 60 * 60 * 24 * 25)

This works fine because the desired constructor for Date takes a long .

Date arithmetic is handled more cleanly by using Calendar s, where you can explicitly add a negative number of days.

Also, with Java 8+, you can use Instant and its minus method to subtract the time.

Instant.now().minus(24, ChronoUnit.DAYS);

Do not roll your own date-time calculations. Date-time work is a surprisingly tricky business. You have already run into the common int -versus- long error with calculation of milliseconds. Use a decent date-time library. Fortunately Java now comes with the industry's best such library.

java.time

As mentioned in the correct Answer by rgettman , you should be using the new java.time framework built into Java 8 and later. The old date-time classes bundled with the earliest versions of Java are notoriously troublesome.

Basics of java.time… An Instant is a moment on the timeline in UTC. Apply a time zone ( ZoneId ) to get a ZonedDateTime .

Time zone is crucial in determining dates, as the date is not the same around the world at any one moment. A new day dawns earlier in the east.

Instant instant = Instant.now(); // In UTC.
ZoneId zoneId = ZoneId.of( "Asia/Kolkata" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
ZonedDateTime zdtTwentyFiveDaysAgo = zdt.minusDays( 25 );

You may want the first moment of the day for that date-time of 25 days ago rather then the current time-of-day. The first moment is not always 00:00:00.0 because of Daylight Saving Time (DST) and perhaps other anomalies. So let java.time determine the time-of-day. We have to go through LocalDate and then back to ZonedDateTime to get the first moment.

ZonedDateTime zdtTwentyFiveDaysAgoStart = zdtTwentyFiveDaysAgo.toLocalDate().atStartOfDay( zoneId );

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM