nl.strohalm.cyclos.utils.Period.java Source code

Java tutorial

Introduction

Here is the source code for nl.strohalm.cyclos.utils.Period.java

Source

/*
This file is part of Cyclos (www.cyclos.org).
A project of the Social Trade Organisation (www.socialtrade.org).
    
Cyclos is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
    
Cyclos 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 General Public License for more details.
    
You should have received a copy of the GNU General Public License
along with Cyclos; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    
 */
package nl.strohalm.cyclos.utils;

import java.io.Serializable;
import java.util.Calendar;
import java.util.GregorianCalendar;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.time.DateUtils;

/**
 * A date period, which can be configured not to take into account the time part in calculations by setting the useTime flag in false. Note that the
 * useTime in false doesn't mean that the begin and end dates have a zero time. The useTime only interfere in calculations. <br>
 * Also not that useTime==false is the default behavior. So by default the begin and end dates are truncated. If you don't want this behavior and need
 * to use the times, you must explicitly set useTime to true.<br>
 * You may also set the inclusiveBegin (default true) and inclusiveEnd (default true) flags.
 * 
 * @author luis
 */
public class Period implements Serializable, Cloneable {

    private static final long serialVersionUID = 6246167529034823152L;

    public static Period begginingAt(final Calendar begin) {
        return new Period(begin, null);
    }

    public static Period between(final Calendar begin, final Calendar end) {
        return new Period(begin, end);
    }

    public static Period betweenOneYear(final int year) {
        final Calendar begin = new GregorianCalendar(year, 0, 1);
        final Calendar end = new GregorianCalendar(year, 11, 31, 23, 59, 59);
        return between(begin, end);
    }

    public static Period day(Calendar day) {
        day = DateHelper.truncate(day);
        return new Period(day, day);
    }

    public static Period endingAt(final Calendar end) {
        return new Period(null, end);
    }

    /**
     * creates a period representing a day. If you set the setUseTime() flag afterwards, then it will represent a point in time.
     * @param time
     * @return
     */
    public static Period exact(final Calendar time) {
        return new Period(time, time);
    }

    private Calendar begin;
    private Calendar end;
    private boolean useTime;
    private boolean inclusiveBegin = true;
    private boolean inclusiveEnd = true;

    public Period() {
    }

    public Period(final Calendar begin, final Calendar end) {
        setBegin(begin);
        setEnd(end);
    }

    @Override
    public Period clone() {
        Period newPeriod;
        try {
            newPeriod = (Period) super.clone();
        } catch (final CloneNotSupportedException e) {
            // this should never happen, since it is Cloneable
            throw new InternalError(e.getMessage());
        }
        newPeriod.begin = begin == null ? null : (Calendar) begin.clone();
        newPeriod.end = end == null ? null : (Calendar) end.clone();

        return newPeriod;
    }

    @Override
    public boolean equals(final Object obj) {
        if (!(obj instanceof Period)) {
            return false;
        }
        final Period p = (Period) obj;
        return new EqualsBuilder().append(begin, p.begin).append(end, p.end).isEquals();
    }

    public Calendar getBegin() {
        return begin;
    }

    public Quarter getBeginQuarter() {
        return getQuarter(begin);
    }

    /**
     * Returns the number of days between the begin and end date. If either is null, returns -1.
     * @see DateHelper#daysBetween(Calendar, Calendar)
     */
    public int getDays() {
        if (begin == null || end == null) {
            return -1;
        }
        return DateHelper.daysBetween(begin, end);
    }

    /**
     * @return The difference between beginDate and endDate from period in seconds
     */
    public long getDifference() {
        if (begin == null || end == null) {
            throw new IllegalStateException("Not a complete period: " + this);
        }

        final double millis = end.getTimeInMillis() - begin.getTimeInMillis();
        return (long) Math.ceil(millis / DateUtils.MILLIS_PER_SECOND);
    }

    public Calendar getEnd() {
        return end;
    }

    public Quarter getEndQuarter() {
        return getQuarter(end);
    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder().append(begin).append(end).toHashCode();
    }

    /**
     * Checks whether the given date is included in this period. When the useTime flag is true, the time of the parameter (date) and the time of the
     * begin and end dates of the period are taken into account to compute the result. If the exact begin date/time is included depends on the
     * <code>inclusiveBegin</code> flag; by default, this is true, so begin date/time is considered to be <strong>included</strong> in the period. If
     * the exact end date/time is included depends on the <code>inclusiveEnd</code> flag; which behaves in the same way as the inclusiveBegin flag.
     * Both are true by default.<br>
     * When the useTime flag is false, the dates are truncated to compute the result, and the inclusiveBegin and inclusiveEnd flags are ignored.
     */
    public boolean includes(final Calendar date) {
        if (date == null) {
            return false;
        } else if (begin == null && end == null) {
            return true;
        } else {
            if (useTime) {
                if (begin == null) {
                    return (inclusiveEnd) ? !end.before(date) : date.before(end);
                } else if (end == null) {
                    return (inclusiveBegin) ? !date.before(begin) : begin.before(date);
                } else {
                    final boolean beginOK = (inclusiveBegin) ? !date.before(begin) : begin.before(date);
                    final boolean endOK = (inclusiveEnd) ? !end.before(date) : date.before(end);
                    return beginOK && endOK;
                }
            } else {
                final Calendar tDate = DateUtils.truncate(date, Calendar.DATE);
                Calendar tBegin = begin;
                Calendar tEnd = end;

                if (begin != null) {
                    tBegin = DateUtils.truncate(begin, Calendar.DATE);
                }
                if (end != null) {
                    // If not using time, we'll assume the end of the interval is
                    // the instant before the next day.
                    tEnd = DateHelper.truncateNextDay(end);
                }

                if (tBegin == null) {
                    // it's included if the date is an instant before the next day.
                    return tDate.before(tEnd);
                } else if (tEnd == null) {
                    // it's included if the date is not before the begin
                    return !tDate.before(tBegin);
                } else {
                    return !tDate.before(tBegin) && tDate.before(tEnd);
                }
            }
        }
    }

    public boolean isInclusiveBegin() {
        return inclusiveBegin;
    }

    public boolean isInclusiveEnd() {
        return inclusiveEnd;
    }

    public boolean isUseTime() {
        return useTime;
    }

    public void setBegin(final Calendar begin) {
        this.begin = begin;
    }

    public void setEnd(final Calendar end) {
        this.end = end;
    }

    public void setInclusiveBegin(final boolean inclusiveBegin) {
        this.inclusiveBegin = inclusiveBegin;
    }

    public void setInclusiveEnd(final boolean inclusiveEnd) {
        this.inclusiveEnd = inclusiveEnd;
    }

    public void setUseTime(final boolean useTime) {
        this.useTime = useTime;
    }

    @Override
    public String toString() {
        return "begin: " + FormatObject.formatObject(begin, "<null>") + ", end: "
                + FormatObject.formatObject(end, "<null>");
    }

    public Period useTime() {
        useTime = true;
        return this;
    }

    private Quarter getQuarter(final Calendar cal) {
        final int month = cal.get(Calendar.MONTH);
        int quarter = month / 3;
        quarter++;
        return Quarter.getQuarter(quarter);
    }
}