Search code examples
javadatedatetime-formatlocaldate

Format credit card date MM/yy to MM/dd/yyyy


I have method that can take 2 different types of date formats:

  • MM/YY (credit card expiration date)
  • yyyyMMdd (funding expiration date)

Credit card expiration date is considered expired on the last day of that month. So, if cc date is May, 2017 (05/17), this cc is considered expired on 31th of May.

Funding expiration date will expire on the day it says it expires. So, if I am looking at it on the same day, it should return TRUE as funding has expired.

This is my code:

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Date;

public static boolean dateHasExpired(String dateInput)
{
     LocalDate d = LocalDate.now();
     LocalDate dateParsed = null;

     if (dateInput.contains("/"))
     {
          int iYear = Integer.parseInt(dateInput.substring(dateInput.indexOf("/") + 1));
          int iMonth = Integer.parseInt(dateInput.substring(0, dateInput.indexOf("/")));
          int daysInMonth = LocalDate.of(iYear, iMonth, 1).getMonth().maxLength();

          dateInput = iMonth+"/"+daysInMonth+"/"+iYear;
      }
      else
      {
          dateInput = ConvertDate(dateInput, "yyyyMMdd", "MM/dd/yyyy");
      }

      DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("MM/dd/yyyy");
      dateParsed = LocalDate.parse(dateInput, dateTimeFormatter);
      return d.compareTo(dateParsed) <= 0;
 }

public static String ConvertDate(String dateValue, String currentFormat, String requiredFormat)
{
     SimpleDateFormat inFormatter = new SimpleDateFormat(currentFormat);
     SimpleDateFormat outFormatter = new SimpleDateFormat(requiredFormat);
     String outDate = "";

     try
     {
         java.util.Date date = inFormatter.parse(dateValue);
         outDate = outFormatter.format(date);
     }
     catch (ParseException e) {
         ErrorLogger.logError  ( e );
     }
     return outDate;
 }

Does anyone know of better way of doing this?

I also noticed LocalDate doesn't account for Leap Year, so Feb 2015 has 29 days, just like Feb 2016, so my daysInMonth will not be a good number.

Looks like Date is more tollerant than LocalDate when it comes to year being yy and month 5 for month of May.


Solution

  • You can use java.time.YearMonth class, which contains a method that returns the last day of the respective month (and also takes care of leap years):

    public static boolean dateHasExpired(String dateInput) {
        LocalDate today = LocalDate.now();
        LocalDate dateParsed = null;
    
        if (dateInput.contains("/")) {
            // parse credit card expiration date
            YearMonth ym = YearMonth.parse(dateInput, DateTimeFormatter.ofPattern("MM/yy"));
             // get last day of month (taking care of leap years)
            dateParsed = ym.atEndOfMonth();
        } else {
            // parse funding expiration date
            dateParsed = LocalDate.parse(dateInput, DateTimeFormatter.ofPattern("yyyyMMdd"));
        }
    
        // expired if today is equals or after dateParsed
        return ! today.isBefore(dateParsed);
    }
    

    With this code (considering that today is May 02, 2017):

    System.out.println(dateHasExpired("04/17")); // true
    System.out.println(dateHasExpired("05/17")); // false
    System.out.println(dateHasExpired("06/17")); // false
    System.out.println(dateHasExpired("20170501")); //true
    System.out.println(dateHasExpired("20170502")); // true
    System.out.println(dateHasExpired("20170503")); // false
    

    Note that atEndOfMonth() method takes care of leap years, so these will also work:

    System.out.println(dateHasExpired("02/15"));
    System.out.println(dateHasExpired("02/16"));
    

    I've added a System.out.println(dateParsed); in dateHasExpired method, just to check if the date is being parsed correctly. And the output for the dates above are (respectively):

    2015-02-28
    2016-02-29
    

    And dateHasExpired returns true for both, as expected.