Quizas a usted alguna vez le toco programar como encontrar el último día hábil del mes. La definición:
Es el último día del mes, que no cae un fin de semana y que no es un día feriado.
Para trabajar este ejemplo utilizaremos fechas de los Estados Unidos, mercado de finanzas. En el caso de los días feriados, vamos a utilizar el calendario de OCC (Options Clearing Corporation). Dependiendo del área y país en donde usted trabaje el calendario de las fechas será distinto (por ejemplo Estados Unidos y Venezuela).
La solución en Java es sencilla, usando la clase Calendar. Después de jugar un poco al final terminé escribiendo esta clase que muestra el último día hábil del mes y le dice a usted si la fecha entrada por el teclado es un día hábil o no:
package com.kodegeek.blog.finance;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.ResourceBundle;
import java.util.Scanner;
import java.util.Set;
import java.util.logging.Logger;
/**
* Helper date methods tailored for the financial industry.
* License: LGPL
* BLOG: http://kodegeek.com
* @author josevnz@kodegeek.com
*
*/
public final class DateHelper {
private final static ResourceBundle BUNDLE;
private final static Logger log;
private static final Set holidays;
static {
BUNDLE = ResourceBundle.getBundle(DateHelper.class.getName());
log = Logger.getLogger(DateHelper.class.getName());
// Populate the holidays set
holidays = new HashSet();
for (String dateStr: BUNDLE.getString("com.kodegeek.blog.finance.DateHelper.holidays").split(";\\s*", -1)) {
try {
holidays.add(DateFormat.getDateInstance(DateFormat.DEFAULT).parse(dateStr));
} catch (ParseException e) {
log.warning(String.format(BUNDLE.getString("com.kodegeek.blog.finance.DateHelper.error.badDate"), dateStr));
continue;
}
}
}
/**
* Default constructor
*/
private DateHelper() {
// Only static methods go on this class
}
/**
* Check if a given date is the last business day of the month
* @param aDate The date to test
* @return True if is the last day of the month, false otherwise
*/
public final static boolean isLastBusinessDayOfMonth(final Date aDate) {
boolean isLastBusinessDay = false;
// Can do a comparison?
if (aDate == null) {
return isLastBusinessDay;
}
Calendar calendar = Calendar.getInstance();
// Current date on a weekend
calendar.setTime(aDate);
int day = calendar.get(Calendar.DAY_OF_MONTH);
int month = calendar.get(Calendar.MONTH);
int year = calendar.get(Calendar.YEAR);
int lastbusinessDayOfMonth = getLastBusinessDayOfMonth(month, year);
if (lastbusinessDayOfMonth == day) {
isLastBusinessDay = true;
}
return isLastBusinessDay;
}
/**
* Get the last business day of the month for a given month / year combination
* @param month The month
* @param year The year
* @return The last business day
*/
public static int getLastBusinessDayOfMonth(final int month, final int year) {
int day = -1;
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.MONTH, month);
calendar.set(Calendar.YEAR, year);
calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
// Keep looking backwards until the day is not a weekend or a holiday
while(true) {
if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY) {
calendar.add(Calendar.DAY_OF_MONTH, -1);
continue;
} else if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
calendar.add(Calendar.DAY_OF_MONTH, -2);
continue;
} else if (holidays.contains(calendar.getTime())) {
calendar.add(Calendar.DAY_OF_MONTH, -1);
continue;
}
break;
} // End while
day = calendar.get(Calendar.DAY_OF_MONTH);
return day;
}
/**
* Unit test, load today date and check if is a end of the month
* @param args The date to test from the command line
* @throws Exception If the date is invalid for the given local
*/
public static void main(String [] args) throws Exception {
Scanner scan = new Scanner(System.in);
do {
String currDateStr = null;
SimpleDateFormat format = new SimpleDateFormat("yy-M-d");
try {
System.out.println("Please enter a date to check (YYYY-MM-DD, Ctrl-C to exit):");
currDateStr = scan.nextLine();
Date date = format.parse(currDateStr);
if (date != null) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
int month = calendar.get(Calendar.MONTH);
int year = calendar.get(Calendar.YEAR);
System.out.println(String.format("Last business day of the month: %d", getLastBusinessDayOfMonth(month, year)));
System.out.println(String.format("%s %s", currDateStr,isLastBusinessDayOfMonth(date) == true? "Is the last business day": "Is not the last business day"));
}
} catch (ParseException pExp) {
System.err.println(String.format("Ignoring bad date: '%s'", currDateStr));
}
} while (true);
}
}
El resource bundle lo único que contiene son los días feriados:
# Bank holidays per OCC calendar 2009 - http://www.optionsclearing.com/market/infomemos/2008/oct/24961.pdf
com.kodegeek.blog.finance.DateHelper.holidays=Jan 01, 2009;January 19, 2009; Feb 26, 2009;Apr 10, 2009;May 25, 2009;July 3, 2009; Sep 7, 2009; Nov 26, 2009; Dec 25, 2009; Oct 12, 2009; Nov 11, 2009
com.kodegeek.blog.finance.DateHelper.error.badDate=Got bad date '%s' from property
La idea es buscar el último día del mes y de allí contar hacia atrás, esquivando fines de semana y días feriados.
Please enter a date to check (YYYY-MM-DD, Ctrl-C to exit):
2009-02-27
Last business day of the month: 27
2009-02-27 Is the last business day
En una siguiente entrega les mostraré como hacer lo mismo en Ruby.
Blogalaxia:calendar, calendario, java.perl.ruby, occ
Technorati:calendar, calendario, java.perl.ruby, occ
To2blogs:calendar, calendario, java.perl.ruby, occ
Del.icio.us:calendar, calendario, java.perl.ruby, occ
Xydisimo men, ja yo hace tanto no hago java en forma, que ya se me esta olvidando. pero me latio mucho tu clase…la compro pa ievar 😀
saludos
Bueno, gracias y me alegra que ye haya gustado el código 😀