Friday, December 7, 2012

Joda-Time Tutorial

Introduction

Joda-Time is a quality implementation of the date/time library for Java. It is intended to be a replacement for out-of-the-box JDK Date and Calendar classes. The design of Joda-Time allows for multiple calendar systems while still providing a simple API. By the time of this writing eight calendar systems were supported by the library including the following ones: Gregorian, Julian, Buddhist, Ethiopic, Coptic, and Islamic. Supporting classes include time zone, duration, format and parsing.

Why Joda-Time?

Joda-Time has been carefully designed to overcome all the issues the standard JDK date/time classes are blamed for. It is under active development since 2002 and has the mature and reliable code base. There are lots of reasons to use Joda-Time, in particular:
  • It is easy to use. The standard JDK Calendar makes accessing “normal” dates difficult due to the lack of simple methods. Joda-Time has straightforward field accessors such as getYear() or getDayOfWeek().
  • It is easy to extend. The JDK supports multiple calendar systems via subclasses of Calendar. This is clunky, and in practice it is very difficult to write another calendar system. Joda-Time supports multiple calendar systems via a pluggable system based on the Chronology class.
  • It comprises comprehensive feature set. The library is intended to provide all the functionality that is required for date/time calculations. It already provides out-of-the-box features, such as support for oddball date formats, which are difficult to replicate with the JDK.
  • It incorporates up-to-date time zone calculations. The time zone implementation is based on the public tz database, which is updated several times a year. New Joda-Time releases incorporate all the changes made to this database. Should the changes be needed earlier, manually updating the zone data is easy.
  • It performs better than standard JDK date/time classes. The standard JDK Calendar has strange performance characteristics as it recalculates fields at unexpected moments. Joda-Time does only the minimal calculation for the field that is being accessed.
  • It is free and open source. The last but not the least. Joda-Time is free and licensed under the business friendly Apache License Version 2.0.

Core Concepts

The major building blocks of Joda-Time are the concepts of instant, partial, interval, duration, period, chronology and time zone. They are briefly described in the following sections. For more detailed information regarding each concept you are encouraged to visit the corresponding official documentation page.

Instants

Instant is the most frequently used concept in Joda-Time. An Instant is defined as a moment in the datetime continuum specified as a number of milliseconds from 1970-01-01T00:00Z. This definition of milliseconds is consistent with that of the JDK in Date or Calendar making interoperating between the two APIs simple and straightforward. An instant is represented by the ReadableInstant interface within Joda-Time. Currently there are four implementations of the interface:
  • Instant – A simple immutable implementation which is restricted to the UTC time zone and is intended for time zone and calendar neutral data transfer.
  • DateTime – The most commonly used class in the library, and an immutable representation of a date and time with calendar and time zone.
  • DateMidnight – Similar to DateTime and also immutable but with the time component forced to be midnight (at the start of a day).
  • MutableDateTime – A mutable representation of date and time with calendar and time zone.
For general usage immutable implementations are recommended. To get more information about instants please visit Official User Guide and Instant Key Concept pages.

Partials

A partial as its name implies is a partial date and time representation. All implementations represent local dates and times, and do not reference a time zone. Hence they only partially represent a date or time in the datetime continuum. It is not possible to directly interoperate between a partial and instant because a partial does not fully specify a single point in the datetime continuum, but instead may match multiple points. A partial is represented by the ReadablePartial interface within Joda-Time. Currently there are six implementations of the interface:
  • LocalDate – an immutable implementation that represents a date without a time or time zone.
  • LocalTime – an immutable implementation that represents a time without a date or time zone.
  • LocalDateTime – an immutable implementation that represents date and time without a time zone.
  • YearMonth – an immutable implementation that represents a year and month (it can be useful for credit card expiry dates).
  • MonthDay – an immutable implementation that represents a month and day (it can be useful for birthdays without years).
  • Partial – An immutable implementation that can store any combination of date and time fields (for example, using this class you could create a YearMonth or DayOfWeekDayOfMonth partial).
