com.sapienter.jbilling.server.process.BusinessDays.java Source code

Java tutorial

Introduction

Here is the source code for com.sapienter.jbilling.server.process.BusinessDays.java

Source

/*
 jBilling - The Enterprise Open Source Billing System
 Copyright (C) 2003-2011 Enterprise jBilling Software Ltd. and Emiliano Conde
    
 This file is part of jbilling.
    
 jbilling is free software: you can redistribute it and/or modify
 it under the terms of the GNU Affero General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.
    
 jbilling is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU Affero General Public License for more details.
    
 You should have received a copy of the GNU Affero General Public License
 along with jbilling.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.sapienter.jbilling.server.process;

import com.sapienter.jbilling.common.SessionInternalError;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.joda.time.DateMidnight;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;

/**
 * Utilities for calculating dates and dealing with business days (aka, banking days).
 *
 * @author Vikas Bodani, Brian Cowdery
 * @since 29/04/11
 */
public class BusinessDays {
    private static final Logger LOG = Logger.getLogger(BusinessDays.class);

    private static final DateFormat DEFAULT_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");

    private List<Date> holidays = new ArrayList<Date>();
    private Calendar start = GregorianCalendar.getInstance();
    private Calendar end = GregorianCalendar.getInstance();

    public BusinessDays() {
    }

    public BusinessDays(List<Date> holidays) {
        this.holidays = holidays;
    }

    public BusinessDays(File holidayFile) {
        loadHolidayFile(holidayFile);
    }

    public BusinessDays(File holidayFile, DateFormat dateformat) {
        loadHolidayFile(holidayFile, dateformat);
    }

    /**
     * Loads an external file containing the dates of holidays. These days will be handled
     * as non-business days when calculating business dates.
     *
     * This method assumes a default date format of "yyyy-MM-dd".
     *
     * @param file files to load
     */
    public void loadHolidayFile(File file) {
        loadHolidayFile(file, DEFAULT_DATE_FORMAT);
    }

    /**
     * Loads an external file containing the dates of holidays. These days will be handled
     * as non-business days when calculating business dates.
     *
     * @param file files to load
     * @param dateFormat date format of dates
     */
    public void loadHolidayFile(File file, DateFormat dateFormat) {
        holidays.clear();

        if (file != null && file.exists()) {
            BufferedReader in = null;

            try {
                in = new BufferedReader(new FileReader(file));

                String line = null;
                while ((line = in.readLine()) != null) {
                    if (StringUtils.isNotBlank(line)) {
                        try {
                            Date holiday = dateFormat.parse(line);
                            holidays.add(holiday);
                        } catch (ParseException e) {
                            LOG.warn("Invalid holiday date, or wrong date format - ignoring entry '" + line + "'");
                        }
                    }
                }

            } catch (IOException e) {
                LOG.warn("Holiday file " + file.getPath() + " could not be read.");

            } finally {
                try {
                    if (in != null) {
                        in.close();
                    }
                } catch (IOException e) {
                    /* ignore */
                }
            }
        } else {
            LOG.warn("Holiday file not set or does not exist.");
        }
    }

    /**
     * Convert a non-business day range and calculate an appropriate end date that falls on
     * a business day. If the original date range contains a weekend day or holiday, then the
     * resulting end date will be incremented as to exclude it.
     *
     * @param startDate starting date
     * @param endDate ending date
     * @return new end date for a business-day date range
     */
    public Date calculateEndDate(Date startDate, Date endDate) {
        start.setTime(startDate);
        end.setTime(endDate);

        while (start.before(end)) {
            if (start.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY
                    || start.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
                end.add(Calendar.DATE, 1);
            } else {
                for (Date holiday : holidays) {
                    if (isEqual(holiday, start.getTime())) {
                        end.add(Calendar.DATE, 1);
                    }
                }
            }
            start.add(Calendar.DATE, 1);
        }

        return end.getTime();
    }

    /**
     * Adds the given number of business days to the starting date.
     *
     * @param startDate initial start date to add days to
     * @param days business days to add
     * @return date with business days added
     */
    public Date addBusinessDays(Date startDate, int days) {
        start.setTime(startDate);

        int nonBusinessDays = 0;
        for (int i = 0; i < days; i++) {
            start.add(Calendar.DATE, 1);

            if (start.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY
                    || start.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
                nonBusinessDays++;
            }

            for (Date holiday : holidays) {
                if (isEqual(holiday, start.getTime())) {
                    nonBusinessDays++;
                }
            }
        }

        start.add(Calendar.DATE, nonBusinessDays);
        return start.getTime();
    }

    private boolean isEqual(Date startDate, Date endDate) {
        return new DateMidnight(startDate).equals(new DateMidnight(endDate));
    }
}