Introducing Joda Time: The smart date API

7

Recently I did a short presentation on Joda Time. Yesterday, on our yearly ODTUG preview, I was surpised that Joda Time is not known very well by ADF developers. To convince you of the power of this library I will give you a few examples of how and why I use it. It’s up to you if, after reading this post, you are going to use it in the future as well.

Lets start by asking a simple question. If you use the JDK date API what would you do to create a Date object with the value 18 februari 2009 ?

 

Date mydate = new Date(2009, 2, 18);

 

Aha… The actual statement would be:

 

Date mydate = new Date(109, 1, 18); 

 

Say what ? Yep years start to count from 1900, and months are zero based so january is 0 and december is 11. You can use Calendar instead, however, that is something I do not want to know. And that is only the java.util.date. Most of us are also using java.sql.date, oracle.jbo.domain.date and more of these……..I need an API that is easy to use. It’s time for JODA.

 

LocalDate mydate = new LocalDate(2009,2,18); 

 

The major building blocks of joda time are, instants, intervals, durations, periods, chronolgy and timezones. Let me explain this by playing around with some dates and try to do the same with the sun JDK API. First of all I want to add or substract days and years from a certain date. You would have to create two calenderInstances and then do the calculations. Be aware: substracting is actually adding a negative amount…..

 

    Calendar now = Calendar.getInstance();
    Calendar somewhereInTime;
    SimpleDateFormat formatter =
      new SimpleDateFormat("E yyyy-MM-dd hh:mm:ss a zzz");

    somewhereInTime = (Calendar)now.clone();
    somewhereInTime.add(Calendar.YEAR, - 4);
    System.out.println("  Four years ago it was: " + formatter.format(somewhereInTime.getTime()));

 

Joda allows you to substract or add units by calling the according methods directly.

 

    LocalDate now = new LocalDate();
    LocalDate somewhereInTime;
    DateTimeFormatter fmt = ISODateTimeFormat.date();

    somewhereInTime = now.minusYears(4);
    System.out.println("  Four years ago it was: " + somewhereInTime.toString(fmt));

 

I will not start a discussion on leapyears, because that works pretty much ok in both libs, however JODA thinks that 1000 AD is not a leapyear while JDK thinks it is. Both are rigth because according to the gregorian calendar 1000 is not a leapyear, but the gregorian calendar was only invented in 1538 ! In the year 1000 AD the Julian calender was used and 1000 is a leapyear.

 

Now lets take a look at how to calculate the diffence between two dates, or more specifically, how to get the exact number of days between two given dates.

 

  private static void dateDiff() {

    System.out.println("Calculate difference between two dates");
    System.out.println("=================================================================");

    Date startDate = new GregorianCalendar(2000, 1, 19, 00, 00).getTime();
    Date endDate = new Date();

    long diff = endDate.getTime() - startDate.getTime();

    System.out.println("  Difference between " + endDate);
    System.out.println("  and " + startDate + " is " + (diff / (1000L * 60L * 60L * 24L)) + " days.");

  }

 

What about that… 1000 milis times 60 seconds times 60 minutes times 24 hours and there’s your difference in days…. With JODA it works like this:

 

  private static void dateDiff() {

    System.out.println("Calculate difference between two dates");
    System.out.println("=================================================================");

    DateTime startDate = new DateTime(2000, 1, 19, 0, 0, 0, 0);
    DateTime endDate = new DateTime();

    Days d = Days.daysBetween(startDate, endDate);
    int days = d.getDays();

    System.out.println("  Difference between " + endDate);
    System.out.println("  and " + startDate + " is " + days + " days.");

  }

 

