All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.integratedmodelling.engine.time.literals.TimeValue Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 *  Copyright (C) 2007, 2015:
 *  
 *    - Ferdinando Villa 
 *    - integratedmodelling.org
 *    - any other authors listed in @author annotations
 *
 *    All rights reserved. This file is part of the k.LAB software suite,
 *    meant to enable modular, collaborative, integrated 
 *    development of interoperable data and model components. For
 *    details, see http://integratedmodelling.org.
 *    
 *    This program is free software; you can redistribute it and/or
 *    modify it under the terms of the Affero General Public License 
 *    Version 3 or any later version.
 *
 *    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
 *    Affero General Public License for more details.
 *  
 *     You should have received a copy of the Affero General Public License
 *     along with this program; if not, write to the Free Software
 *     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *     The license is also available at: https://www.gnu.org/licenses/agpl.html
 *******************************************************************************/
package org.integratedmodelling.engine.time.literals;

import org.integratedmodelling.api.lang.IParseable;
import org.integratedmodelling.api.time.ITimeInstant;
import org.integratedmodelling.common.time.TemporalPrecision;
import org.integratedmodelling.exceptions.KlabException;
import org.integratedmodelling.exceptions.KlabRuntimeException;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

/**
 * A parsed literal representing one point in time, parsed from a string that satisfies the JODA Time parser.
 * The typical input is an ISO8601 date/time string, such as "2006-12-13T21:39:45.618-08:00". Linked to the
 * DateTimeValue type as an extended literal. The same syntax can be used to define an entire time observation
 * of type TemporalRecord using a literal.
 *
 * TODO parser should support yyyy, mm-yyyy and dd-mm-yyyy by simple pattern recognition, and set
 * correspondent PRECISION values (YEAR, MONTH, DAY). Whatever doesn't match should be given to Yoda for ISO
 * parsing and assumed MILLISECOND precision.
 *
 * @author Ferdinando Villa
 *
 */
public class TimeValue implements ITimeInstant, IParseable {

    int precision = TemporalPrecision.MILLISECOND;

    public static String matchYear = "[0-2][0-9][0-9][0-9]";

    public static String matchMonthYear = "[0-1][0-9]-[0-2][0-9][0-9][0-9]";

    public static String matchDayMonthYear = "[0-3][0-9]-[0-1][0-9]-[0-2][0-9][0-9][0-9]";

    DateTime value;

    /* set to "now" */
    public TimeValue() throws KlabException {
        value = new DateTime();
    }

    public TimeValue(DateTime date) {
        value = date;
    }

    public void parse(String s) {
        try {

            if (s.matches(matchYear)) {
                DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyy");
                value = fmt.parseDateTime(s);
                precision = TemporalPrecision.YEAR;
            } else if (s.matches(matchMonthYear)) {
                DateTimeFormatter fmt = DateTimeFormat.forPattern("MM-yyyy");
                value = fmt.parseDateTime(s);
                precision = TemporalPrecision.MONTH;
            } else if (s.matches(matchDayMonthYear)) {
                DateTimeFormatter fmt = DateTimeFormat.forPattern("dd-MM-yyyy");
                value = fmt.parseDateTime(s);
                precision = TemporalPrecision.DAY;
            } else {
                value = new DateTime(s);
            }
        } catch (Exception e) {
            throw new KlabRuntimeException(e);
        }
    }

    public TimeValue(String s) {
        parse(s);
    }

    public TimeValue(long d) {
        this(new DateTime(d));
    }

    public int getValuesCount() {
        return 1;
    }

    public DateTime getTimeData() {
        return value;
    }

    public int getPrecision() {
        return precision;
    }