A partial can be converted to a full instant by specifying the missing values. At least time zone is required. It may be necessary to specify other missing fields. For example, conversion from a LocalDate to a DateTime requires filling in the time fields and the time zone. In terms of date/time math it means the following:

Partial + Missing Fields + Time Zone = Instant

For more information about partials please visit Partial Key Concept page.

Intervals

An interval in Joda-Time represents an interval of time from one instant to another instant. They are both fully specified instants in the datetime continuum (i.e. each instant is set up with a time zone). Intervals are implemented as half-open, which means the start instant is included in the interval but the end one is excluded. The end is always greater than or equal to the start. Both end-points are restricted to having the same chronology and the same time zone. An interval is represented by the ReadableInterval interface. Currently there are two implementations of the interface:
As usual, immutable implementation is recommended for general usage. To get more information about intervals please visit Official User Guide and Interval Key Concept pages.

Durations

Duration in Joda-Time represents duration of time measured in milliseconds. The duration is often obtained from an interval. Durations are a very simple concept, and the implementation is also simple. They have no chronology or time zone, and consist solely of the millisecond duration. Duration is represented by the ReadableDuration interface and currently there is only one implementation of the ReadableDuration interface: Duration. Durations can be added to an instant, or to either end of an interval to change those objects. In date/time math it means the following:

Instant + Duration = Instant

For more information about durations please visit Official User Guide and Duration Key Concept pages.

Periods

A period in Joda-Time represents a period of time defined in terms of fields, for example, 5 years 2 months 4 days and 7 hours. This differs from duration in that it is inexact in terms of milliseconds. A period can only be resolved to an exact number of milliseconds by specifying the instant (including chronology and time zone) it is relative to.

For example, consider a period of a month. If you add this period to the 1st of February (ISO) then you will get the 1st of March. If you add the same period to the 1st of March you will get the 1st of April. But the duration added (in milliseconds) in these two cases is very different.

As a second example, consider adding 1 day at the daylight savings boundary. If you use a period to do the addition then either 23 or 25 hours will be added as appropriate. If you had created duration equal to 24 hours, then you would end up with the wrong result.

Period is represented by the ReadablePeriod interface. The implementations of the period concept can be divided into two groups. The first one contains implementations which can store a single field only, such as days or hours, but not both. The second group is comprised of implementations which can store multiple fields and hence can express values like 5 months 3 days and 11 hours.

The first group contains seven implementations:
  • Years – an immutable years-only implementation.
  • Months – an immutable months-only implementation.
  • Weeks – an immutable weeks-only implementation.
  • Days – an immutable days-only implementation.
  • Hours – an immutable hours-only implementation.
  • Minutes – an immutable minutes-only implementation.
  • Seconds – an immutable seconds-only implementation.
The second group contains two implementations:
Periods are not associated with either a chronology or a time zone. Periods can be added to an instant, or to either end of an interval to change those objects. In date/time math it means the following:

Instant + Period = Instant

For more information about periods please visit Official User Guide and Period Key Concept pages.

Chronology

A chronology in Joda-Time is a pluggable calendar system. The JDK supports multiple calendar systems via subclasses of Calendar. This is clunky, and in practice it is very difficult to write another calendar system. Joda-Time supports multiple calendar systems by designing a pluggable system.

The default chronology in Joda-Time is ISO. This calendar system is the same as that used by business in the majority of the world today. The ISO system is unsuitable for historical work before 1583 as it applies the leap year rules from today back in time (it is a proleptic calendar). As a result, users requiring a more historically accurate calendar system are forced to think about their actual requirements.

Internally, all the chronology, field and time zone classes are maintained as singletons. Thus there is an initial setup cost when using Joda-Time, but after that only the main API instance classes (DateTime, Interval, Period, etc.) have creation and garbage collector costs.

The Chronology class is the key to the Joda-Time design, but it is not the key to using the API however. For most applications, the Chronology can be ignored as it will default to the ISOChronology.

For more information about chronologies please visit Official User Guide and Chronology Key Concept pages.

