kr.debop4j.timeperiod.calendars.DateDiff.java Source code

Java tutorial

Introduction

Here is the source code for kr.debop4j.timeperiod.calendars.DateDiff.java

Source

/*
 * Copyright 2011-2013 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package kr.debop4j.timeperiod.calendars;

import com.google.common.base.Objects;
import kr.debop4j.core.ValueObjectBase;
import kr.debop4j.core.tools.HashTool;
import kr.debop4j.timeperiod.ITimeCalendar;
import kr.debop4j.timeperiod.Quarter;
import kr.debop4j.timeperiod.TimeCalendar;
import kr.debop4j.timeperiod.tools.TimeSpec;
import kr.debop4j.timeperiod.tools.Times;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.joda.time.Duration;

import java.io.Serializable;

/**
 *  ? ? ?? {@link ITimeCalendar},  ?  ? .
 *
 * @author ? sunghyouk.bae@gmail.com
 * @since 13. 5. 20.  5:16
 */
@Slf4j
public class DateDiff extends ValueObjectBase implements Serializable {

    @Getter
    private final DateTime start;
    @Getter
    private final DateTime end;
    @Getter
    private final Duration difference;
    @Getter
    private final ITimeCalendar timeCalendar;

    @Getter(lazy = true)
    private final int years = calcYears();
    @Getter(lazy = true)
    private final int quarters = calcQuarters();
    @Getter(lazy = true)
    private final int months = calcMonths();
    @Getter(lazy = true)
    private final int weeks = calcWeeks();
    @Getter(lazy = true)
    private final int days = (int) Math.round(roundEx(getDifference().getStandardDays()));
    @Getter(lazy = true)
    private final int hours = (int) Math.round(roundEx(getDifference().getStandardHours()));
    @Getter(lazy = true)
    private final int minutes = (int) Math.round(roundEx(getDifference().getStandardMinutes()));
    @Getter(lazy = true)
    private final int seconds = (int) Math.round(roundEx(getDifference().getStandardSeconds()));

    @Getter(lazy = true)
    private final int elapsedYears = getYears();
    @Getter(lazy = true)
    private final int elapsedQuarters = getQuarters();
    @Getter(lazy = true)
    private final int elapsedMonths = getMonths() - getElapsedYears() * TimeSpec.MonthsPerYear;

    @Getter(lazy = true)
    private final DateTime elapsedStartDays = getStart().plusYears(getElapsedYears())
            .plusMonths(getElapsedMonths());
    @Getter(lazy = true)
    private final int elapsedDays = (int) new Duration(getElapsedStartDays(), getEnd()).getStandardDays();

    @Getter(lazy = true)
    private final DateTime elapsedStartHours = getStart().plusYears(getElapsedYears())
            .plusMonths(getElapsedMonths()).plusDays(getElapsedDays());
    @Getter(lazy = true)
    private final int elapsedHours = (int) new Duration(getElapsedStartHours(), getEnd()).getStandardHours();

    @Getter(lazy = true)
    private final DateTime elapsedStartMinutes = getStart().plusYears(getElapsedYears())
            .plusMonths(getElapsedMonths()).plusDays(getElapsedDays()).plusHours(getElapsedHours());
    @Getter(lazy = true)
    private final int elapsedMinutes = (int) new Duration(getElapsedStartMinutes(), getEnd()).getStandardMinutes();

    @Getter(lazy = true)
    private final DateTime elapsedStartSeconds = getStart().plusYears(getElapsedYears())
            .plusMonths(getElapsedMonths()).plusDays(getElapsedDays()).plusHours(getElapsedHours())
            .plusMinutes(getElapsedMinutes());
    @Getter(lazy = true)
    private final int elapsedSeconds = (int) new Duration(getElapsedStartSeconds(), getEnd()).getStandardSeconds();

    public DateDiff(DateTime moment) {
        this(moment, Times.now());
    }

    public DateDiff(DateTime moment, ITimeCalendar timeCalendar) {
        this(moment, Times.now(), timeCalendar);
    }

    public DateDiff(DateTime start, DateTime end) {
        this(start, end, TimeCalendar.getDefault());
    }

    public DateDiff(DateTime start, DateTime end, ITimeCalendar timeCalendar) {

        this.start = start;
        this.end = end;
        this.difference = new Duration(start, end);
        this.timeCalendar = (timeCalendar != null) ? timeCalendar : TimeCalendar.getDefault();
    }

    public boolean isEmpty() {
        return difference.isEqual(Duration.ZERO);
    }

    public int getStartYear() {
        return timeCalendar.getYear(getStart());
    }

    public int getEndYear() {
        return timeCalendar.getYear(getEnd());
    }

    public int getStartMonthOfYear() {
        return timeCalendar.getMonthOfYear(getStart());
    }

    public int getEndMonthOfYear() {
        return timeCalendar.getMonthOfYear(getEnd());
    }

    private int calcYears() {
        if (Objects.equal(start, end))
            return 0;

        int compareDay = Math.min(end.getDayOfMonth(),
                timeCalendar.getDaysInMonth(getStartYear(), getEndMonthOfYear()));
        DateTime compareDate = new DateTime(getStartYear(), getEndMonthOfYear(), compareDay, 0, 0)
                .plusMillis(end.getMillisOfDay());

        if (end.compareTo(start) > 0) {
            if (compareDate.compareTo(start) < 0)
                compareDate = compareDate.plusYears(1);
        } else if (compareDate.compareTo(start) > 0) {
            compareDate = compareDate.plusYears(-1);
        }

        return getEndYear() - timeCalendar.getYear(compareDate);
    }

    private int calcQuarters() {
        if (Objects.equal(start, end))
            return 0;

        int year1 = Times.getYearOf(getStartYear(), getStartMonthOfYear());
        Quarter quarter1 = Times.getQuarterOfMonth(getStartMonthOfYear());

        int year2 = Times.getYearOf(getEndYear(), getEndMonthOfYear());
        Quarter quarter2 = Times.getQuarterOfMonth(getEndMonthOfYear());

        return (year2 * TimeSpec.QuartersPerYear + quarter2.getValue())
                - (year1 * TimeSpec.QuartersPerYear + quarter1.getValue());
    }

    private int calcMonths() {
        if (Objects.equal(start, end))
            return 0;

        int compareDay = Math.min(end.getDayOfMonth(),
                timeCalendar.getDaysInMonth(getStartYear(), getStartMonthOfYear()));
        DateTime compareDate = Times.asDate(getStartYear(), getStartMonthOfYear(), compareDay)
                .plusMillis(end.getMillisOfDay());

        // log.trace("compareDay=[{}], compareDate=[{}]", compareDay, compareDate);

        if (end.compareTo(start) > 0) {
            if (compareDate.compareTo(start) < 0)
                compareDate = compareDate.plusMonths(1);
        } else if (compareDate.compareTo(start) > 0) {
            compareDate = compareDate.plusMonths(-1);
        }

        int month = (getEndYear() * TimeSpec.MonthsPerYear + getEndMonthOfYear())
                - (timeCalendar.getYear(compareDate) * TimeSpec.MonthsPerYear
                        + timeCalendar.getMonthOfYear(compareDate));

        // log.trace("calc month=[{}]", month);

        return month;
    }

    private int calcWeeks() {
        if (Objects.equal(start, end))
            return 0;

        DateTime week1 = Times.getStartOfWeek(start, timeCalendar.getFirstDayOfWeek());
        DateTime week2 = Times.getStartOfWeek(end, timeCalendar.getFirstDayOfWeek());

        DateDiff.log.trace("week1=[{}], week2=[{}]", week1, week2);

        if (Objects.equal(week1, week2))
            return 0;

        return (int) (new Duration(week1, week2).getStandardDays() / TimeSpec.DaysPerWeek);
    }

    @Override
    public int hashCode() {
        return HashTool.compute(start, end, difference, timeCalendar);
    }

    @Override
    protected Objects.ToStringHelper buildStringHelper() {
        return super.buildStringHelper().add("start", start).add("end", end).add("difference", difference)
                .add("timeCalendar", timeCalendar);
    }

    private static double roundEx(double number) {
        return (number >= 0.0) ? Math.round(number) : -Math.round(-number);
    }

    private static final long serialVersionUID = 3415272759108830763L;
}