    /**
     * Compare at the resolution intrinsic in the date. Code should read easily.
     *
     * TODO no normalization of time zones is done - we should ensure both TZ are the same before comparing.
     *
     * @param v1
     * @return true if comparable
     */
    public boolean comparable(TimeValue v1) {

        if (precision == TemporalPrecision.YEAR) {
            return value.year().getMaximumValue() == v1.value.year().getMaximumValue();

        } else if (precision == TemporalPrecision.MONTH) {

            return value.year().equals(v1.value.year()) && value.monthOfYear().equals(v1.value.monthOfYear());

        } else if (precision == TemporalPrecision.DAY) {
            return value.year().equals(v1.value.year()) && value.monthOfYear().equals(v1.value.monthOfYear())
                    && value.dayOfMonth().equals(v1.value.dayOfMonth());
        }

        return v1.value.equals(value);
    }

    @Override
    public String toString() {

        if (precision == TemporalPrecision.YEAR) {
            return value.toString("yyyy");
        } else if (precision == TemporalPrecision.MONTH) {
            return value.toString("MM-yyyy");
        } else if (precision == TemporalPrecision.DAY) {
            return value.toString("dd-MM-yyyy");
        }
        return value.toString();
    }

    public boolean isIdentical(TimeValue obj) {

        return (precision == obj.precision) && value.equals(obj.value);

    }

    public TimeValue leastPrecise(TimeValue v) {

        if (comparable(v)) {
            return new Integer(precision).compareTo(v.precision) > 0 ? this : v;
        }
        return null;
    }

    public TimeValue mostPrecise(TimeValue v) {

        if (comparable(v)) {
            return new Integer(precision).compareTo(v.precision) > 0 ? v : this;
        }
        return null;
    }

    public int getDayOfMonth() {
        return value.getDayOfMonth();
    }

    public int getJulianDay() {
        return value.getDayOfYear();
    }

    public int getMonth() {
        return value.getMonthOfYear();
    }

    public int getYear() {
        return value.getYear();
    }

    public int getNDaysInMonth() {
        return value.dayOfMonth().withMaximumValue().getDayOfMonth();
    }

    public int getNDaysInYear() {
        return value.dayOfYear().withMaximumValue().getDayOfYear();
    }

    @Override
    public boolean equals(Object other) {

        boolean ret = (other instanceof TimeValue);
        if (ret) {
            ret = precision == ((TimeValue) other).precision;
        }
        if (ret) {
            ret = value.equals(((TimeValue) other).value);
        }
        return ret;
    }

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

    /**
     * Return the end of the implied extent according to the precision in the generating string.
     *
     * @return end of implied extent
     */
    public TimeValue getEndOfImpliedExtent() {

        TimeValue end = null;
        switch (precision) {

        case TemporalPrecision.MILLISECOND:
            end = new TimeValue(value.plus(1));
            break;
        case TemporalPrecision.SECOND:
            end = new TimeValue(value.plusSeconds(1));
            break;
        case TemporalPrecision.MINUTE:
            end = new TimeValue(value.plusMinutes(1));
            break;
        case TemporalPrecision.HOUR:
            end = new TimeValue(value.plusHours(1));
            break;
        case TemporalPrecision.DAY:
            end = new TimeValue(value.plusDays(1));
            break;
        case TemporalPrecision.MONTH:
            end = new TimeValue(value.plusMonths(1));
            break;
        case TemporalPrecision.YEAR:
            end = new TimeValue(value.plusYears(1));
            break;
        }

        return end;

    }

    // @Override
    // public boolean is(Object object) {
    // // TODO Auto-generated method stub
    // return false;
    // }

    @Override
    public String asText() {
        // TODO luke did this - seemed straightforward - double check for correctness
        return value.toString();
    }

    public int compareTo(TimeValue other) {
        return this.value.compareTo(other.value);
    }

    /**
     * Overridden DateTime.compareTo() function. Extracting milliseconds from two DateTime/ITimeInstant objects is
     * probably more efficient than creating a new DateTime from other.getMillis() just for one comparison.
     */
    @Override
    public int compareTo(ITimeInstant other) {
        long millis = value.getMillis();
        long otherMillis = other.getMillis();
        if (millis == otherMillis) {
            return 0;
        }
        if (millis < otherMillis) {
            return -1;
        }
        return 1;
    }

    @Override
    public long getMillis() {
        return value.getMillis();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy