Quick News

ObjectLab Open Source News

2011-11-18 YourKit is kindly supporting open source projects with its full-featured Java Profiler. YourKit, LLC is the creator of innovative and intelligent tools for profiling Java and .NET applications. Take a look at YourKit's leading software products: YourKit Java Profiler and YourKit .NET Profiler.

2010-05-10 Version 1.2.0 is out and contains a couple of changes, including the ability to see the registered calendar and unregistering calendars (useful if calendars are dynamic). More info on the changes here. Also, one of the authors is on Twitter, follow your favorite Belgian at http://twitter.com/benoitx.

2007-03-25 Version 1.1.0 is out and contains a couple of changes, a new HolidayHandler and the ability to define a valid range for the holiday (and if the calculation is beyond that range, an exception is thrown). This is done via HolidayCalendar which should replace the simple Set<E> for holidays. More info on the changes here.

ObjectLab Kit Introduction

ObjectLab Kit came out of our frustration to have to re-do the same kind of code over and over each time we joined a new company and Bank. Most banks will require basic Date calculation, we did spot another open source project for this but their licence forbids most financial institution from using it. This one is released under the business-friendly Apache 2.0 license. Digg!

Getting Started

DateCalc comes in 2 different implementations, both run on JDK 1.5 or higher:

Maven

If you're using Maven, setup is easy, as DateCalc is in the Maven Central Repository.

To use the JDK Version:

         <dependency>
           <groupId>net.objectlab.kit</groupId>
           <artifactId>datecalc-common</artifactId>
           <version>1.2.0</version>
         </dependency>
         <dependency>
           <groupId>net.objectlab.kit</groupId>
           <artifactId>datecalc-jdk</artifactId>
           <version>1.2.0</version>
         </dependency>
      

To use the JODA Version (recommended):

         <dependency>
           <groupId>net.objectlab.kit</groupId>
           <artifactId>datecalc-common</artifactId>
           <version>1.2.0</version>
         </dependency>
         <dependency>
           <groupId>net.objectlab.kit</groupId>
           <artifactId>datecalc-joda</artifactId>
           <version>1.2.0</version>
         </dependency>
      

Download the Jars

If you are not using Maven, you can download the jars here.

Date Calculations? What is that?

Apart from the very basic "add days" features, most business have to deal with Holidays and what to do when a calculated day falls on a holiday. This library does not attempt to create or guess the holidays, we all know that some bank holidays can be decided at a moment's notice in some markets. All financial institutions or big business will have their own official list of 'holidays' anyway.

Furthermore, "weekends" also need to be handled and some market have a different week to the conventional Monday -> Friday, our library provides you with full flexibility to design a Working Week.

As such a Non-working Day can be a holiday or a 'weekend'.

Ok, what algorithm for handling a holiday do you support?

At the moment, we support the following 6 algorithms:

  1. Do Nothing, i.e. leave the date as-is, even if it is a non-working day.
  2. Forward, if the date is a non-working day, move forward to the next working day.
  3. Backward, if the date is a non-working day, move backward to the previous working day.
  4. Modified Following, if the date is a non-working day, move forward to the next working day, UNLESS it crosses over a new month, in which case we revert to find the last working day of the current month.
  5. Modified Preceeding, if the date is a non-working day, move backward to the previous working day, UNLESS it crosses over a new month, in which case we revert to find the next working day of the current month.
  6. ForwardUnlessNegative (new with v1.1.0), acts like a Forward algo unless the increment is negative, in which case it behaves like Backward.

See this page for some examples.

UML?

We generate our JavaDocs with the added twist of UML diagrams:

Main interfaces

The main interfaces are:

Here are the examples of how to get a DateCalculator "forward" for the "UK" holidays (if you have registered the holidays). The WorkingWeek is Mon-Fri by default.

JDK

2 implementations for Pure JDK have been released

  1. Calendar:
    DateCalculator<Calendar> calc1 = CalendarKitCalculatorsFactory.getDefaultInstance()
            .getDateCalculator("UK", HolidayHandlerType.FORWARD);
            
    PeriodCountCalculator<Calendar> calc2 = CalendarKitCalculatorsFactory.getDefaultInstance()
            .getPeriodCountCalculator();
    
    IMMDateCalculator<Calendar> calc3 = CalendarKitCalculatorsFactory.getDefaultInstance()
            .getIMMDateCalculator();
            
  2. Date:
    DateCalculator<Date> calc1 = DateKitCalculatorsFactory.getDefaultInstance()
            .getDateCalculator("UK", HolidayHandlerType.FORWARD);
    
    PeriodCountCalculator<Date> calc2 = DateKitCalculatorsFactory.getDefaultInstance()
            .getPeriodCountCalculator();
    
    IMMDateCalculator<Date> calc3 = DateKitCalculatorsFactory.getDefaultInstance()
            .getIMMDateCalculator();
            

JODA

