Sunday, July 20, 2014

Common Date-Time Operations In Java - Formatting and Parsing Date-Time

In Date and Time With Java, a general overview of date/time related API was given. This post walks through formatting and Parsing Date-Time in Java.


Parsing and Formatting Date and Time.


What is the difference between December, 04, 1984 and 12/04/1984, and 04/Dec/1984 and ... or difference between 13:00hr and 1PM and...

Formating. They all represent the same date and time but are formatted differently.

Formatting date/time values as string, and parsing date/time values expressed in string into objects, are one of the common tasks when dealing with date/time. 

Formatting allows you to take a Java object that represents date or time and convert it into a string represention using a predefined formatting.

Conversely, with parsing, you take date or time values expressed as strings and have it converted it into valid Java date or time objects.

We quickly go over how to accomplish these tasks:



Prior to Java 8:


Prior to Java 8 using java.text.Dateformat was one of the options available for formatting (date/time objects to strings) and parsing (strings to date/time objects).

The java.text.Dateformat is an abstract class, so you cannot instantiate it using new keyword. You get an instance of java.text.Dateformat using one of the various static factory methods it comes with.


Using java.text.Dateformat To Format Date to String:

import java.text.DateFormat;
import java.util.Date;


public class SimpleFormatExample {

public static void main(String[] args) {

Date now = new Date();
// get the default DateFormat
DateFormat formatter = DateFormat.getInstance();
// Format Date object to String
String dateAsString = formatter.format(now)
// print formatted string
System.out.println(dateAsString);

}

}

Running the above code prints:

7/19/14 7:28 PM

Here we are using DateFormat.getInstance() to get a formatter that formats the java.util.Date object into a string with the pattern: "month/date/last two digits of the year/ hour:minutes PM/AM" 

This pattern is the default when you use DateFormat.getInstance(). You can use the other provided formating options that comes with java.text.Dateformat to specify further the formating desired.

import java.text.DateFormat;

import java.util.Date;
public class SimpleFormatExample {
public static void main(String[] args) {
Date now = new Date();
// Using DateFormat.SHORT with DateFormat.getTimeInstance()
DateFormat shortTimeFormatter = 
DateFormat.getTimeInstance(DateFormat.SHORT);

System.out.println(shortTimeFormatter.format(now));
// Using DateFormat.LONG and DateFormat.LONG 
//with DateFormat.getDateTimeInstance();
DateFormat dateTimeFormatter = 
DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);

System.out.println(dateTimeFormatter.format(now));
}

}

Running the above code gives:

7:36 PM
July 19, 2014 7:36:57 PM CEST

As you would notice, in the first example DateFormat.getInstance()was used to get the default formater, but in this example we used DateFormat.getTimeInstance() which formats only time and DateFormat.getDateTimeInstance() which formats both date and time.

There are more formating constants available. You can check the Oracle Java tutorial for more example and options.

Using java.text.Dateformat to Parse String to Date:

Apart from the format() method, the java.text.Dateformat has the parse() method that parses strings that are in line with the format that was used to instantiate the java.text.Dateformat object into a Date object.

For example taking the formatted strings in the formating examples above and parsing them back to Date:


import java.text.DateFormat;
import java.util.Date;

public class SimpleFormatExample {

public static void main(String[] args) {

try {// Parsing date string in the default format

DateFormat defaultFormatter = DateFormat.getInstance();
Date date1 = defaultFormatter.parse("7/19/14 7:28 PM");

// Parsing time in short format back to Date
DateFormat shortTimeFormatter = 
DateFormat.getTimeInstance(DateFormat.SHORT);

Date date2 = shortTimeFormatter.parse("7:36 PM");

// Parsing date/time in long format back to Date
DateFormat dateTimeFormatter = 
DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);
Date date3 = dateTimeFormatter.parse("July 19, 2014 7:36:57 PM CEST");
} catch (Exception e) {

}

}

}
With date2 since only the time is specified, the date value is by default set to the start of epoch time.


java.text.simpleDateFormat allows you to customize further the formating of a date expressed in String. This should be used for situations where the default formating options in java.text.Dateformat does not suffice.

For example to get a Date object and express it in the string format: "Sat Jul 19 20:01:09 CEST 2014" 

you do

import java.text.SimpleDateFormat;
import java.util.Date;

public class SimpleFormatExample {

public static void main(String[] args) {

SimpleDateFormat format = 
new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy");
System.out.println(format.format(new Date()));

}

}

The "EEE MMM dd HH:mm:ss zzz yyyy" is the formatting pattern.

java.text.simpleDateFormat comes with plethora of options that can be used for string date formating. You can check the Oracle Java tutorial on SimpleDateFormat for more usage example and options.

With Joda Time:

The key class at play when carrying out formatting and parsing operations with the Joda-time library is org.joda.time.format.DateTimeFormatter. It controls the printing and parsing of a datetime to and from a string.

You get a copy of the org.joda.time.format.DateTimeFormatter object via any of the following methods:


  • ISODateTimeFormat:
    The org.joda.time.format.ISODateTimeFormat class is a factory from which you can obtain copies of org.joda.time.format.Date2014-08-06T20:28:57.518+02:00TimeFormatter configured for some predefined formatting. See examples below.
  • DateTimeFormat:
    the org.joda.time.format.DateTimeFormat class is another factory, from which instances of org.joda.time.format.DateTimeFormatter can be obtained. Unlike ISODateTimeFormat, you provide the pattern and style. It does allows ability to format date/time object into string using formats that may not be available in ISODateTimeFormat
  • DateTimeFormatterBuilder 
    the org.joda.time.format.DateTimeFormatterBuilder class is another factory from which instances of org.joda.time.format.DateTimeFormatter can be obtained. It allows the constructing of the formatter via method calls. 
  • new DateTimeFormatter
    Even though it is actually possible to get an instance of org.joda.time.format.DateTimeFormatter by calling its constructor, using the factory methods is usually preferred.

