Package org.jquantlib.time

Source Code of org.jquantlib.time.Date$ISODate

/*
Copyright (C) 2008 Srinivas Hasti

This source code is release under the BSD License.

This file is part of JQuantLib, a free-software/open-source library
for financial quantitative analysts and developers - http://jquantlib.org/

JQuantLib is free software: you can redistribute it and/or modify it
under the terms of the JQuantLib license.  You should have received a
copy of the license along with this program; if not, please email
<jquant-devel@lists.sourceforge.net>. The license is also available online at
<http://www.jquantlib.org/index.php/LICENSE.TXT>.

This program 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 license for more details.

JQuantLib is based on QuantLib. http://quantlib.org/
When applicable, the original copyright notice follows this notice.
*/

package org.jquantlib.time;

import java.util.Formatter;
import java.util.List;
import java.util.Locale;

import org.jquantlib.QL;
import org.jquantlib.Settings;
import org.jquantlib.lang.exceptions.LibraryException;
import org.jquantlib.util.DefaultObservable;
import org.jquantlib.util.Observable;
import org.jquantlib.util.Observer;

/**
* Date class to represent time in days.
*
* @author Richard Gomes
*
*/
public class Date implements Observable, Comparable<Date>, Cloneable {

    private /* @NonNegative */ long serialNumber;

