Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java: Easiest Way to Subtract Dates

I have created a class with two fields that need to be dates, start_date and date_passed. I have been researching the best way in java to have dates in a YYYY MM DD format that allows for easy date subtraction, and the ability to "make-up" a date, say in the future for example.

Example of what I'd like it to do...

library.circulate_book("Chemistry", **start date here**) //actual date or random date
library.pass_book("Chemistry", **Date Passed here**) //random date such as 5 days after start date
int days_had = Date_Passed - start_date

So far, I've found plenty of ways to format dates using Calendars and Date classes, but have yet to find one that looks like it would work considering most dates end up as Strings. Any suggestions/small examples are greatly appreciated! Also, any links to examples would be awesome!

like image 928
Bob Avatar asked Nov 04 '15 19:11

Bob


2 Answers

tl;dr

To move from one date to another by adding/subtracting a number of days.

LocalDate.now(
    ZoneId.of( "Pacific/Auckland" ) 
)
.minusDays( 5 )

To calculate the number of days, months, and years elapsed between two dates.

ChronoUnit.DAYS.between( start , stop )

Parsing

First you must parse your string inputs into date-time objects. Then you work on preforming your business logic with those objects.

Stop thinking of date-time values as strings, that will drive you nuts. We work with date-time objects in our code; we exchange data with users or other apps using a String representation of that date-time object.

In Java 8 and later, use the java.time framework. See Tutorial.

You want only a date, without time-of-day, so we can use the LocalDate class.

That funky double-colon syntax is a method reference, a way to say what method should be called by other code.

String input = "2015 01 02";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern ( "yyyy MM dd" );
LocalDate localDate = formatter.parse ( input , LocalDate :: from );

Current date

Determining today’s date requires a time zone. For any given moment, the date varies around the globe by zone.

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
LocalDate todayTunis = LocalDate.now( z ) ;

If you want the JVM’s current default time zone, call ZoneId.systemDefault.

Subtracting Dates

This has been addressed many times before on StackOveflow.com. For example, How to subtract X days from a date using Java calendar?. For details, see other Answers such as this one by me and this one by me for more details. Tip: "elapsed" is a key search word.

Use ChronoUnit.DAYS enum to calculate count of days elapsed.

LocalDate weekLater = localDate.plusDays ( 7 );
long daysElapsed = java.time.temporal.ChronoUnit.DAYS.between( todayTunis , weekLater ) ;

Dump to console.

System.out.println ( "localDate: " + localDate + " to " + weekLater + " in days: " + daysElapsed );

localDate: 2015-01-02 to 2015-01-09 in days: 7

like image 51
Basil Bourque Avatar answered Oct 16 '22 09:10

Basil Bourque


The best way to do this in Java-8 is not the flawed answer of Basil Bourque but this approach:

String startDate = "2016 01 02";
String passedDate = "2016 02 29";

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MM dd");
LocalDate date1 = LocalDate.parse(startDate, formatter);
LocalDate date2 = LocalDate.parse(passedDate, formatter);

long elapsedDays = ChronoUnit.DAYS.between(date1, date2);
System.out.println(elapsedDays); // 58 (correct)

The suggested use of java.time.Period.getDays() is dangerous and often wrong as soon as the elapsed duration exceeds one month. The whole Period is P1M27D so this code effectively only queries the partial amount of elapsed days (there is also an elapsed month):

System.out.println(Period.between(date1, date2).getDays()); // 27 (WRONG!!!)

A satisfying solution using the classes java.util.Date, GregorianCalendar etc. is hard to find. You can use the answer of Tacktheritrix but have to be aware of the fact that the calculated count of elapsed days might differ due to the sub-day-parts of java.util.Date and is also not reliable because of ignoring day-light-saving switches (where the clock jumps by one hour in many parts of the world).

Side note: At least 8 external libraries offer good answers to your problem, too. But I think, your simple use-case does not justify the embedding of an extra library unless you are not yet on Java-8. Any alternative solution how to count the elapsed days between two dates would not be easier than in Java-8 - only similar. And since you accepted the Java-8-related answer of Basil Bourque, I assume that you are indeed on Java-8 so I leave out the answer how to solve your problem with other libraries.

like image 31
Meno Hochschild Avatar answered Oct 16 '22 09:10

Meno Hochschild