Using ISODateTimeFormat to get DateTimeFormatter 

import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;
import org.joda.time.DateTime;

public class usingISODateTimeFormat {
public static void main(String[] args) {
DateTimeFormatter formatter = ISODateTimeFormat.basicDate();
System.out.println(formatter.print(DateTime.now()));
}

}

org.joda.time.format.ISODateTimeFormat can be used to format java.util.Date. (not just the joda related date-time objects, i.e org.joda.time.DateTime as above)

To do so the epoch time representation of java.util.Date needs to be used.

import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;
import org.joda.time.DateTime;

public class usingISODateTimeFormat {
public static void main(String[] args) {
DateTimeFormatter formatter = ISODateTimeFormat.basicDate();
System.out.println(formatter.print(new Date().getTime()));
}

}

The above example would print out

20140720

Which is date represented as a combination of year month and date. This is the formating obtained using basicDate(). Other predefined formats are available. See the method summary for the rest of available formatting options.

Using DateTimeFormat to get DateTimeFormatter

import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.DateTime;

public class usingDateTimeFormat {
public static void main(String[] args) {
DateTimeFormatter formatter = 
 DateTimeFormat.forPattern("dd/MM/yyyy HH:mm:ss");
System.out.println(formatter.print(DateTime.now()));
}
}

The above example would print out

20/07/2014 20:20:05

Which is clearly the pattern specified in forPattern() method.

Another method for providing the formating for org.joda.time.format.DateTimeFormat is to use the forStyle(). This uses a shorter pattern style.

The short pattern consist of just two characters. First character specifies Date Formating, second character for Time formating.

The character can be any two out of : a character of 'S' for short style, 'M' for medium, 'L' for long, 'F' for full and '-' for none

for example:
DateTimeFormatter formatter = DateTimeFormat.forStyle("LS");
System.out.println(formatter.print(DateTime.now()));

prints out July 20, 2014 8:27 PM (Date in Long format, Time in Short format)

while
DateTimeFormatter formatter = DateTimeFormat.forStyle("-L");
System.out.println(formatter.print(DateTime.now()));

prints out 8:28:29 PM CEST (no date and time in long format)

Using org.joda.time.format.DateTimeFormat to Parse String to Date:

Apart from the print() method, the org.joda.time.format.DateTimeFormatter has a couple of methods that can be used to parse from a string that is in line with the format that was used to instantiate the org.joda.time.format.DateTimeFormatter object into a Date object.

For example taking the formatted string: 20/07/2014 20:20:05 in the formating examples above and parse it back to Date:

DateTimeFormatter formatter = 
DateTimeFormat.forPattern("dd/MM/yyyy HH:mm:ss");

DateTime dateTime = 
formatter.parseDateTime("20/07/2014 20:42:13");

You can check the documentation for more of the available parse* methods.

With Java 8:

java.time.format.DateTimeFormatter

With Java 8, java.time.format.DateTimeFormatter (and java.time.format.DateTimeFormatterBuilder for more complex patterns) is the prefered way to specify the formatting pattern while the respective date-time object handles the formatting using the passed in java.time.format.DateTimeFormatter object.

The choice of having the formatting functionality as part of the Java 8 date/time objects makes for a simplier desgin.

You have a date/time object and you can format it by calling its format method and have the value it embodies formatted based on defined pattern from java.time.format.DateTimeFormatter

Using java.time.format.DateTimeFormatter With Formatting Date to String:

To format with Java 8, define the formatting pattern and then format the required date-time object using the pattern. For example:

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

public class formatExample {
       
public static void main(String[] args) {
//Format examples
LocalDateTime dateTime = LocalDateTime.now();

//using pattern
System.out.println(dateTime.format(DateTimeFormatter.ofPattern("d**MMM**uuuu")));
// Using one of the predefined patterns
System.out.println(dateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
 }
 
}

running this prints:

20**Jul**2014
2014-07-20T21:19:56.865

The first output is formatted using the given pattern: "d**MMM**uuuu" while the second output is formatted using one of the default patterns that comes with java.time.format.DateTimeFormatter

You can find more information and available predefined formats from the documentation

Using java.time.format.DateTimeFormatter With Parsing String to Date:

When parsing a formatted string to date-time object with Java 8's date-time API, the parsing method is made available as static parse() method of the respective date-time class. so for example. LocalDateTime.parse(...), LocalDate.parse(...) etc.

The parse() methods, just like the format() methods works with  java.time.format.DateTimeFormatter

So taking output 20**Jul**2014 from the previous example and parsing it back to LocalDateTime, we have:

LocalDateTime dateTime1 = LocalDateTime.parse("20**Jul**2014", DateTimeFormatter.ofPattern("d**MMM**uuuu"));

With all these explained, I guess seeing date and time expressed in a format like this: 2014-07-20T20:28:57.518 should not come across as confusing as it did for me when I initally encounterd it. (This format, by the way, is the default toString implementation you have for the org.joda.time.DateTime object).

It is just a Date-Time object expressed in a particular pattern: yyyy-MM-ddTHH:mm:ss.SSSZZ which happens to be the international standard for representation of date and time

No comments: