package com.fp.persistence.commondb.helper; import java.sql.Date; import java.sql.Timestamp; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.GregorianCalendar; import com.fp.common.helper.CalculationBase; import com.fp.common.logger.APPLogger; import com.fp.persistence.commondb.exception.CommondbException; /** * Clase utilitaria para el manejo de fechas. * * @author Jorge Vaca * @version 2.1 */ public class APPDates implements Comparable { /* Fecha base para las Operaciones */ private Date date; /* Base de Calculo */ private CalculationBase base; /* Calendario Encargado de las operaciones con las Fechas */ private final GregorianCalendar calendar; /* Formateador de Fechas para transporte */ private final SimpleDateFormat formateador; /** * Crea una nueva instancia de Dates * * @param pDate Fecha base * @param pBase Base de Calculo; */ public APPDates(String pDate, CalculationBase pBase) throws Exception { this(new Date(FormatDates.getInstance().getTransportDateFormat().parse(pDate).getTime()), pBase); } /** * Crea una nueva instancia de Dates * * @param pDate Fecha base como string formato yyyy-MM-dd */ public APPDates(String pDate) throws Exception { this(pDate, CalculationBase.B360365); } /** * Crea una nueva instancia de Dates * * @param pDate Fecha base * @param pBase Base de Calculo; */ public APPDates(Date pDate, CalculationBase pBase) throws Exception { this.date = pDate; this.base = pBase; this.calendar = new GregorianCalendar(); this.calendar.setTime(this.date); this.formateador = FormatDates.getInstance().getTransportDateFormat(); } /** * Crea una nueva instancia de Dates * * @param pDate Fecha base * @param pBase Base de Calculo; */ public APPDates(Date pDate, CalculationBase pBase, SimpleDateFormat sdf) throws Exception { this.date = pDate; this.base = pBase; this.calendar = new GregorianCalendar(); this.calendar.setTime(this.date); this.formateador = sdf; } /** * Crea una nueva instancia de Dates con base 360/365 * * @param pDate Fecha base */ public APPDates(Date pDate) throws Exception { this(pDate, CalculationBase.B360365); } /** * Entrega el Valor de date. * * @return Date */ public Date getDate() { return this.date; } /** * Entrega el Valor de date. * * @return Timestamp */ public Timestamp getTimestamp() { return new Timestamp(this.date.getTime()); } /** * Metodoq ue resta un mes a una fecha y le pone el ultimo dia del mes en la misma. * * @throws Exception */ public void substractOneMonth365() throws Exception { this.calendar.add(Calendar.MONTH, -1); int max1 = this.calendar.getActualMaximum(Calendar.DAY_OF_MONTH); this.calendar.set(Calendar.DAY_OF_MONTH, max1); this.date = new Date(this.calendar.getTimeInMillis()); } /** * Clase que se encarga de restar dos fechas, a la fecha mayor se resta una fecha menor. * * @param pInicialdate Feinicial a restar de una fecha final. * @return int * @throws Exception */ public int substract(APPDates pInicialdate) throws Exception { int days = 0; if (pInicialdate.getDate().after(this.date)) { throw new CommondbException("COMMONDB-0001", "FECHA A RESTAR: {0,date,yyyy-MM-dd} ES MAYOR A: {1,date,yyyy-MM-dd}", pInicialdate.getDate(), this.date); } if (pInicialdate.getDate().compareTo(this.date) == 0) { return 0; } if (this.base.getMonthBase() == 365) { days = this.substract365(pInicialdate); } else { days = this.substract360(pInicialdate); } return days; } /** * Metodo que resta fechas en base cuando la base es 365/xxx * * @param pInicialdate Fecha inicia a restar. * @return int * @throws Exception */ private int substract365(APPDates pInicialdate) throws Exception { int days = 0; GregorianCalendar cal1 = new GregorianCalendar(); cal1.setTime(pInicialdate.getDate()); do { cal1.add(Calendar.DATE, 1); days++; } while (this.date.compareTo(cal1.getTime()) != 0); return days; } /** * Metodo que se encarga de restar dos fehcas en base 360. * * @param pInicialdate * @return * @throws Exception */ private int substract360(APPDates pInicialdate) throws Exception { int days = 0; int nYears = this.getField(Calendar.YEAR) - pInicialdate.getField(Calendar.YEAR); int nMonths = this.getField(Calendar.MONTH) - pInicialdate.getField(Calendar.MONTH); int dayone = this.getField(Calendar.DAY_OF_MONTH); if (dayone == 31) { dayone = 30; } int daytwo = pInicialdate.getField(Calendar.DAY_OF_MONTH); if (daytwo == 31) { daytwo = 30; } int nMonth = this.getField(Calendar.MONTH); if (nMonth == 1) { // 0 enero, 1 febrero , 2 marzo // si el dia de la fecha es igual al maximo dia del mes if (this.getField(Calendar.DAY_OF_MONTH) == this.calendar.getActualMaximum(Calendar.DAY_OF_MONTH)) { int day = pInicialdate.getField(Calendar.DAY_OF_MONTH); if ((day == 30) || (day == 31)) { dayone = 30; } } } nMonth = pInicialdate.getField(Calendar.MONTH); if (nMonth == 1) { // 0 enero, 1 febrero , 2 marzo // si el dia de la fecha es igual al maximo dia del mes if (pInicialdate.getField(Calendar.DAY_OF_MONTH) == pInicialdate.calendar.getActualMaximum(Calendar.DAY_OF_MONTH)) { int day = this.getField(Calendar.DAY_OF_MONTH); if ((day == 30) || (day == 31)) { daytwo = 30; } } } nYears = nYears * 12 * 30; nMonths = nMonths * 30; days = dayone - daytwo; days = nYears + nMonths + days; /* v_dias_resultado := (nvl(v_anios,0) * 12 * 30) + (nvl(v_meses,0) * 30) + (nvl(v_dia1,0) - nvl(v_dia2,0)); */ return days; } /** * Aniadir dias a una Fecha * * @param days Numero de dias a aniadir */ public void addYearBased(int days) throws Exception { if (this.base.getYearBase() == 365) { this.calendar.add(Calendar.DATE, days); } else { if (Math.abs(days) >= 30) { int month = (int) Math.floor(days / 30); this.calendar.add(Calendar.MONTH, month); this.calendar.add(Calendar.DATE, days % 30); } else { this.calendar.add(Calendar.DATE, days); } } this.date = new Date(this.calendar.getTime().getTime()); } /** * Aniadir dias a una Fecha, amteniendo un dia fijo en la fecha. * * @param days Numero de dias a adicionar. * @param payDay Fecha de pago. * @throws Exception */ public void addDaysBased(int days, Integer payDay) throws Exception { if (this.base.getMonthBase() == 365) { /* * if( days == 31 || this.calendar.getActualMaximum(Calendar.DAY_OF_MONTH) >= days){ * this.calendar.add(Calendar.MONTH,1); }else{ this.calendar.add(Calendar.DATE, days); } */ this.calendar.add(Calendar.DATE, days); } else { if (Math.abs(days) >= 30) { int diff = 0; if (this.calendar.get(Calendar.MONTH) == Calendar.FEBRUARY) { if (this.calendar.get(Calendar.DATE) >= 28) { if ((payDay != null) && (this.calendar.getActualMaximum(Calendar.DAY_OF_MONTH) < payDay)) { // diff= (this.calendar.getActualMaximum(Calendar.DAY_OF_MONTH)==29)?1:2; diff = payDay - this.calendar.getActualMaximum(Calendar.DAY_OF_MONTH); } } } int month = (int) Math.floor(days / 30); this.calendar.add(Calendar.MONTH, month); int d = days % 30; this.calendar.add(Calendar.DATE, d); if (diff > 0) { this.calendar.add(Calendar.DATE, diff); } } else { this.calendar.add(Calendar.DATE, days); } } this.date = new Date(this.calendar.getTime().getTime()); } /** * Aniadir dias a una Fecha * * @param days Numero de dias a aniadir */ public void addMonthBased(int days) throws Exception { if (this.base.getMonthBase() == 365) { this.calendar.add(Calendar.DATE, days); } else { if (Math.abs(days) >= 30) { int diff = 0; if (this.calendar.get(Calendar.MONTH) == Calendar.FEBRUARY) { if (this.calendar.get(Calendar.DATE) >= 28) { diff = (this.calendar.getActualMaximum(Calendar.DAY_OF_MONTH) == 29) ? 1 : 2; } } int month = (int) Math.floor(days / 30); this.calendar.add(Calendar.MONTH, month); this.calendar.add(Calendar.DATE, days % 30); if (diff > 0) { this.calendar.add(Calendar.DATE, diff); } } else { this.calendar.add(Calendar.DATE, days); } } this.date = new Date(this.calendar.getTime().getTime()); } /** * Entrega el Valor de base de calculo. * * @return CalculationBase. */ public CalculationBase getBase() { return this.base; } /** * Fija el valor de base de calculo * * @param base Nuevo valor de base. */ public void setBase(CalculationBase base) { this.base = base; } /* * (non-Javadoc) * * @see java.lang.Object#toString() */ @Override public String toString() { return this.formateador.format(this.date).toString(); } public int getField(int pField) throws Exception { return this.calendar.get(pField); } /** * Entrega el Valor de calendar. * * @return GregorianCalendar. */ public GregorianCalendar getGregorianCalendar() { return this.calendar; } public APPDates dateFrecuency(Frequency pFrecuency) throws Exception { this.calendar.add(Calendar.DATE, pFrecuency.getNumDays(this.getDate(), this.formateador)); return new APPDates(new Date(this.calendar.getTime().getTime())); } public APPDates nextDateofSequence(Frequency pFrecuency, int pDay) throws Exception { int days = pFrecuency.getNumDays(this.getDate(), this.formateador); if (days > 31) { // TODO Incluiy las frecuanias superiores a mensual throw new CommondbException("COMMONDB-0002", "LA FRECUENCIA DEBE SER MENOR O IGUAL A MENSUAL"); } if (pDay > days) { if ((pFrecuency == Frequency.MONTHLY) && (pDay == 31)) { pDay = days; } else { throw new CommondbException("COMMONDB-0003", "El DIA {0} NO PUEDE MAYOR AL NUMEOR DE DIAS DE LA FRECUENCIA{1}", pDay, days); } } GregorianCalendar cal = new GregorianCalendar(); cal.setTime(this.date); if (pFrecuency == Frequency.WEEKLY) { while (cal.get(Calendar.DAY_OF_WEEK) != pDay) { cal.add(Calendar.DAY_OF_WEEK, 1); } return new APPDates(new Date(cal.getTime().getTime())); } cal.set(Calendar.DATE, pDay); APPLogger.getLogger().debug("Calendario base ==> " + cal.getTime()); APPLogger.getLogger().debug("Maximo dia del mes ==> " + cal.getActualMaximum(Calendar.DAY_OF_MONTH)); while (cal.getTime().before(this.date)) { cal.add(Calendar.DATE, days); } while ((cal.get(Calendar.MONTH) != this.getField(Calendar.MONTH)) && (pDay != cal.get(Calendar.DATE))) { cal.add(Calendar.DATE, -1); } if ((cal.get(Calendar.DATE) == 30) && (cal.getActualMaximum(Calendar.DAY_OF_MONTH) == 31)) { cal.add(Calendar.DATE, 1); } return new APPDates(new Date(cal.getTime().getTime())); } public int getJulianDate() throws Exception { GregorianCalendar c = new GregorianCalendar(); c.setTime(this.date); return this.toJulian(c.get(Calendar.YEAR), c.get(Calendar.MONTH), c.get(Calendar.DATE)); } private int toJulian(int year, int month, int day) throws Exception { int julianYear = year; if (year < 0) { julianYear++; } int julianMonth = month; if (month > 2) { julianMonth++; } else { julianYear--; julianMonth += 13; } double julian = (java.lang.Math.floor(365.25 * julianYear) + java.lang.Math.floor(30.6001 * julianMonth) + day + 1720995.0); if ((day + (31 * (month + (12 * year)))) >= JGREG) { int ja = (int) (0.01 * julianYear); julian += (2 - ja) + (0.25 * ja); } return (int) Math.floor(julian); } public static final int JGREG = 15 + (31 * (10 + (12 * 1582))); /** * Adiciona anios, meses, dias, semanas ..Etc a una fecha. * * @param field Constante de anio, mes, dia...Etc * @param value Numero de anios, dias, meses a adicionar puese der un valor negativo. * @throws Exception */ public void addField(int field, int value) throws Exception { getGregorianCalendar().add(field, value); this.date = new Date(getGregorianCalendar().getTimeInMillis()); } /** * Adiciona anios, meses, dias, semanas ..Etc a una fecha. * * @param field Constante de anio, mes, dia...Etc * @param value Numero de anios, dias, meses a adicionar puese der un valor negativo. * @throws Exception */ public void setField(int field, int value) throws Exception { if (field == Calendar.DAY_OF_MONTH) { int maxday = getGregorianCalendar().getActualMaximum(Calendar.DAY_OF_MONTH); if (value > maxday) { value = maxday; } } getGregorianCalendar().set(field, value); this.date = new Date(getGregorianCalendar().getTimeInMillis()); } /** * Compara dos Dates. * * @param o * @return */ @Override public int compareTo(Object o) { if (!(o instanceof APPDates)) { return -1; } APPDates d = (APPDates) o; return this.date.compareTo(d.date); } /** * Entrega el dia del anio al correspondiente a la Fecha * * @return Dia del Anio * @throws Exception */ public int getDayOfYear() throws Exception { GregorianCalendar gcal = new GregorianCalendar(); gcal.setTime(this.date); return gcal.get(Calendar.DAY_OF_YEAR); } /** * Entrega lso dias del mes correspondiente a la fecha. * * @return int * @throws Exception */ public int getDaysOfMonth() throws Exception { if (this.base.getMonthBase() == 360) { return 30; } GregorianCalendar gcal = new GregorianCalendar(); gcal.setTime(this.date); return gcal.getActualMaximum(Calendar.DAY_OF_MONTH); } /** * Fija el ultimo dia del mes corespondiente a la fecha. * * @return * @throws Exception */ public void setLastDateOfMonth() throws Exception { Calendar gcal = new GregorianCalendar(); gcal.setTime(this.date); gcal.set(Calendar.DAY_OF_MONTH, this.getDaysOfMonth()); this.date = new Date(gcal.getTimeInMillis()); } /** * Entrega el mes del aņo correspondiente a la Fecha * * @return mes del aņo * @throws Exception */ public String getMonthOfYear() throws Exception { int month = this.getField(Calendar.MONTH) + 1; if (month < 10) { return "0" + month; } else { return "" + month; } } }