Time Zones

The chronology class also supports the time zone functionality. This is applied to the underlying chronology via the decorator design pattern. The DateTimeZone class provides access to the zones primarily through one factory method, as follows:
DateTimeZone zone = DateTimeZone.forID("Europe/London");
In addition to named time zones, Joda-Time also supports fixed time zones. The simplest of these is UTC, which is defined as a constant:
DateTimeZone zoneUTC = DateTimeZone.UTC;
Joda-Time provides a default time zone which is used in many operations when a time zone is not specified. This is similar in concept to the default time zone of the java.util.TimeZone class. The value can be accessed and updated via static methods:
DateTimeZone defaultZone = DateTimeZone.getDefault();
DateTimeZone.setDefault(myZone);
For more information about time zones and tz database (aka Olson database) please visit Official User Guide and Time Zone Update pages.

Examples

Ok, that’s enough for the theory. Now let’s look at several examples of Joda-Time usage. At the time of this writing the most recent version of the library was 2.1. All the examples are based on that version.

Example 1

Enterprise applications almost always should store the date and time for some of its entities: date of user registration, date of the last user login, dates of payments, etc. Later that information might be displayed in the UI. Having users of the application residing in different time zones is more a rule than an exception. Hence it is important to display the date values in a time zone relevant for a certain user. A commonly used approach is to store the values in the UTC and convert them to the relevant time zone when preparing data for the UI. This example demonstrates how easily it can be implemented using Joda-Time.

The following code snippet shows how to convert the date from UTC time zone to another one:
DateTimeZone localTimeZone = DateTimeZone.forID("Europe/Kiev");

DateTime utcTime = new DateTime(2012, 11, 29, 11, 40,
        DateTimeZone.UTC);
DateTime localTime = utcTime.withZone(localTimeZone);
        
System.out.println(utcTime);
System.out.println(localTime);
This program will print the following (the output is in the ISO 8601 format):

2012-11-29T11:40:00.000Z
2012-11-29T13:40:00.000+02:00

To save the modifications which could be done via UI the reverse conversion is necessary:
DateTimeZone localTimeZone = DateTimeZone.forID("Europe/Kiev");

DateTime localTime = new DateTime(2012, 11, 29, 13, 40,
        localTimeZone);
DateTime utcTime = localTime.withZone(DateTimeZone.UTC);

System.out.println(localTime);
System.out.println(utcTime);
This program will print the following (the output is in the ISO 8601 format):

2012-11-29T13:40:00.000+02:00
2012-11-29T11:40:00.000Z

As you can see, Joda-Time greatly facilitates the common task of date conversion from UTC time zone to the local one and vice versa.

Example 2

The ISO 8601 standard contains a lot of different formats. The one used by default in Joda-Time contains the most complete date/time information but it is not readable enough. A user can easily make a mistake trying to decipher it. That’s why Joda-Time provides rich set of facilities to format the output. This example shows how to use them.

The Joda-Time library contains implementations of all ISO 8601 standard formats. They reside in the ISODateTimeFormat class. The formatters it provides should be enough for the vast majority of use-cases. So before trying any other means of date formatting you are strongly encouraged to explore the facilities of the aforementioned class. The following code snippet demonstrates a couple of them. For a full list of available formatters please consider ISODateTimeFormat javadoc.
DateTime dateTime = new DateTime(2012, 12, 1, 11, 30,
        DateTimeZone.UTC);

System.out.println(ISODateTimeFormat.yearMonthDay().print(dateTime));
System.out.println(ISODateTimeFormat.hourMinuteSecond()
        .print(dateTime));
System.out.println(ISODateTimeFormat.dateHourMinuteSecond()
        .print(dateTime));
The program will print the following output:

2012-12-01
11:30:00
2012-12-01T11:30:00

If the facilities provided by ISODateTimeFormat class don’t suit you well, you can create a custom formatter. In case the required format can be described in terms of a format pattern you can use DateTimeFormat#forPattern factory method. The pattern string is compatible with JDK date patterns. If you need to use a particular locale you can leverage formatter’s withLocale method which returns another formatter based on the original. The example code snippet follows.
DateTime dateTime = new DateTime(2012, 12, 1, 12, 15,
        DateTimeZone.UTC);

DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyy/MMM/dd");
DateTimeFormatter frenchFmt = fmt.withLocale(Locale.FRENCH);
DateTimeFormatter germanFmt = fmt.withLocale(Locale.GERMAN);
The program will print the following output:

2012/Dec/01
2012/déc./01
2012/Dez/01

If you need a really exotic date format you can easily create it with Joda-Time. The library contains DateTimeFormatterBuilder class which allows you to build a formatter programmatically. To unleash the full power of DateTimeFormatterBuilder please consider its javadoc. The following code snippet shows just the top of the iceberg:
DateTime dateTime = new DateTime(2012, 12, 1, 12, 15,
        DateTimeZone.UTC);

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
        .appendDayOfWeekShortText()
        .appendLiteral(", ")
        .appendDayOfMonth(2)
        .appendLiteral('-')
        .appendMonthOfYearShortText()
        .appendLiteral('-')
        .appendYear(4, 4)
        .appendLiteral(", ")
        .appendEraText()
        .toFormatter();

System.out.println(formatter.print(dateTime));
The program will print the following output:

Sat, 01-Dec-2012, AD

The last but not the least: formatters can also be used to parse date from string. In other words every formatter is able to perform date to string conversion and vice versa. The expected format for string to date conversion is the same the formatter has been initially configured with. The following code snippet parses a string in a custom format and then prints it using one of the default formatters:
String strDateTime = "01.12.2012";
DateTimeFormatter formatter = DateTimeFormat
        .forPattern("dd.MM.yyyy");
DateTime dateTime = formatter.parseDateTime(strDateTime);

System.out.println(strDateTime);
System.out.println(ISODateTimeFormat.yearMonthDay()
        .print(dateTime));
The program will print the following output:

01.12.2012
2012-12-01

Example 3

From time to time you can be faced with a task which requires you to consider only date component of a certain event effectively ignoring its time. For example assume you want to build a SQL query which would return all the purchases which were shipped between 5th and 7th of November of 2012. If you work with JDK standard Date and Calendar classes then you manually have to set the time component to 00:00. Joda-Time provides much easier way to implement such tasks: DateMidnight class. It is effectively the same as DateTime class, but, as its name implies, it has the time component set to 00:00. Thus assuming you have parameterized your SQL query with half-open date interval (start date included, end date excluded) and all dates are stored on the server in UTC time zone you can use the following code to build date parameters for the query:
DateMidnight startDate = new DateMidnight(2012, 11, 5,
        DateTimeZone.UTC);
DateMidnight endDate = new DateMidnight(2012, 11, 8,
        DateTimeZone.UTC);
If you are working with JPA or directly with some ORM framework to query the database then you probably will have to give it instances of the standard JDK java.util.Date class. You can easily convert DateMidnight objects to java.util.Date instances:
java.util.Date startDate = new DateMidnight(
        2012, 11, 5, DateTimeZone.UTC).toDate();

java.util.Date endDate = new DateMidnight(
        2012, 11, 8, DateTimeZone.UTC).toDate();
If you prefer to use pure JDBC then you probably will have to give it instances of java.sql.Date class. Fortunately this is also easy to do:
java.sql.Date startDate = new java.sql.Date(
        new DateMidnight(2012, 11, 5, DateTimeZone.UTC).getMillis());

java.sql.Date endDate = new java.sql.Date(
        new DateMidnight(2012, 11, 8, DateTimeZone.UTC).getMillis());

Example 4

The Joda-Time library provides very powerful facilities for date/time arithmetic. For example assume you have the current time instant (now) and you want to know what date will be the first Wednesday of the next year. I don’t want even try to do this with standard JDK classes, but with Joda-Time it is as easy as the following (UTC time zone assumed):
DateTime newYear = new DateTime(DateTimeZone.UTC).dayOfYear()
        .withMaximumValue().plusDays(1);

