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!
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.
Period.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.
Briefly, use a Period
to define a number of standard days, months, and years.
LocalDate weekLater = localDate.plusDays ( 7 );
Period period = Period.between ( localDate , weekLater );
Integer daysElapsed = period.getDays ();
Dump to console.
System.out.println ( "localDate: " + localDate + " to " + weekLater + " in days: " + daysElapsed );
localDate: 2015-01-02 to 2015-01-09 in days: 7
Note the limitation that Period
works only with whole days, that is, date-only values without time-of-day. That is what we need here for this Question, so job done. If you had date-time values (ZonedDateTime
objects), use the ThreeTen-Extra project’s Days
class as noted in linked Question/Answer above.
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.
use java 8 date api or joda, no need for new inventions.
you can find some examples here: http://examples.javacodegeeks.com/core-java/java-8-datetime-api-tutorial/
Here's an answer using Calendar
:
Calendar cal = Calendar.getInstance();
Calendar cal2 = Calendar.getInstance();
cal2.setTime(cal.getTime());
cal2.add(Calendar.DAY_OF_YEAR, 5);
System.out.println((cal2.getTimeInMillis() - cal.getTimeInMillis()) / (1000d * 60 * 60 * 24));
If you are stuck withan older java you can use SimpleDateFormat.
//For substraction
long differenceInMillis = date1.getTime() - date2.getTime();
//Date Format
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy MM dd");
String dateAsString = dateFormat.format(date1); //To get a text representation
Date dateParsed = dateFormat.parse(dateAsString); //To get it back as date