Monday, December 29, 2014

Joda-Time vs Date and Calendar Class in Java

This post is nothing special. I just thought to write it to highlight some benefits to using the Joda-Time library over the Date and Calendar class in Java.

I was working on a project that had to determine if a customer's invoice qualified for a marketing promotion.

The requirements are the following:
1. Check if number of days between retail date and current date is within the days to claim window.
2. Compare retail date if it falls between the marketing fund promotion's end date and start date.


Here's the code using the joda-time library:

 DateTime retailDate = new DateTime(remittanceItem.getRiData().getRetailDate());
 DateTime currentDate = new DateTime();
 for (BudgetDTO budgetDTO: budgetDTOList) {
  Integer daysToClaim = Integer.parseInt(budgetDTO.getRemitDays());
  DateTime startDate = new DateTime(budgetDTO.getStartDate());
  DateTime endDate = new DateTime(budgetDTO.getEndDate());
  //check first if currentDate -  retailDate is within the daysToClaim period
  if (Days.daysBetween(retailDate, currentDate).getDays() <= daysToClaim) {
   //check if retailDate is within the Budget startDate and endDate
   if (!retailDate.isBefore(startDate) && !retailDate.isAfter(endDate)) {
    mktgMapKey = budgetDTO.getProgramId() + "|" + budgetDTO.getIncentiveType();
    mktgMapValue = budgetDTO.getProgramDesc();
    mktgFundValueLabelMap.put(mktgMapKey, mktgMapValue);
    mktgFundProgramIdList.add(budgetDTO.getProgramId());  
   }
  }
 }


Here's the code using Date and Calendar class:

 //create the Date objects
 Date retailDate = remittanceItem.getRiData().getRetailDate();
 Date currentDate = new Date();
 SimpleDateFormat dateFormat = new SimpleDateFormat("MMM dd,yyyy HH:mm:ss");
 for (BudgetDTO budgetDTO: budgetDTOList) {
  long daysToClaim = Long.valueOf(budgetDTO.getRemitDays()).longValue();
  
  //create the Calendar objects
  Calendar startDate = new GregorianCalendar();
  startDate.setTime(budgetDTO.getStartDate());

  Calendar endDate = new GregorianCalendar();
  endDate.setTime(budgetDTO.getEndDate());
  
  Calendar rtlDate = new GregorianCalendar();
  rtlDate.setTime(remittanceItem.getRiData().getRetailDate());
  
  //To compare RELIABLY using Calendar#before() and Calendar#after()
  //we need to clear the time section first for each Calendar object
  startDate.set(Calendar.HOUR, 0);
  startDate.set(Calendar.HOUR_OF_DAY, 0);
  startDate.set(Calendar.MINUTE, 0);
  startDate.set(Calendar.SECOND, 0);
  startDate.set(Calendar.MILLISECOND, 0);

  endDate.set(Calendar.HOUR, 11);
  endDate.set(Calendar.HOUR_OF_DAY, 23);
  endDate.set(Calendar.MINUTE, 59);
  endDate.set(Calendar.SECOND, 59);
  endDate.set(Calendar.MILLISECOND, 0);
  
  rtlDate.set(Calendar.HOUR, 0);
  rtlDate.set(Calendar.HOUR_OF_DAY, 0);
  rtlDate.set(Calendar.MINUTE, 0);
  rtlDate.set(Calendar.SECOND, 0);
  rtlDate.set(Calendar.MILLISECOND, 0);

  //calculate difference in number of days
  long diff = currentDate.getTime() - retailDate.getTime();
  long diffDays = diff / (24 * 60 * 60 * 1000);
  
  //check first if it is within the daysToClaim period
  if (diffDays <= daysToClaim) {
   //check if retailDate is within the Budget startDate and endDate
   if ((!rtlDate.before(startDate) && !rtlDate.after(endDate))){
    mktgMapKey = budgetDTO.getProgramId() + "|" + budgetDTO.getIncentiveType();
    mktgMapValue = budgetDTO.getProgramDesc();
    mktgFundValueLabelMap.put(mktgMapKey, mktgMapValue);
    mktgFundProgramIdList.add(budgetDTO.getProgramId());  
   }
  }
 }


So you see. Using the Joda-Time library is not complex but definitely cleaner and less verbose.


Resources:
Joda-Time API