DateTime firstWednesday = newYear.plusDays(
        DateTimeConstants.WEDNESDAY - newYear.getDayOfWeek());

System.out.println(ISODateTimeFormat.dateHourMinuteSecond()
        .print(firstWednesday)); 
At the time of this writing the program printed the following output:

2013-01-02T15:01:13

As you can see, the first Wednesday of 2013 is the 2nd of January.

Example 5

Sometimes it can be useful to store date/time information independently of a certain time zone. The Joda-Time library has convenient ways to do this: partials. One of the most frequent operations being done with partials is conversion from partials to instants and vice versa. A couple of listings showing how to do that follow.

The following code snippet shows how to assemble a DateTime instance using UTC time zone, LocalDate, and LocalTime objects:
LocalDate partialDate = new LocalDate(2012, 12, 3);
LocalTime partialTime = new LocalTime(12, 50);
DateTime dateTime = partialDate.toDateTime(partialTime,
        DateTimeZone.UTC);

System.out.println(ISODateTimeFormat.dateHourMinuteSecond()
        .print(dateTime));
The program will print the following output:

2012-12-03T12:50:00

The next code snippet shows how to assemble a DateTime instance using current time instant in UTC time zone and LocalTime object representing 23:30:
LocalTime partialTime = new LocalTime(23, 30);
DateTime dateTime = partialTime.toDateTime(
        new DateTime(DateTimeZone.UTC));

System.out.println(ISODateTimeFormat.dateHourMinuteSecond()
        .print(dateTime));
At the time of this writing the program printed the following output:

2012-12-03T23:30:00

Joda-Time contains YearMonth partial implementation. This class stores only year and month information as its name implies. It is useful to represent credit card expiration dates for example. Assume you have a credit card which expires in the December of 2014. Here is an easy way to determine which day of week it will be:
YearMonth expirationDate = new YearMonth(2014, 12);

String expirationDay = expirationDate.toDateTime(
        new DateTime(DateTimeZone.UTC).dayOfMonth().withMinimumValue())
                .dayOfWeek().getAsText();

System.out.println(expirationDay);
The program will print the following output:

Monday

Joda-Time has an easy way to represent day and month: MonthDay partial implementation. It is a convenient approach to store birthdays for example. Assume you have a friend whose birthday is the 1st of July. To find out which day of week will it be in the next year you could use the following code:
MonthDay birthday = new MonthDay(7, 1);

String dayOfWeek = birthday.toDateTime(new DateTime(DateTimeZone.UTC)
        .plusYears(1)).dayOfWeek().getAsText();

System.out.println(dayOfWeek);
At the time of this writing (year 2012) the program printed the following output:

Monday

A couple of previous code snippets showed how to convert partials to instants. The reverse conversion is even easier: partials’ constructors can be used to do that. The following code snippet shows some examples:
DateTime instant = new DateTime(2012, 12, 21, 8, 15,
        DateTimeZone.UTC);

LocalDate partialDate = new LocalDate(instant);
LocalTime partialTime = new LocalTime(instant);
LocalDateTime partialDateTime = new LocalDateTime(instant);
YearMonth yearMonth = new YearMonth(instant);
MonthDay monthDay = new MonthDay(instant);

System.out.println(partialDate.toString(
        ISODateTimeFormat.yearMonthDay()));
System.out.println(partialTime.toString(
        ISODateTimeFormat.hourMinute()));
System.out.println(partialDateTime.toString("yyyy.MM.dd/HH:mm:ss"));
System.out.println(yearMonth.toString("yyyy\\MMM"));
System.out.println(monthDay.toString("dd-MMM"));
The program will print the following output:

2012-12-21
08:15
2012.12.21/08:15:00
2012\Dec
21-Dec

Example 6

Sometimes you may need to work with time intervals (e.g. to implement time management application). You can use Interval class within Joda-Time to do this. The great thing about this class is that it provides an easy way of determining relationships between time intervals (gaps, overlaps, abuts). Here are a couple of examples:
DateTime today = new DateTime(DateTimeZone.UTC);

