How to format/parse dates with LocalDateTime in Java 8 - Example Tutorial

One of the common tasks in Java project is formatting or parsing date to String and vice-versa. Parsing date means you have a String which represents a date e.g. "2017-08-3" and you want to convert it into an object which represents the date in Java e.g. java.util.Date in pre-Java 8 world and LocalDate or LocalDatetime in Java 8 world. Similarly, formatting a date means converting a date instance into String, for example, you have a Date object or LocalDatetime object and you want a String in dd-MM-yyyy format. Java 8 API provides a good support for formatting and parsing dates. For example, if you have a date as String e.g. "2017-08-3 12:30" and you want to convert it to a LocalDateTime instance, which is a new class from JDK 8 Date and Time API and contains both date and time part, how do you do that? Well, you can use the format() and parse() method from LocalDateTime class to achieve that, but you need one more thing, a date format.

Prior to Java 8, you might be aware that we use SimpleDateFormat and DateFormat class to represent a format, which has lots of problem e.g. they were heavy, mutable, and not thread-safe, which means you cannot share them and every time you need to convert String to Date, you have to create a new DateFormat object. Though encapsulating SimpleDateFormat into a thread-local variable does offer some respite, it wasn't enough.

JDK 8 has addressed this problem in the new DateTimeFormatter class, which can be used to define date and time format e.g. "yyyy-MM-dd HH: mm", the syntax to specify the format is same as what we use earlier with SimpleDateFormat class, but this class is both thread-safe and immutable which means you can share its instance between threads. Ideally, you can store the reference of DateTimeFormatter into a static variable to make it global.

Another advantage of using DateTimeFormatter is that it offers several built-in formatter e.g. java.time.format.DateTimeFormatter.ISO_LOCAL_DATE_TIME, which can represent a date as "2017-08-03T10:15:30". You can see a full list of built-in formatter in Javadoc or you can read Java SE 8 for Really Impatient to find out more about that.

Once you got your formatter, parsing or formatting date is as easy as calling a method. You just need to call the LocalDateTime.parse() method to convert a String to LocalDateTime in Java 8. The parse() takes a String and parse into LocalDateTime instance based upon format specified by DateTimeFormatter. The parse() method is also overloaded and by default it uses ISO_LOCAL_DATE_TIME format which is "yyyy-MM-dd HH:mm" i.e. "2017-08-03T10:15:30", but if your String is in a different format then you can specify a separate formatter.

So, enough theory, let's begin the real work...



How to format dates with LocalDateTime

Let's assume you are loading date as String from a database or a file which are in ISO format e.g. "yyyy-MM-dd HH:mm" and you want to convert them to java.time.LocalDateTime. Here are the exact steps to parse a date String to LocalDateTime in Java 8:

1) Create a DateTimeFormatter object
2) Use LocalDateTime.parse(string, formatter) method to convert String to LocalDatetime object

Btw, in our case dates are ISO format, you don't need to create a separate formatter and you can directly call the parse method, as shown in the following example:

String date = "2017-03-08T12:30:54";
LocalDateTime localdatetime = LocalDateTime.parse(date);

System.out.println("origional date as string: " + date);
System.out.println("generated LocalDateTime: " + localdatetime);

Output
origional date as string: 2017-03-08T12:30:54
generated LocalDateTime: 2017-03-08T12:30:54

Btw, if your date string is not in ISO format expected by parse method e.g. there is no T or missing minute of second part then it will throw DateTimeParseException. For example, if you want to parse "2017-08-3 12:30" or "2017-03-08 12:30:54", then it will throw following exception:

Exception in thread "main" java.time.format.DateTimeParseException: Text '2017-03-08T12:30:54' could not be parsed at index 10 at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1949) at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1851) at java.time.LocalDateTime.parse(LocalDateTime.java:492) at Demo.main(Demo.java:22)


To avoid this error, you can create a DateTimeFormatter instance which matches your date String. For example, if your dates are similar to "2017-08-3 12:30" then you can create a DateTimeFormatter as shown below:

DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");

After this, you can use this formatter instance to parse String to LocalDateTime as shown in the following example:

String date = "2017-03-08 12:30:54";
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
LocalDateTime dateTime = LocalDateTime.parse(date, format);

System.out.println("origional date as string: " + date);
System.out.println("generated LocalDateTime: " + dateTime);

Output:
origional date as string: 2017-03-08 12:30
generated LocalDateTime: 2017-03-08T12:30

You can see there is no more exception, but you must ensure that date as String must match with the pattern you define in your DateTimeFormatter instance. Since it is also thread-safe and immutable, you can even store this in a static variable and share among another part of your program. You can read more about thread-safety and immutability in new date and time API on Java SE 8 for the Really Impatient book.

How to format/parse dates with LocalDateTime in Java


How to format dates with LocalDateTime

In the last section, you have learned how to parse a date e.g. convert a String representation of a date into the corresponding object i.e. LocalDateTime in Java 8. Now, let's do the opposite, create a formatted string from an existing LocalDateTime object e.g. a date in "dd-MM-yyyy" format.

Again we need a DateTimeFormatter instance which holds our date pattern and then we can use the format() method of the LocalDateTime class to achieve this. Though, you should remember that format() is a non-static method and you need an instance of LocalDateTime class to call this method. Here is an example to format dates with LocalDatetime in Java 8:

DateTimeFormatter aFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm");
LocalDateTime localDateTime = LocalDateTime.of(2017, Month.AUGUST, 3, 12, 30);
String foramttedString = localDateTime.format(aFormatter); // "2017-03-08 12:30"

System.out.println("origional LocalDatetime object: " + localDateTime);
System.out.println("generated string : " + foramttedString);