2 implementations for Joda have been released

  1. LocalDate (recommended):
    DateCalculator<LocalDate> calc1 = LocalDateKitCalculatorsFactory.getDefaultInstance()
            .getDateCalculator("UK", HolidayHandlerType.FORWARD);
    
    PeriodCountCalculator<LocalDate> calc2 = LocalDateKitCalculatorsFactory.getDefaultInstance()
            .getPeriodCountCalculator();
    
    IMMDateCalculator<LocalDate> calc3 = LocalDateKitCalculatorsFactory.getDefaultInstance()
            .getIMMDateCalculator();
            
  2. YearMonthDay:
    DateCalculator<YearMonthDay> calc1 = YearMonthDayKitCalculatorsFactory.getDefaultInstance()
            .getDateCalculator("UK", HolidayHandlerType.FORWARD);
    
    PeriodCountCalculator<YearMonthDay> calc2 = YearMonthDayKitCalculatorsFactory.getDefaultInstance()
            .getPeriodCountCalculator();
    
    IMMDateCalculator<YearMonthDay> calc3 = YearMonthDayKitCalculatorsFactory.getDefaultInstance()
            .getIMMDateCalculator();
            

How do I use it?

There are several steps

  • Register holidays in the factory by calling registerHolidays(final String name, HolidayCalendar<Date> holidays)
  • Use the factory to get a DateCalculator with a given Handler (forward/backward etc), it is a disposable object that should not be shared accross threads, each thread should get its own!
  • when you get a DateCalculator, you can set the startDate, this sets the currentDate too. The startDate does not move. The current date is the result of your calculations. If the startDate is a non-working day, it may be moved automatically according to the HolidayHandler.
  • when you call moveByDays(..), moveByBusinessDays(..), moveByTenor the currentDate is moved in the Calculator.

Using Joda Time LocalDate

// create or get the Holidays
final Set<LocalDate> holidays = new HashSet<LocalDate>();
holidays.add(new LocalDate("2006-08-28"));
//... keep adding all holidays for 2006

// create the HolidayCalendar ASSUMING that the set covers 2006!
final HolidayCalendar<LocalDate> calendar = new DefaultHolidayCalendar<LocalDate>
        (holidays, new LocalDate("2006-01-01"), new LocalDate("2006-12-31"));
  
// register the holidays, any calculator with name "UK"
// asked from now on will receive an IMMUTABLE reference to this calendar
LocalDateKitCalculatorsFactory.getDefaultInstance().registerHolidays("UK", calendar);

// ask for a LocalDate calculator for "UK" 
// (even if a new set of holidays is registered, this one calculator is not affected
DateCalculator<LocalDate> cal = LocalDateKitCalculatorsFactory.getDefaultInstance()
        .getDateCalculator("UK", HolidayHandlerType.FORWARD);
        
// set startDate, this will also set the current business date.
cal.setStartDate(new LocalDate("2006-08-28")); 

// startDate stays 28 Aug 06 BUT the currentDate has moved, 
// according to Forward handler to 29 Aug 2006.
LocalDate start = cal.getStartDate();   // 28 Aug 06
LocalDate current = cal.getCurrentBusinessDate(); // 29 Aug 06

LocalDate newCurrent = cal.moveByDays(4).getCurrentBusinessDate(); // 4 Sept 06 due to weekend!

// Example with Tenor, 1W with a 2 day spot lag
LocalDate date1WeekFromSpot = cal.moveByTenor(StandardTenor.T_1W, 2).getCurrentBusinessDate();
    

Using JDK Calendar

// create or get the Holidays
final Set<Calendar> holidays = new HashSet<Calendar>();
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.DAY_OF_MONTH, 28);
calendar.set(Calendar.MONTH, Calendar.AUGUST);
calendar.set(Calendar.YEAR, 2006);
holidays.add(calendar);  
//... keep adding all holidays for 2006

// create the HolidayCalendar ASSUMING that the set covers 2006!
final HolidayCalendar<Calendar> calendar = new DefaultHolidayCalendar<Calendar>
        (holidays, new Calendar("2006-01-01"), new Calendar("2006-12-31"));

// register the holidays, any calculator with name "UK"
// asked from now on will receive an IMMUTABLE reference to this calendar
CalendarKitCalculatorsFactory.getDefaultInstance().registerHolidays("UK", calendar);

// ask for a LocalDate calculator for "UK" 
// (even if a new set of holidays is registered, this one calculator is not affected
DateCalculator<Calendar> cal = LocalDateKitCalculatorsFactory.getDefaultInstance()
        .getDateCalculator("UK", HolidayHandlerType.FORWARD);

Calendar initial = Calendar.getInstance();
initial.set(Calendar.DAY_OF_MONTH, 28);
initial.set(Calendar.MONTH, Calendar.AUGUST);
initial.set(Calendar.YEAR, 2006);

// set startDate, this will also set the current business date.
cal.setStartDate(initial);

// the startDate stays 28 Aug 06 BUT the currentDate has moved, 
// according to Forward handler to 29 Aug 2006.
Calendar start = cal.getStartDate();   // 28 Aug 06
Calendar current = cal.getCurrentBusinessDate(); // 29 Aug 06

Calendar newCurrent = cal.moveByDays(4).getCurrentBusinessDate(); // 4 Sept 06 due to weekend!

// Example with Tenor, 1W with a 2 day spot lag
Calendar date1WeekFromSpot = cal.moveByTenor(StandardTenor.T_1W, 2).getCurrentBusinessDate();