Interval firstMeeting = new Interval(
        new LocalTime(9, 0).toDateTime(today),
        new LocalTime(10, 0).toDateTime(today));

Interval coffeeBreak = new Interval(
        new LocalTime(10, 0).toDateTime(today),
        new LocalTime(10, 30).toDateTime(today));

Interval secondMeeting = new Interval(
        new LocalTime(10, 30).toDateTime(today),
        new LocalTime(12, 0).toDateTime(today));

Interval lunchTime = new Interval(
        new LocalTime(13, 0).toDateTime(today),
        new LocalTime(14, 0).toDateTime(today));

Interval thirdMeeting = new Interval(
        new LocalTime(16, 0).toDateTime(today),
        new LocalTime(18, 0).toDateTime(today));

Interval sportEvent = new Interval(
        new LocalTime(17, 0).toDateTime(today),
        new LocalTime(19, 0).toDateTime(today));

System.out.printf(
        "First meeting abuts coffee break: %b\n",
        firstMeeting.abuts(coffeeBreak));
System.out.printf(
        "Lunch time is before second meeting: %b\n",
        lunchTime.isBefore(secondMeeting));
System.out.printf(
        "Sport event is after the lunch: %b\n",
        sportEvent.isAfter(lunchTime));
System.out.printf(
        "Sport event overlaps with the third meeting: %b\n",
        sportEvent.overlaps(thirdMeeting));

Interval gap = thirdMeeting.gap(lunchTime);
Interval overlap = thirdMeeting.overlap(sportEvent);

System.out.printf(
        "I will miss the part of sport event: from %s to %s\n",
        ISODateTimeFormat.hourMinute().print(overlap.getStart()),
        ISODateTimeFormat.hourMinute().print(overlap.getEnd()));

System.out.printf(
        "I have spare time after lunch: from %s to %s\n",
        ISODateTimeFormat.hourMinute().print(gap.getStart()),
        ISODateTimeFormat.hourMinute().print(gap.getEnd()));
The program will print the following output:

First meeting abuts coffee break: true
Lunch time is before second meeting: false
Sport event is after the lunch: true
Sport event overlaps with the third meeting: true
I will miss the part of sport event: from 17:00 to 18:00
I have spare time after lunch: from 14:00 to 16:00

This listing is only a small subset of what can be achieved using Interval class. Please consider its javadoc for additional information about the API it provides.

Example 7

The Joda-Time library doesn’t allow you to compare intervals (i.e. Interval class doesn’t implement Comparable interface). But you do can compare their durations. The following example shows how to build a sorted set of intervals which sorts them by duration (starting from the shortest):
DateTime today = new DateTime(DateTimeZone.UTC);

Set<Interval> events = new TreeSet<Interval>(
        new Comparator<Interval>() {
            public int compare(Interval o1, Interval o2) {
                return o1.toDuration().compareTo(o2.toDuration());
            }
        });

events.add(new Interval(
        new LocalTime(9, 0).toDateTime(today),
        new LocalTime(11, 0).toDateTime(today)));

events.add(new Interval(
        new LocalTime(10, 0).toDateTime(today),
        new LocalTime(15, 0).toDateTime(today)));

events.add(new Interval(
        new LocalTime(13, 0).toDateTime(today),
        new LocalTime(16, 0).toDateTime(today)));

events.add(new Interval(
        new LocalTime(8, 0).toDateTime(today),
        new LocalTime(18, 0).toDateTime(today)));

events.add(new Interval(
        new LocalTime(16, 0).toDateTime(today),
        new LocalTime(17, 0).toDateTime(today)));

for (Interval event : events) {
    DateTimeFormatter formatter = ISODateTimeFormat.hourMinute();

    System.out.printf("event: %s-%s, duration: %d\n",
            formatter.print(event.getStart()),
            formatter.print(event.getEnd()),
            event.toDurationMillis());
}
The program will print the following output:

event: 16:00-17:00, duration: 3600000
event: 09:00-11:00, duration: 7200000
event: 13:00-16:00, duration: 10800000
event: 10:00-15:00, duration: 18000000
event: 08:00-18:00, duration: 36000000

Example 8

The concept of periods allows you to operate easily on periods of time defined in terms of fields (e.g. 4 years, 3 months, 5 days and 2 hours) instead of milliseconds. This implies that periods are inexact in terms of milliseconds and cannot be resolved to an exact number of milliseconds without an instant. Periods are useful when time period as a whole is important rather than its duration in terms of milliseconds. The following code snippet shows how the same period can yield totally different millisecond amount depending on the context:
DateMidnight firstOfFebruary = new DateMidnight(
        2012, 2, 1, DateTimeZone.UTC);
DateMidnight firstOfMarch = new DateMidnight(
        2012, 3, 1, DateTimeZone.UTC);

DateTimeFormatter formatter = ISODateTimeFormat.yearMonthDay();

System.out.println(formatter.print(firstOfFebruary.plus(Months.ONE)));
System.out.println(formatter.print(firstOfMarch.plus(Months.ONE)));
The program will print the following output:

2012-03-01
2012-04-01

The next code snippet shows a simple example of generic period implementation (Period class) usage:
DateTimeFormatter formatter = ISODateTimeFormat.yearMonthDay();

DateMidnight start = new DateMidnight(2013, 1, 1, DateTimeZone.UTC);
DateMidnight end = new DateMidnight(2014, 8, 1, DateTimeZone.UTC);

Period period = new Period(start, end);

DateMidnight startMinusPeriod = start.minus(period);
DateMidnight endPlusPeriod = end.plus(period);

System.out.printf("before start: %s\n", formatter
        .print(startMinusPeriod));
System.out.printf("period start: %s\n", formatter.print(start));
System.out.printf("period end:   %s\n", formatter.print(end));
System.out.printf("after  end:   %s\n", formatter
        .print(endPlusPeriod));
The program will print the following output:

before start: 2011-06-01
period start: 2013-01-01
period end:   2014-08-01
after  end:   2016-03-01

Example 9

And finally the last but not the least: this example is about JDK interoperability. From time to time you may need to fall back to standard Date class (e.g. your favorite framework works in its terms or you may have some legacy/integration code which you cannot modify). The closest analogue of standard Date class in Joda-Time is the notion of instant. Not surprisingly all instant implementations can be easily converted to JDK Date. The reverse conversion is also straightforward. The following code snippet shows how to do both:
DateTime dateTime = new DateTime(
        2013, 1, 1, 11, 15, DateTimeZone.UTC);

Date instantToDate = dateTime.toInstant().toDate();
Date dateTimeToDate = dateTime.toDate();
Date dateMidnightToDate = dateTime.toDateMidnight().toDate();
Date mutableDateTimeToDate = dateTime.toMutableDateTime().toDate();

Instant dateToInstant = new Instant(instantToDate.getTime());
DateTime dateToDateTime = new DateTime(dateTimeToDate.getTime());
DateMidnight dateToDateMidnight = new DateMidnight(
        dateMidnightToDate.getTime());
MutableDateTime dateToMutableDateTime = new MutableDateTime(
        mutableDateTimeToDate.getTime());
As you can see, streamlined interoperability between JDK standard date/time facilities and Joda-Time library allows you to write most of your application logic in terms of much more convenient Joda-Time API and fall back to standard means only when absolutely necessary.

Conclusion

Thank you for working through this tutorial. I hope it was useful and gave you the necessary basis to start using Joda-Time library in your software development efforts. This tutorial is not claimed to be an exhaustive Joda-Time guide so you are encouraged to explore the documentation to get more information about the library. Any comments and suggestions are appreciated.

See you soon!

4 comments:

  1. Great tutorial, Nice explanation.. :-)

    ReplyDelete
    Replies
    1. Thanks, I'm glad it was helpful to you :)

      Delete
  2. Awesome explanation:) :)

    ReplyDelete