    static final int monthLength[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

    private static final int monthLeapLength[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

    private static final int monthOffset[] = {
        0, 31, 59, 90, 120, 151,        // Jan - Jun
        181, 212, 243, 273, 304, 334,   // Jun - Dec
        365 // used in dayOfMonth to bracket day
    };

    private static final int monthLeapOffset[] = {
        0, 31, 60, 91, 121, 152,        // Jan - Jun
        182, 213, 244, 274, 305, 335,   // Jun - Dec
        366 // used in dayOfMonth to bracket day
    };

    // the list of all December 31st in the preceding year
    // e.g. for 1901 yearOffset[1] is 366, that is, December 31 1900
    private static final int yearOffset[] = {
        // 1900-1909
        0366731, 1096, 1461, 1827, 2192, 2557, 2922, 3288,
        // 1910-1919
         3653, 4018, 4383, 4749, 5114, 5479, 5844, 6210, 6575, 6940,
        // 1920-1929
         7305, 7671, 8036, 8401, 8766, 9132, 9497, 9862,10227,10593,
        // 1930-1939
        10958,11323,11688,12054,12419,12784,13149,13515,13880,14245,
        // 1940-1949
        14610,14976,15341,15706,16071,16437,16802,17167,17532,17898,
        // 1950-1959
        18263,18628,18993,19359,19724,20089,20454,20820,21185,21550,
        // 1960-1969
        21915,22281,22646,23011,23376,23742,24107,24472,24837,25203,
        // 1970-1979
        25568,25933,26298,26664,27029,27394,27759,28125,28490,28855,
        // 1980-1989
        29220,29586,29951,30316,30681,31047,31412,31777,32142,32508,
        // 1990-1999
        32873,33238,33603,33969,34334,34699,35064,35430,35795,36160,
        // 2000-2009
        36525,36891,37256,37621,37986,38352,38717,39082,39447,39813,
        // 2010-2019
        40178,40543,40908,41274,41639,42004,42369,42735,43100,43465,
        // 2020-2029
        43830,44196,44561,44926,45291,45657,46022,46387,46752,47118,
        // 2030-2039
        47483,47848,48213,48579,48944,49309,49674,50040,50405,50770,
        // 2040-2049
        51135,51501,51866,52231,52596,52962,53327,53692,54057,54423,
        // 2050-2059
        54788,55153,55518,55884,56249,56614,56979,57345,57710,58075,
        // 2060-2069
        58440,58806,59171,59536,59901,60267,60632,60997,61362,61728,
        // 2070-2079
        62093,62458,62823,63189,63554,63919,64284,64650,65015,65380,
        // 2080-2089
        65745,66111,66476,66841,67206,67572,67937,68302,68667,69033,
        // 2090-2099
        69398,69763,70128,70494,70859,71224,71589,71955,72320,72685,
        // 2100-2109
        73050,73415,73780,74145,74510,74876,75241,75606,75971,76337,
        // 2110-2119
        76702,77067,77432,77798,78163,78528,78893,79259,79624,79989,
        // 2120-2129
        80354,80720,81085,81450,81815,82181,82546,82911,83276,83642,
        // 2130-2139
        84007,84372,84737,85103,85468,85833,86198,86564,86929,87294,
        // 2140-2149
        87659,88025,88390,88755,89120,89486,89851,90216,90581,90947,
        // 2150-2159
        91312,91677,92042,92408,92773,93138,93503,93869,94234,94599,
        // 2160-2169
        94964,95330,95695,96060,96425,96791,97156,97521,97886,98252,
        // 2170-2179
        98617,98982,99347,99713,100078,100443,100808,101174,101539,101904,
        // 2180-2189
        102269,102635,103000,103365,103730,104096,104461,104826,105191,105557,
        // 2190-2199
        105922,106287,106652,107018,107383,107748,108113,108479,108844,109209,
        // 2200
        109574
    };

    private static final boolean yearIsLeap[] = {
        // 1900 is leap in agreement with Excel's bug
        // 1900 is out of valid date range anyway
        // 1900-1909
         true,false,false,false, true,false,false,false, true,false,
        // 1910-1919
        false,false, true,false,false,false, true,false,false,false,
        // 1920-1929
         true,false,false,false, true,false,false,false, true,false,
        // 1930-1939
        false,false, true,false,false,false, true,false,false,false,
        // 1940-1949
         true,false,false,false, true,false,false,false, true,false,
        // 1950-1959
        false,false, true,false,false,false, true,false,false,false,
        // 1960-1969
         true,false,false,false, true,false,false,false, true,false,
        // 1970-1979
        false,false, true,false,false,false, true,false,false,false,
        // 1980-1989
         true,false,false,false, true,false,false,false, true,false,
        // 1990-1999
        false,false, true,false,false,false, true,false,false,false,
        // 2000-2009
         true,false,false,false, true,false,false,false, true,false,
        // 2010-2019
        false,false, true,false,false,false, true,false,false,false,
        // 2020-2029
         true,false,false,false, true,false,false,false, true,false,
        // 2030-2039
        false,false, true,false,false,false, true,false,false,false,
        // 2040-2049
         true,false,false,false, true,false,false,false, true,false,
        // 2050-2059
        false,false, true,false,false,false, true,false,false,false,
        // 2060-2069
         true,false,false,false, true,false,false,false, true,false,
        // 2070-2079
        false,false, true,false,false,false, true,false,false,false,
        // 2080-2089
         true,false,false,false, true,false,false,false, true,false,
        // 2090-2099
        false,false, true,false,false,false, true,false,false,false,
        // 2100-2109
        false,false,false,false, true,false,false,false, true,false,
        // 2110-2119
        false,false, true,false,false,false, true,false,false,false,
        // 2120-2129
         true,false,false,false, true,false,false,false, true,false,
        // 2130-2139
        false,false, true,false,false,false, true,false,false,false,
        // 2140-2149
         true,false,false,false, true,false,false,false, true,false,
        // 2150-2159
        false,false, true,false,false,false, true,false,false,false,
        // 2160-2169
         true,false,false,false, true,false,false,false, true,false,
        // 2170-2179
        false,false, true,false,false,false, true,false,false,false,
        // 2180-2189
         true,false,false,false, true,false,false,false, true,false,
        // 2190-2199
        false,false, true,false,false,false, true,false,false,false,
        // 2200
        false
    };




    //
    // public constructors
    //

    /**
     *  Default constructor returning a null date.
     */
    public Date() {
        this(0);
    }

    /**
     *  Constructor taking a serial number as given by Applix or Excel.
     *
     * @param serialNumber
     * @return
     */
    public Date(final long serialNumber) {
        this.serialNumber = serialNumber;
    }

    /**
     *  More traditional constructor.
     *
     * @param d
     * @param moreGreeks
     * @param y
     */
    public Date(final int day, final Month month, final int year) {
        this(fromDMY(day, month.value(), year));
    }

    /**
     *  More traditional constructor.
     *
     * @param d
     * @param moreGreeks
     * @param y
     */
    public Date(final int day, final int month, final int year) {
        this(fromDMY(day, month, year));
    }


    //
    // public methods :: inspectors
    //

    public Weekday weekday() /* @ReadOnly */ {
        final int w = (int) (serialNumber % 7);
        return Weekday.valueOf(w == 0L ? 7 : w);
    }

    public int dayOfMonth() /* @ReadOnly */ {
        return dayOfYear() - monthOffset(month().value(), isLeap(year()));
    }

    /**
     * One-based (Jan 1st = 1)
     *
     * @return
     */
    public int dayOfYear() /* @ReadOnly */ {
        return (int) (serialNumber - yearOffset(year()));
    }

    public Month month() /* @ReadOnly */ {
        final int d = dayOfYear(); // dayOfYear is 1 based
        int m = d / 30 + 1;
        final boolean leap = isLeap(year());
        while (d <= monthOffset(m, leap)) {
            --m;
        }
        while (d > monthOffset(m + 1, leap)) {
            ++m;
        }
        return Month.valueOf(m);
    }

    public int year() /* @ReadOnly */ {
        int y = (int) (serialNumber / 365) + 1900;
        if (serialNumber <= yearOffset(y)) {
            --y;
        }
        return y;
    }

    public long serialNumber() /* @ReadOnly */ {
        return this.serialNumber;
    }


    //
    // public methods :: name date algebra
    //

    /**
     *  increments <code>this</code> date by the given number of days
     *
     *  @return this
     */
    //-- Date& operator+=(BigInteger days);
    public Date addAssign(final int days) {
        serialNumber += days;
        checkSerialNumber();
        delegatedObservable.notifyObservers();
        return this;
    }

    /**
     *  increments <code>this</code> date by the given period
     *
     *  @return this
     */
    //-- Date& operator+=(const Period&);
    public Date addAssign(final Period period) {
        serialNumber = advance(this, period.length(), period.units());
        checkSerialNumber();
        delegatedObservable.notifyObservers();
        return this;
    }

    /**
     *  decrement <code>this</code> date by the given number of days
     *
     *  @return this
     */
    //-- Date& operator-=(BigInteger days);
    public Date subAssign(final int days) {
        serialNumber -= days;
        checkSerialNumber();
        delegatedObservable.notifyObservers();
        return this;
    }

    /**
     *  decrements <code>this</code> date by the given period
     *
     *  @return this
     */
    //-- Date& operator-=(const Period&);
    public Date subAssign(final Period period) {
        serialNumber = advance(this, -1 * period.length(), period.units());
        checkSerialNumber();
        delegatedObservable.notifyObservers();
        return this;
    }


    //    /**
    //     *  1-day pre-increment
    //     *
    //     *  @return this
    //     */
    //    //-- Date& operator++();
    //    Date inc();

    /**
     *  1-day post-increment
     *
     *  @return this
     */
    //-- Date operator++(int );
    public Date inc() {
        serialNumber++;
        checkSerialNumber();
        return this;
    }

    //    /**
    //     *  1-day pre-decrement
    //     *
    //     *  @return this
    //     */
    //    //-- Date& operator--();
    //    Date dec();

    /**
     *  1-day post-decrement
     *
     *  @return this
     */
    //-- Date operator--(int );
    public Date dec() {
        serialNumber--;
        checkSerialNumber();
        return this;
    }



    /**
     *  returns a new date incremented by the given number of days
     *
     *  @return a new instance
     */
    //-- Date operator+(BigInteger days) const;
    public Date add(final int days) /* @ReadOnly */ {
        return new Date(this.serialNumber + days);
    }


    /**
     *  returns a new date incremented by the given period
     *
     *  @return a new instance
     */
    //-- Date operator+(const Period&) const;
    public Date add(final Period period) /* @ReadOnly */ {
        return new Date( advance(this, period.length(), period.units()) );
    }

    /**
     *  returns a new date decremented by the given number of days
     *
     *  @return a new instance
     */
    //-- Date operator-(BigInteger days) const;
    public Date sub(final int days) /* @ReadOnly */ {
        return new Date(this.serialNumber - days);
    }

    /**
     *  returns a new date decremented by the given period
     *
     *  @return a new instance
     */
    //-- Date operator-(const Period&) const;
    public Date sub(final Period period) /* @ReadOnly */ {
        return new Date( advance(this, -1 * period.length(), period.units()) );
    }

    /**
     * Difference in days between dates
     */
    public long sub(final Date another) {
        return serialNumber - another.serialNumber;
    }


    //
    // public methods :: relates Date
    //

    //-- bool operator==(const Date&, const Date&);
    public boolean eq(final Date another) {
        return serialNumber == another.serialNumber;
    }

    //-- bool operator!=(const Date&, const Date&);
    public boolean ne(final Date another) {
        return serialNumber != another.serialNumber;
    }

    //-- bool operator<(const Date&, const Date&);
    public boolean lt(final Date another) {
        return serialNumber < another.serialNumber;
    }

    //-- bool operator<=(const Date&, const Date&);
    public boolean le(final Date another) {
        return serialNumber <= another.serialNumber;
    }

    //-- bool operator>(const Date&, const Date&);
    public boolean gt(final Date another) {
        return serialNumber > another.serialNumber;
    }

    //-- bool operator>=(const Date&, const Date&);
    public boolean ge(final Date another) {
        return serialNumber >= another.serialNumber;
    }


    //
    // public methods :: not originally defined in QuantLib/C++
    //

    /**
     * @return true if this Date is <i>null or non-valid date</i>
     */
    public boolean isNull() {
        return this.serialNumber<=0;
    }

    public final boolean isToday() {
        final java.util.Calendar cal = java.util.Calendar.getInstance();
        final int d = cal.get(java.util.Calendar.DAY_OF_MONTH);
        final int m = cal.get(java.util.Calendar.MONTH);
        final int y = cal.get(java.util.Calendar.YEAR);
        return serialNumber == fromDMY(d, m+1, y);
    }


    //
    // public methods :: provide access to inner classes
    //

    /**
     * Provides access to a long date formatter.
     * <p>
     * The only useful method is <code>toString()</code> which returns a date formated as Mon, dd yyyy
     *
     * @return
     */
    public Object longDate() {
        return new LongDate();
    }

    /**
     * Provides access to a long date formatter.
     * <p>
     * The only useful method is <code>toString()</code> which returns a date formated as mm/dd/yyyy
     *
     * @return
     */
    public Object shortDate() {
        return new ShortDate();
    }

    /**
     * Provides access to a ISO date formatter.
     * <p>
     * The only useful method is <code>toString()</code> which returns a date formated as yyyy-mm-dd
     *
     * @return
     */
    public Object isoDate() {
        return new ISODate();
    }


    //
    // implements Comparable<Date>
    //

    @Override
    public int compareTo(final Date o) {
        if (this.equals(o))
            return 0;
        if (this.le(o))
            return -1;
        return 1;
    }


    //
    // implements Observable
    //

    /**
     * Implements multiple inheritance via delegate pattern to an inner class
     */
    private final Observable delegatedObservable = new DefaultObservable(this);

    public final void addObserver(final Observer observer) {
        delegatedObservable.addObserver(observer);
    }

    public final int countObservers() {
        return delegatedObservable.countObservers();
    }

    public final void deleteObserver(final Observer observer) {
        delegatedObservable.deleteObserver(observer);
    }

    public final void notifyObservers() {
        delegatedObservable.notifyObservers();
    }

    public final void notifyObservers(final Object arg) {
        delegatedObservable.notifyObservers(arg);
    }

    public final void deleteObservers() {
        delegatedObservable.deleteObservers();
    }

    public final List<Observer> getObservers() {
        return delegatedObservable.getObservers();
    }


    //
    // Overrides Object
    //

    @Override
    public int hashCode() {
        return (int) this.serialNumber;
    }

    @Override
    public boolean equals(final Object anObject) {
        if (anObject==null)
            return false;
        if (!(anObject instanceof Date))
            return false;
        return eq((Date)anObject);
    }

    @Override
    //-- std::ostream& operator<<(std::ostream&, const Date&);
    public String toString() {
        return longDate().toString();
    }


    //
    // implements Cloneable
    //

    @Override
    public Date clone() {
        try {
            return (Date) super.clone();
        } catch (final CloneNotSupportedException e) {
            throw new LibraryException(e);
        }
    }


    //
    // protected methods
    //
    // These methods were not declared in QuantLib/C++
    //


    /**
     * Assigns the today's date to <code>this</code> instance
     *
     * @note Does not trigger notifications
     *
     * @return this instance
     *
     * @see
     */
    //TODO: consider @PackagePrivate
    protected final long todaysSerialNumber() {
        final java.util.Calendar cal = java.util.Calendar.getInstance();
        final int d = cal.get(java.util.Calendar.DAY_OF_MONTH);
        final int m = cal.get(java.util.Calendar.MONTH);
        final int y = cal.get(java.util.Calendar.YEAR);
        return fromDMY(d, m+1, y);
    }


    /**
     * Assigns a new serialNumber to <code>this</code> instance.
     *
     * @note Does not trigger notifications
     *
     * @return this instance
     *
     * @see inner class DateProxy in {@link Settings}
     */
    //TODO: consider @PackagePrivate
    protected final Date assign(final long serialNumber) {
        this.serialNumber = serialNumber;
        return this;
    }



    //
    // private methods
    //

    private void checkSerialNumber() {
        QL.ensure(serialNumber >= minimumSerialNumber() && serialNumber <= maximumSerialNumber(),
        "Date's serial number is outside allowed range"); // QA:[RG]::verified // TODO: message
    }


    private long advance(final Date date, final int n, final TimeUnit units) {
        switch (units) {
        case Days:
            return (n + date.serialNumber);
        case Weeks:
            return (7 * n + date.serialNumber);
        case Months: {
            int d = date.dayOfMonth();
            int m = date.month().value() + n;
            int y = date.year();
            while (m > 12) {
                m -= 12;
                y += 1;
            }
            while (m < 1) {
                m += 12;
                y -= 1;
            }

            QL.ensure(y >= 1900 && y <= 2199 , "year out of bounds. It must be in [1901,2199]"); // QA:[RG]::verified // TODO: message
            final int length = monthLength(m, isLeap(y));
            if (d > length) {
                d = length;
            }
            final long result = fromDMY(d, m, y);
            //QL.debug("{}", result);
            return result;
        }
        case Years: {
            int d = date.dayOfMonth();
            final int m = date.month().value();
            final int y = date.year() + n;

            QL.ensure(y >= 1900 && y <= 2199 , "year out of bounds. It must be in [1901,2199]"); // QA:[RG]::verified // TODO: message
            if (d == 29 && m == Month.February.value() && !isLeap(y)) {
                d = 28;
            }

            final long result = fromDMY(d, m, y);
            //QL.debug("{}", result);
            return result;
        }
        default:
            throw new LibraryException("undefined time units"); // QA:[RG]::verified // TODO: message
        }
    }


    //
    // public static methods
    //

    /**
     * Today's date.
     *
     * @return a new instance
     */
    public static final Date todaysDate() {
        final java.util.Calendar cal = java.util.Calendar.getInstance();
        final int d = cal.get(java.util.Calendar.DAY_OF_MONTH);
        final int m = cal.get(java.util.Calendar.MONTH);
        final int y = cal.get(java.util.Calendar.YEAR);
        return new Date(d, m + 1, y);
    }

    /**
     * Earliest allowed date
     *
     * @return a new instance
     */
    public static final Date minDate() {
        return new Date(minimumSerialNumber());
    }

    /**
     * Latest allowed date
     *
     * @return a new instance
     */
    public static final Date maxDate() {
        return new Date(maximumSerialNumber());
    }

    /**
     * Whether the given year is a leap one
     *
     * @param y
     * @return
     */
    public static final boolean isLeap(final int year) {
        return yearIsLeap[year - 1900];
    }

    /**
     * Last day of the month to which the given date belongs
     *
     * @return a new instance
     */
    public static final Date endOfMonth(final Date d) {
        final int m = d.month().value();
        final int y = d.year();
        return new Date(monthLength(m, isLeap(y)), m, y);
    }

    /**
     * Whether a date is the last day of its month
     *
     * @return
     */
    public static final boolean isEndOfMonth(final Date d) {
        return (d.dayOfMonth() == monthLength(d.month().value(), isLeap(d.year())));
    }

    /**
     * Next given weekday following or equal to the given date
     * <p>
     * E.g., the Friday following Tuesday, JANUARY 15th, 2002 was JANUARY 18th, 2002.
     *
     * @see http://www.cpearson.com/excel/DateTimeWS.htm
     *
     * @return a new instance
     */
    public static final Date nextWeekday(final Date d, final Weekday w) {
        final int wd = d.weekday().value();
        final int dow = w.value();
        return new Date(d.serialNumber + (wd > dow ? 7 : 0) - wd + dow);
    }

    /**
     * n-th given weekday in the given month and year
     * <p>
     * E.g., the 4th Thursday of March, 1998 was March 26th, 1998.
     *
     * @see http://www.cpearson.com/excel/DateTimeWS.htm
     *
     * @param n
     * @param w
     * @param m
     * @param y
     *
     * @return a new instance
     */
    public static final Date nthWeekday(final int n, final Weekday w, final Month m, final int y) {
        return nthWeekday(n, w, m.value(), y);
    }

    /**
     * Returns a new Date which is the n-th week day of a certain month/year
     *
     * @param nth is the desired week
     * @param dayOfWeek is the desired week day
     * @param month is the desired month
     * @param year is the desired year
     *
     * @return a new instance
     */
    public static final Date nthWeekday(final int nth, final Weekday dayOfWeek, final int month, final int year) {
        QL.require(nth > 0, "zeroth day of week in a given (month, year) is undefined"); // QA:[RG]::verified //TODO: message
        QL.require(nth < 6, "no more than 5 weekday in a given (month, year)"); // QA:[RG]::verified //TODO: message
        final int m = month;
        final int y = year;
        final int dow = dayOfWeek.value();
        // FIXME: code review
        final int first = new Date(1, m, y).weekday().value();
        final int skip = nth - (dow >= first ? 1 : 0);
        return new Date(1 + dow - first + skip * 7, m, y);
    }

    /**
     * Return the minimum Date in a range.
     */
    public static Date min(final Date... t) {
        QL.require(t!=null , "argument cannot be null"); // QA:[RG]::verified // TODO: message
        if (t.length == 0)
            return new Date();
        else {
            Date min = t[0];
            for (int i=1; i<t.length; i++) {
                final Date curr = t[i];
                if (curr.lt(min)) {
                    min = curr;
                }
            }
            return min;
        }
    }

    /**
     * Return the maximum Date in a range.
     */
    public static Date max(final Date... t) {
        QL.require(t!=null , "argument cannot be null"); // QA:[RG]::verified // TODO: message
        if (t.length == 0)
            return new Date();
        else {
            Date max = t[0];
            for (int i=1; i<t.length; i++) {
                final Date curr = t[i];
                if (curr.gt(max)) {
                    max = curr;
                }
            }
            return max;
        }
    }


    //
    // private static methods
    //

    static private long minimumSerialNumber() {
        return 367;       // Jan 1st, 1901
    }

    static private long maximumSerialNumber() {
        return 109574;    // Dec 31st, 2199
    }

    /**
     * This method is intended to calculate the integer value of a (day, month, year)
     *
     * @param d is the day as a number
     * @param m is the month as a number
     * @param y is the year as a number
     * @return
     */
    private static final long fromDMY(final int d, final int m, final int y) {
        QL.require(y >= 1900 && y <= 2199 , "year out of bound. It must be in [1901,2199]"); // QA:[RG]::verified // TODO: message
        QL.require(m > 0 && m < 13 , "month outside JANUARY-December range [1,12]"); // QA:[RG]::verified // TODO: message
        final boolean leap = isLeap(y);
        final int len = monthLength(m, leap);
        final int offset = monthOffset(m, leap);
        QL.ensure(d > 0 && d <= len , "day outside month day-range"); // QA:[RG]::verified // TODO: message
        final long result = d + offset + yearOffset(y);
        return result;
    }

    /**
     * Returns the length of a certain month
     *
     * @param m is the desired month, as a number
     * @param leapYear if <code>true</code> means a leap year
     * @return the length of a certain month
     */
    private static final int monthLength(final int m, final boolean leapYear) {
        return (leapYear ? monthLeapLength[m - 1] : monthLength[m - 1]);
    }

    /**
     * Returns the offset of a certain month
     *
     * @param m is the desired month, as a number. If you specify 13, you will get the number of days of a year
     * @param leapYear if <code>true</code> means a leap year
     * @return the offset of a certain month or the length of an year
     * @see DefaultDate#yearOffset
     */
    private static final int monthOffset(final int m, final boolean leapYear) {
        return (leapYear ? monthLeapOffset[m - 1] : monthOffset[m - 1]);
    }

    /**
     * Returns the offset of a certain year
     *
     * @param y
     *            is the desired year
     * @return the offset of a certain year
     */
    private static final long yearOffset(final int year) {
        return yearOffset[year - 1900];
    }

  /**
   * This method is equivalent to std:lower_bound function
   * Returns an index pointing to the first element in the ordered collection is equal or greater than passed value
   *
   * @param dates order collection in ascending order
   * @param value Date to be compared
   * @return index to element which is >= passed value
   */
  public static int lowerBound(final List<Date> dates, final Date value) {
        int len = dates.size();
        int from = 0;
        int half;
        int middle;

        while (len > 0) {
            half = len >> 1;
            middle = from;
            middle = middle + half;

            if (value.compareTo(dates.get(middle)) == 1) { // value > 1
                from = middle;
                from++;
                len = len - half - 1;
            } else {
                len = half;
            }
        }
        return from;
     }

  /**
   * This method is equivalent to C++ sdt:upper_bound function
   * Returns an index pointing to the first element in the ordered collection which is greater than passed value

   * @param dates order collection in ascending order
   * @param value Date to be compared
   * @return index to element which is > passed value
   */
  public static int upperBound(final List<Date> dates, final Date value) {

        int len = dates.size();
        int from = 0;
        int half;
        int middle;

        while (len > 0) {
            half = len >> 1;
            middle = from;
            middle = middle + half;
            if (value.compareTo(dates.get(middle)) == -1) {
                len = half;
            } else {
                from = middle;
                from++;
                len = len - half - 1;
            }
        }
        return from;
  }

    //
    // public inner classes
    //

    /**
     * This class provides a long output formatter, e.g: September 18, 2009
     */
    private final class LongDate {
        @Override
        public final String toString() {
            if ( isNull() )
                return "null date";
            else {
                final StringBuilder sb = new StringBuilder();
                final Formatter formatter = new Formatter(sb, Locale.US);
                formatter.format("%s %d, %d", month(), dayOfMonth(), year());
                return sb.toString();
            }
        }
    }


    /**
     * This class provides a short output formatter, e.g: 09/18/2009
     */
    private final class ShortDate {
        @Override
        public final String toString() {
            if ( isNull() )
                return "null date";
            else {
                final StringBuilder sb = new StringBuilder();
                final Formatter formatter = new Formatter(sb, Locale.US);
                formatter.format("%02d/%02d/%4d", month().value(), dayOfMonth(), year());
                return sb.toString();
            }
        }
    }

    /**
     * This class provides an ISO date output formatter, e.g: 2009-09-18
     */
    private final class ISODate {
        @Override
        public final String toString() {
            if ( isNull() )
                return "null date";
            else {
                final StringBuilder sb = new StringBuilder();
                final Formatter formatter = new Formatter(sb, Locale.US);
                formatter.format("%04d-%02d-%02d", year(), month().value(), dayOfMonth());
                return sb.toString();
            }
        }
    }

}
TOP

Related Classes of org.jquantlib.time.Date$ISODate

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.
y>