Output:
origional LocalDatetime object: 2017-08-03T12:30
generated string : 03-08-2017 12:30

You should notice that we are calling the format method on an object and not with a class because it's a non-static method which is just opposite of parse(), which is a static method. You can also see that generated String confirms your pattern i.e. "03-08-2017 12:30" is in "dd-MM-yyyy HH:mm" format.



Java Program to format/parse Date with LocalDateTime in JDK 8

This is our sample Java program which encapsulates examples of both parsing and formatting dates with LocalDateTime in Java 8.

import java.time.LocalDateTime;
import java.time.Month;
import java.time.format.DateTimeFormatter;

/*
* Java Program to parse to LocalDateTime in JDK 8. 
* We'll convert a String "2017-03-08 12:30" into LocalDateTime.
* we'll also see how to format a LocalDateTime instance to String format. 
*/
public class Demo {

public static void main(String[] args) throws Exception {

// parsing a string date to LocalDateTime
String date = "2017-03-08 12:30";
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
LocalDateTime dateTime = LocalDateTime.parse(date, format);

System.out.println("origional date as string: " + date);
System.out.println("generated LocalDateTime: " + dateTime);


//formatting a LocalDateTime to string instance
DateTimeFormatter aFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
LocalDateTime localDateTime = LocalDateTime.of(2017, Month.AUGUST, 3, 12, 30);
String foramttedString = localDateTime.format(aFormatter); // "2017-03-08 12:30"

System.out.println("origional LocalDatetime object: " + localDateTime);
System.out.println("generated string : " + foramttedString);

// be careful, string must contain date and time portion
// if you are converting to LocalDateTime, or else, your
// code will break

LocalDateTime dateWithoutTime = LocalDateTime.parse("2017-08-03", format);
}

}

Output
origional date as string: 2017-03-08 12:30
generated LocalDateTime: 2017-03-08T12:30
origional LocalDatetime object: 2017-08-03T12:30
generated string : 2017-08-03 12:30
Exception in thread "main" java.time.format.DateTimeParseException: 
Text '2017-08-03' could not be parsed at index 10
at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1949)
at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1851)
at java.time.LocalDateTime.parse(LocalDateTime.java:492)
at Demo.main(Demo.java:35)


Important points

1) The LocalDateTime.parse() method is used for parsing and it's a static method but format() method is not static and it needs a LocalDateTime instance to call upon. That's the important difference to notice between parse() and format() method. For example LocalDateTime.format(DateTimeFromatter) is illegal in Java and give compile time error.

2) You must make sure that your String confirms to the format you are using for both parsing and formatting if it doesn't then both parse() and format() method will throw DateTimeParseException e.g. "Exception in thread "main" java.time.format.DateTimeParseException: Text '2017-08-03' could not be parsed at index 10".

3) There are several built-in formats available in Java 8, our same should be to leverage if it severs the purpose instead of creating a new one.

4) Since DateTimeFormatter is both immutable and thread-safe, it's recommended to store it in a static variable and share among whoever wants to use but make sure that the variable is both static and final so that thread can read it but cannot assign a new reference or null to it, which can cause subtle issues. See my post about dangers of using a static variable in multi-threading environment for more details.

Here is the summary of code to format or parse date to LocalDateTime in Java 8:

How to format/parse dates with LocalDateTime in Java 8 - Example Tutorial


That's all about how to format and parse dates with LocalDateTime in Java 8. As I said, each of the new class e.g. LocalDate, LocalTime, and LocalDateTime has a parse and format method which can be used to convert a string to date and vice-versa. Just remember that you need a DateTimeFormatter, whose pattern must match with your date String, if it doesn't then both parse() method will throw java.time.format.DateTimeParseException error.

You should also remember the difference between parse() and format() method, former is static while later is non-static. Another thing you can keep in mind is to reuse DateTimeFormatter instance either in form of static variable or leveraging several built-in formatter available in JDK. You can further read Java SE 8 for Really Impatient to learn more about new features of Java 8, including new Date and Time API.


Other Java 8 Date and Time tutorial you may like to explore:
How to compare two dates in Java? (tutorial)
How to get current Timestamp value in Java? (tutorial)
How to convert String to LocalDateTime in Java 8? (example)
How to convert java.util.Date to java.sql.Timestamp in JDBC? (tutorial)
How to convert Date to LocalDateTime in Java 8? (tutorial)
How to get current date and time in Java 6? (tutorial)
How to parse String to Date using JodaTime library? (example)
How to convert java.util.Date to java.sql.Date in JDBC? (tutorial)
How to convert String to LocalDateTime in Java 8 (tutorial)

Further Learning
What's New in Java 8
From Collections to Streams in Java 8 Using Lambda Expressions

Thanks for reading this article so far. If you like this Java 8 date and time tutorial and my tips then please share with your friends and colleagues. If you have any question or feedback then please drop a comment.

2 comments :

Anonymous said...

I'm getting an exception for this:
String date = "2017-03-08 12:30:54";
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
LocalDateTime dateTime = LocalDateTime.parse(date, format);
Exception:
Exception in thread "main" java.time.format.DateTimeParseException: Text '2017-03-08 12:30:54' could not be parsed, unparsed text found at index 16
Looks like pattern and date should exactly match:
- "2017-03-08 12:30:54" for "yyyy-MM-dd HH:mm:ss"
- "2017-03-08 12:30" for "yyyy-MM-dd HH:mm"
BTW:
java.text.SimpleDateFormat works for this case.

Javin Paul said...

@Anonymous, yes, pattern must match exactly with the date, otherwise you will receive, java.time.format.DateTimeParseException. Btw, thanks for sharing your input about SimpleDateFormat, didn't know that it handle this case :-)

Post a Comment