Easy isn’t it ? You can also work with intervals. To do that you just declare an interval with an startDate and an endDate. Take a look at the following example

 

  private static void intervalAndDuration() {
  DateTime start = new DateTime();
  DateTime  end = start.plusYears(2);

  Interval interval = new Interval(start, end);

  //From the interval it's easy to get the start and end by just 'getting' them

  DateTime start = interval.getStart();


  //If you need to know what the duration of an interval is, you can invoke toDuration() on the inteval.


  Duration duration = interval.toDuration();
 
  // its also possible to work with period. A period is a period of time in terms of fields. That is:YEARS, MONTHS, WEEKS   // and so on

  Period period = interval.toPeriod();

  // or

  Period weeks = interval.toPeriod(PeriodType.weeks());

 

The chronology is a kind of pluggable calendar, that can handle the different calendar systems.

 

Chronology coptic = CopticChronology.getInstance();
    DateTime now = new DateTime(coptic);
    int year = now.getYear();
    // year is 1725
Chronology buddhist = BuddhistChronology.getInstance();
    DateTime now = new DateTime(buddhist);
    int year = now.getYear();
    // year is 2525

 

Last thing to show is the easy conversion from a JDK date to a JODA date and vice versa. This is very easy. You can construct a new JODA date from a JDK date, do calculations and when you are finished go back to JDK date. Converting from joda-time to Calendar/Date involves a single method call either way. For example: new DateTime(Calendar or Date) and DateTime.toCalendar(). That’s just one example. You can convert pretty much any other joda-time construct back to JDK classes with ease.

 

Using joda time in your ADF project is easy. just include the jodatime library in your project, and include it in the classes where you need it.

For me it is clear that JODA time has a very friendly API which can be used to do exactly what I want. Also  JSR-310 (new date and time API for Java) is inspired by Joda-Time.

 

There is much more to tell about JODA time, so if you are curious, you can take a look at the Joda.org homepage at joda-time.sourceforge.net/

 

Share.

About Author

Luc Bors is Expertise Lead ADF and technical specialist/architect at AMIS, Nieuwegein (The Netherlands). He developed several Workshops and training on ADF and also is an ADF and JHeadstart instructor. Luc is a member of the ADF Methodology group and publishes articles on ADF in oracle technology related magazines, on the AMIS technology blog, (http://technology.amis.nl/blog).

7 Comments

  1. Hi,
    Can anyone please help on how to create only Time (without date) and calculate intervals between 2 times. I need a way to convert a string like 11:30 to time..

  2. Hi ana,
    No experience on that, but what I learn from the JODA-time wiki (http://joda-time.sourceforge.net/cal_islamic.html) is below. Take a look a that wiki
     
    // setup date object for midday on May Day 2004 (ISO year 2004)
    DateTime dtISO = new DateTime(2004, 5, 1, 12, 0, 0, 0);

    // find out what the same instant is using the Islamic Chronology

    DateTime dtIslamic = dtISO.withChronology(IslamicChronology.getInstance());

  3. Hey Hi,
    can you please help me by suggesting How to use Islamic Calendar /Lunar Calendar with JodoTime. Please tell me as soon as possible.
    Thank You

  4. Hi Robert,

    according to the component documentation the inputDate only accepts java.util.Date.

    If you need the value as a LocalDate instance, you could try to do the following:

    Use the org.joda.time.LocalDate date untill you have to actually show the date in the adf component. In other words: bind the to a java.util.Date date, and in the getter you first get the org.joda.time.LocalDate date and convert it to a java.util.Date date, which is the date that you return.

    When the date is changed, you can use a valueChangeListener which converts the java.util.Date date to the org.joda.time.LocalDate date.

    I wish a had a different answer, but I don’t. Let me know the solution you pick.

    Say hello to the rest of the team, and good luck with the next phase in the project !

  5. Robert Willems on

    Hi Luc,

    how do you configure the af:inputDate to bind to a value that is a LocalDate instance?
    It seems to want to set the model to an java.util.Date :(

    Regards,
    Robert (and the rest of the team ;-))

  6. Jasper Fontaine on

    For some additional fun, try doing this:

    DateTimeFormatter formatter =
    DateTimeFormat.forPattern(“yyyy-MM-dd HH:mm:ss.S”).withLocale(DUTCH_LOCALE);
    DateTime dt = formatter.parseDateTime(“1893-03-31 23:53:28.0″);
    System.out.println(dt.toDate());
    :)