Java Date/Time Introduction
There are many Java classes available for date/time and it can becomes pretty confusing. This article try to give an overview of which classes or libraries for working with Date/Time in Java, and how you should use it. So, hopefully you doesn't need to look into the source codes to understand the salient features.
Prior to Java 8
If you using Java prior Java 8, you must be familiar with following classes:
Class | Description |
---|---|
java.util.Date | represents a specific instant in time, with millisecond precision. |
java.util.Calendar | is an abstract class that provides methods for converting between a specific instant in time and a set of calendar fields such as YEAR, MONTH, DAY_OF_MONTH, HOUR, and so on. Calendar also provides methods for manipulating the calendar fields, such as getting the date of the next week. An instant in time can be represented by a millisecond value that is an offset from the Epoch, January 1, 1970 00:00:00.000 GMT (Gregorian). |
java.util.GregorianCalendar | is a concrete subclass of Calendar and provides the standard calendar system used by most of the world. |
java.util.TimeZone | represents a time zone offset, and also figures out daylight savings. |
java.sql.Date | a class that extends java.util.Date, a thin wrapper around a millisecond value that allows JDBC to identify this as an SQL DATE value. A milliseconds value represents the number of milliseconds that have passed since January 1, 1970 00:00:00.000 GMT. |
java.sql.Time | a class that extends java.util.Date, a thin wrapper that allows the JDBC API to identify this as an SQL TIME value. The Time class adds formatting and parsing operations to support the JDBC escape syntax for time values. |
java.sql.Timestamp | a class that extends java.util.Date, a thin wrapper that allows the JDBC API to identify this as an SQL TIMESTAMP value. It adds the ability to hold the SQL TIMESTAMP fractional seconds value, by allowing the specification of fractional seconds to a precision of nanoseconds. A Timestamp also provides formatting and parsing operations to support the JDBC escape syntax for timestamp values. |
There is also System.currentTimeMillis(), a static method that returns the current date and time as milliseconds since January 1st 1970. We can use the returned long value to initialize classes like Date, Timestamp, etc. Let's check below brief example for Java Date/Time standard library features before Java 8:
import java.sql.Time;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;
public class DateTimePrior8Example {
public static void main(String[] args) throws ParseException {
long now = System.currentTimeMillis();
Date date = new Date(now);
System.out.println("java.util.Date: " + date);
java.sql.Date sqlDate = new java.sql.Date(now);
System.out.println("java.sql.Date: " + sqlDate);
Time sqlTime = new Time(now);
System.out.println("java.sql.Time: " + sqlTime);
Timestamp ts = new Timestamp(now);
System.out.println("java.sql.Timestamp: " + ts);
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(now);
System.out.println("java.util.Calendar: " + cal.getTime());
GregorianCalendar gCal = new GregorianCalendar();
gCal.setTimeInMillis(now);
System.out.println("java.util.GregorianCalendar: " + gCal.getTime());
String strDate = "2019-07-03 08:15:35";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
java.util.Date dt = sdf.parse(strDate);
System.out.println("Date in SGT: " + dt);
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
dt = sdf.parse(strDate);
System.out.println("Date in UTC: " + dt);
}
}
If above code executed, here the result:
java.util.Date: Wed Jul 03 01:29:29 SGT 2019 java.sql.Date: 2019-07-03 java.sql.Time: 01:29:29 java.sql.Timestamp: 2019-07-03 01:29:29.137 java.util.Calendar: Wed Jul 03 01:29:29 SGT 2019 java.util.GregorianCalendar: Wed Jul 03 01:29:29 SGT 2019 Date in SGT: Wed Jul 03 08:15:35 SGT 2019 Date in UTC: Wed Jul 03 16:15:35 SGT 2019
Joda-Time
The standard date and time classes prior to Java SE 8 are poor. To fill this gap, Joda-Time provides a quality replacement for the Java date and time classes, and even became the de-facto standard date and time library for Java prior to Java SE 8. Many projects, using Joda-Time libraries, instead of the standard Java date and time classes. If you working with Joda-Time, you must aware about following classes:
Class | Description |
---|---|
org.joda.time.Instant | is the standard implementation of a fully immutable instant in time. |
org.joda.time.DateTime | is the standard implementation of an unmodifiable datetime class. |
org.joda.time.DateTimeZone | is an abstract class that represents a time zone |
org.joda.time.LocalDate | is an immutable datetime class representing a date without a time zone. |
org.joda.time.LocalDateTime | is an unmodifiable datetime class representing a datetime without a time zone. |
org.joda.time.LocalTime | is an immutable time class representing a time without a time zone. |
Joda-Time also comes with some key features:
- org.joda.time.Duration: Specifying a length of time in milliseconds. In Duration, there is no concept of fields, such as days or seconds, as these fields can vary in length
- org.joda.time.Period: Specifying a set of duration field values. Unlike Duration, a time period is divided into a number of fields, such as hours and seconds.
- org.joda.time.Interval: Represents a period of time between two instants
A comprehensive and flexible formatter-parser:
- org.joda.time.format.DateTimeFormatter: Controls the printing and parsing of a datetime to and from a string.
You need to add Joda-Time dependency, as example if you are using maven:
<!-- https://mvnrepository.com/artifact/joda-time/joda-time -->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.10.2</version>
</dependency>
Following code will showcase Joda-Time library:
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.Duration;
import org.joda.time.Instant;
import org.joda.time.Interval;
import org.joda.time.LocalDate;
import org.joda.time.LocalDateTime;
import org.joda.time.LocalTime;
import org.joda.time.Period;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
public class DateTimeJodaTimeExample {
public static void main(String[] args) {
LocalDate localDate = LocalDate.now();
System.out.println("org.joda.time.LocalDate: " + localDate);
LocalTime localTime = LocalTime.now();
System.out.println("org.joda.time.LocalTime: " + localTime);
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println("org.joda.time.LocalDateTime: " + localDateTime);
Instant instant = new Instant();
System.out.println("org.joda.time.Instant: " + instant);
DateTime dateTime = instant.toDateTime();
System.out.println("org.joda.time.DateTime: " + dateTime);
long now = System.currentTimeMillis();
long plus24Hours = now + 24*24*60*1000; // in miliseconds
Duration duration = new Duration(now, plus24Hours);
System.out.println("org.joda.time.Duration: " + duration);
Instant instantPlus24Hours = instant.plus(duration);
System.out.println("Instant plus Duration: " + instantPlus24Hours);
Period period = new Period().withMonths(1);
System.out.println("org.joda.time.Period: " + period);
DateTime datePeriod = dateTime.plus(period);
System.out.println("Date plus Period: " + datePeriod);
Interval interval = new Interval(instant, instantPlus24Hours);
System.out.println("org.joda.time.Interval: " + interval);
DateTimeFormatter fmt = DateTimeFormat.forPattern("dd-MM-yyyy HH:mm:ss:SSSZZ ZZZ");
DateTime dt1 = new DateTime();
System.out.println(fmt.print(dt1));
DateTimeZone dtz2 = DateTimeZone.forID("UTC");
DateTime dt2 = dt1.withZone(dtz2);
System.out.println(fmt.print(dt2));
DateTimeZone dtz3 = DateTimeZone.forID("America/New_York");
DateTime dt3 = dt1.withZone(dtz3);
System.out.println(fmt.print(dt3));
}
}
Will resulting:
org.joda.time.LocalDate: 2019-07-04 org.joda.time.LocalTime: 05:26:47.263 org.joda.time.LocalDateTime: 2019-07-04T05:26:47.265 org.joda.time.Instant: 2019-07-03T21:26:47.266Z org.joda.time.DateTime: 2019-07-04T05:26:47.266+08:00 org.joda.time.Duration: PT34560S Instant plus Duration: 2019-07-04T07:02:47.266Z org.joda.time.Period: P1M Date plus Period: 2019-08-04T05:26:47.266+08:00 org.joda.time.Interval: 2019-07-03T21:26:47.266Z/2019-07-04T07:02:47.266Z 04-07-2019 05:26:47:314+08:00 Asia/Singapore 03-07-2019 21:26:47:314+00:00 UTC 03-07-2019 17:26:47:314-04:00 America/New_York
Note that Joda-Time is considered to be a largely “finished” project. No major enhancements are planned. If you are using Java SE 8 and above, please migrate or use java.time
(JSR-310).
Java 8 Date/Time API
In Java 8 a whole new set of date time API was added as an effort to revamp older date time API. This is done with the introduction of a whole new set of classes under located in the package java.time which is part of the standard Java 8 class library. Here some classes that mostly we use in Java 8 (and going forward) Date/Time API:
Class | Description |
---|---|
java.time.Instant | An instantaneous point on the time-line. |
java.time.LocalDate | A date without a time-zone in the ISO-8601 calendar system, such as 2007-12-03. |
java.time.LocalDateTime | A date-time without a time-zone in the ISO-8601 calendar system, such as 2007-12-03T10:15:30. |
java.time.LocalTime | A time without a time-zone in the ISO-8601 calendar system, such as 10:15:30. |
java.time.OffsetDateTime | A date-time with an offset from UTC/Greenwich in the ISO-8601 calendar system, such as 2007-12-03T10:15:30+01:00. |
java.time.OffsetTime | A time with an offset from UTC/Greenwich in the ISO-8601 calendar system, such as 10:15:30+01:00. |
java.time.ZonedDateTime | A date-time with a time-zone in the ISO-8601 calendar system, such as 2007-12-03T10:15:30+01:00 Europe/Paris. |
And some highlighted classes:
- java.time.Duration: A time-based amount of time, such as '34.5 seconds'.
- java.time.Period: A date-based amount of time in the ISO-8601 calendar system, such as '2 years, 3 months and 4 days'.
- java.time.format.DateTimeFormatter: Formatter for printing and parsing date-time objects.
Find similarity between Java 8 classes and Joda-Time? In fact JSR 310: Date and Time API is submitted by by the author of Joda-Time library (Stephen Colebourne) and led jointly by Michael Nascimento Santos and Roger Riggs (Oracle).
Without further ado, here code example for Java 8 Date/Time standard library:
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Period;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
public class DateTimeJava8Example {
public static void main(String[] args) {
LocalDate localDate = LocalDate.now();
System.out.println("java.time.LocalDate: " + localDate);
LocalTime localTime = LocalTime.now();
System.out.println("java.time.LocalTime: " + localTime);
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println("java.time.LocalDateTime: " + localDateTime);
Instant instant = Instant.now();
System.out.println("java.time.Instant: " + instant);
Instant instantPlus24Hours = instant.plusSeconds(24*24*60);
Duration duration = Duration.between(instant, instantPlus24Hours);
System.out.println("java.time.Duration: " + duration);
LocalDate nextMonth = localDate.plusMonths(1);
Period period = Period.between(localDate, nextMonth);
System.out.println("java.time.Period: " + period);
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm:ss:SSSZZ VV");
ZonedDateTime dtz1 = localDateTime.atZone(ZoneId.systemDefault());
System.out.println(fmt.format(dtz1));
ZonedDateTime dtz2 = dtz1.withZoneSameInstant(ZoneId.of("UTC"));
System.out.println(fmt.format(dtz2));
ZonedDateTime dtz3 = dtz1.withZoneSameInstant(ZoneId.of("America/New_York"));
System.out.println(fmt.format(dtz3));
}
}
with result:
java.time.LocalDate: 2019-07-04 java.time.LocalTime: 05:34:46.909 java.time.LocalDateTime: 2019-07-04T05:34:46.909 java.time.Instant: 2019-07-03T21:34:46.909Z java.time.Duration: PT9H36M java.time.Period: P1M 04-07-2019 05:34:46:909+0800 Asia/Singapore 03-07-2019 21:34:46:909+0000 UTC 03-07-2019 17:34:46:909-0400 America/New_York
Conclusion
If you working with Java version prior of Java 8, and you feel that the standard library are limited, you can use Joda-Time library as complement or alternative library. But if you already use Java 8 and above, use Date/Time standard library that comes in package java.time.