I’m working on a project in Java, and I wanted to do some simple processing of dates. I tried reading the Java tutorials and looking at questions and answers on Stack Overflow, but the solutions they offered were too complicated for what I was looking for, or were using classes that were old and not recommended to be used. I finally figured out a nice easy way to handle the processing, so I thought I’d document it here.
What I was trying to do
The dates I have are stored in Strings, in the format “YYYY-MM-DD”; for example, June 30, 2019 is stored as “2019-06-30”. This is a nice easy format to work with; I don’t need to concern myself with timezones or anything complicated, and it’s easy to sort and compare, because I can just do String comparisons with the compareTo() method.
Besides comparisons and sorting, I also want to do some other processing: getting the date the day before, the week before, and the week after. This isn’t so easy to do; I would need to write a bunch of code that knows how many days there are in the month, and handle the case of moving to previous months or years, and deal with leap years, etc., etc., etc. Yeah, I know it’s not that hard, but it would be easier to use some pre-existing, exhaustively tested code to do it!
Java’s LocalDate class is the solution
It turns out the best way to do this is to use Java’s LocalDate class, in the java.time package. A LocalDate object contains a date without a timezone, using the standard Gregorian calendar that we all know and love in Canada (and most of the world). If you really want to know more details about the calendar (you don’t need to to understand this blog post), you can read about the ISO 8601 calendar on Wikipedia.
Creating a LocalDate object
Creating a LocalDate object was really easy for me. Because I’ve already got the date stored in my program in a String in the format YYYY-MM-DD, I can just call the parse() method; I pass in the String, and it returns a LocalDate object:
LocalDate someDate = LocalDate.parse( "2019-06-30" );
There are other lots of other methods you can use to create LocalDate objects, but this was all I needed to do. Take a look at the API for other possible methods, like now() or of().
Converting back to a String
LocalDate provides a toString() method, which returns a String in the YYYY-MM-DD format:
String dateAsString = someDate.toString();
Of course, because Java will call toString() automatically when converting an object to a String, I can display the date with:
System.out.println( "The date is " + someDate );
LocalDate manipulation
If I want to get the day before the current date, I can use the minusDays() method:
LocalDate dayBefore = someDate.minusDays( 1 );
Note that LocalDate objects are immutable; once they’re set, you can’t change them, so the minusDays() method doesn’t change the original date, it returns a new LocalDate object with the new date. As a result, if I wanted to change the someDate variable, I’d have to do:
someDate = someDate.minusDays( 1 );
If I want to change by other units, there’s also minusWeeks(), minusMonths(), and minusYears(). You can also use the minus() methods for more complicated manipulation, but I didn’t need to bother with that. So anyways, here’s how I can get the date from the week before:
LocalDate weekBefore = someDate.minusWeeks( 1 );
Similarly, if I want to get the next day, I can use the plusDays() method:
LocalDate dayAfter = someDate.plusDays( 1 );
There are similar methods for plusWeeks(), plusMonths(), plusYears(), and plus().
Comparing LocalDates
LocalDate provides the standard comparison functions that we’re all used to: the equals() method checks if two dates are equal:
someDate.equals( dayBefore )
evaluates to false, and the compareTo() method compares two dates, returning an integer less than, equal to, or greater than zero:
someDate.compareTo( dayBefore )
evaluates to a value greater than 0.
For some reason, my brain has never been able to remember the order of compareTo(); does it compare the parameter to the object, or the object to the parameter? I always have to try it out in test code, and I inevitably get it the wrong way! But, with LocalDates, there’s some nice comparison methods I can use so I don’t have to think about it! If I want to see if a date is before, I can use the isBefore() method:
someDate.isBefore( dayBefore )
evaluates to false. I can wrap my head around that: I just read the code and it makes sense — “is someDate before dayBefore?”
There’s also an isAfter() method:
someDate.isAfter( dayBefore )
evaluates to true.
There’s also an isEqual() method; you can use that, or equals().
I wish there was an isOnOrAfter() or isOnOrBefore() method, but there’s not; I just have to use compareTo() for that.
Other methods
LocalDate provides lots and lots of other methods, but I didn’t need to use them. Take a look; if you’re wanting to do some simple date manipulation, there might be something there you want to use!
All the code
Here’s the program I used to test all the code in this post:
import java.time.LocalDate; public class SimpleDateExample { public static void main( String[] args ) { LocalDate someDate = LocalDate.parse( "2019-06-30" ); String dateAsString = someDate.toString(); System.out.println( "dateAsString = " + dateAsString ); System.out.println( "The date is " + someDate ); LocalDate dayBefore = someDate.minusDays( 1 ); System.out.println( "Day before: " + dayBefore ); // someDate = someDate.minusDays( 1 ); // System.out.println( "The date is " + someDate ); LocalDate weekBefore = someDate.minusWeeks( 1 ); System.out.println( "Week before: " + weekBefore ); LocalDate dayAfter = someDate.plusDays( 1 ); System.out.println( "Day after: " + dayAfter ); System.out.println( "Using equals: " + someDate.equals( dayBefore ) ); System.out.println( "Using compareTo with dayBefore: " + someDate.compareTo( dayBefore ) ); System.out.println( "Using compareTo with dayAfter: " + someDate.compareTo( dayAfter ) ); System.out.println( "Using isBefore: " + someDate.isBefore( dayBefore ) ); System.out.println( "Using isAfter: " + someDate.isAfter( dayBefore ) ); } }