Package client.net.sf.saxon.ce.value

Source Code of client.net.sf.saxon.ce.value.GDateValue

package client.net.sf.saxon.ce.value;

import client.net.sf.saxon.ce.expr.XPathContext;
import client.net.sf.saxon.ce.expr.sort.ComparisonKey;
import client.net.sf.saxon.ce.functions.Component;
import client.net.sf.saxon.ce.om.StandardNames;
import client.net.sf.saxon.ce.trans.Err;
import client.net.sf.saxon.ce.trans.NoDynamicContextException;
import client.net.sf.saxon.ce.trans.XPathException;
import client.net.sf.saxon.ce.type.ConversionResult;
import client.net.sf.saxon.ce.type.ValidationFailure;
import com.google.gwt.regexp.shared.MatchResult;
import com.google.gwt.regexp.shared.RegExp;


/**
* Abstract superclass for the primitive types containing date components: xs:date, xs:gYear,
* xs:gYearMonth, xs:gMonth, xs:gMonthDay, xs:gDay
*/
public abstract class GDateValue extends CalendarValue {
    protected int year;         // unlike the lexical representation, includes a year zero
    protected int month;
    protected int day;
    /**
     * Test whether a candidate date is actually a valid date in the proleptic Gregorian calendar
     */

    protected static byte[] daysPerMonth = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    protected static final short[] monthData = {306, 337, 0, 31, 61, 92, 122, 153, 184, 214, 245, 275};

    /**
     * Get the year component of the date (in local form)
     * @return the year component, as represented internally (allowing a year zero)
     */

    public int getYear() {
        return year;
    }

    /**
     * Get the month component of the date (in local form)
     * @return the month component (1-12)
     */

    public int getMonth() {
        return month;
    }

    /**
     * Get the day component of the date (in local form)
     * @return the day component (1-31)
     */

    public int getDay() {
        return day;
    }

    private static RegExp datePattern =
            RegExp.compile("\\-?([0-9]+)-([0-9][0-9])-([0-9][0-9])([-+Z].*)?");

    protected static ConversionResult setLexicalValue(GDateValue dt, CharSequence s) {
        String str = s.toString();
        MatchResult match = datePattern.exec(str);
        if (match == null) {
            return badDate("wrong format", str);
        }
        dt.year = DurationValue.simpleInteger(match.getGroup(1));
        if (str.startsWith("-")) {
          dt.year = dt.year - 1; // no year zero in lexical space for XSD 1.0 - so -1 becomes 0 and -2 becomes -1 etc.
            dt.year = -dt.year;
        }
        dt.month = DurationValue.simpleInteger(match.getGroup(2));
        dt.day = DurationValue.simpleInteger(match.getGroup(3));
        String tz = match.getGroup(4);
        int tzmin = parseTimezone(tz);
        if (tzmin == BAD_TIMEZONE) {
            return badDate("invalid timezone", str);
        }
        dt.setTimezoneInMinutes(tzmin);
        if (dt.year == 0) {
            return badDate("year zero", str);
        }
        // Check that this is a valid calendar date
        if (!DateValue.isValidDate(dt.year, dt.month, dt.day)) {
            return badDate("non-existent date", s);
        }
        return dt;
    }


    private static ValidationFailure badDate(String msg, CharSequence value) {
        ValidationFailure err = new ValidationFailure(
                "Invalid date " + Err.wrap(value, Err.VALUE) + " (" + msg + ")");
        err.setErrorCode("FORG0001");
        return err;
    }

    /**
     * Determine whether a given date is valid
     * @param year the year (permitting year zero)
     * @param month the month (1-12)
     * @param day the day (1-31)
     * @return true if this is a valid date
     */

    public static boolean isValidDate(int year, int month, int day) {
        return month > 0 && month <= 12 && day > 0 && day <= daysPerMonth[month - 1]
                || month == 2 && day == 29 && isLeapYear(year);
    }

    /**
     * Test whether a year is a leap year
     * @param year the year (permitting year zero)
     * @return true if the supplied year is a leap year
     */

    public static boolean isLeapYear(int year) {
        return (year % 4 == 0) && !(year % 100 == 0 && !(year % 400 == 0));
    }

    /**
     * The equals() methods on atomic values is defined to follow the semantics of eq when applied
     * to two atomic values. When the other operand is not an atomic value, the result is undefined
     * (may be false, may be an exception). When the other operand is an atomic value that cannot be
     * compared with this one, the method returns false.
     * <p/>
     * <p>The hashCode() method is consistent with equals().</p>
     *
     * <p>This implementation performs a context-free comparison: it fails with ClassCastException
     * if one value has a timezone and the other does not.</p>
     *
     * @param o the other value
     * @return true if the other operand is an atomic value and the two values are equal as defined
     *         by the XPath eq operator
     * @throws ClassCastException if the values are not comparable
     */

    public boolean equals(Object o) {
        if (o instanceof GDateValue) {
            GDateValue gdv = (GDateValue)o;
            return getPrimitiveType() == gdv.getPrimitiveType() && toDateTime().equals(gdv.toDateTime());
        } else {
            return false;
        }
    }

    public int hashCode() {
        return DateTimeValue.hashCode(year, month, day, 12, 0, 0, 0, getTimezoneInMinutes());
    }

    /**
     * Compare this value to another value of the same type, using the supplied context object
     * to get the implicit timezone if required. This method implements the XPath comparison semantics.
     * @param other the value to be compared
     * @param context the XPath dynamic evaluation context (needed only to get the implicit timezone)
     * @return -1 if this value is less, 0 if equal, +1 if greater
     */

    public int compareTo(CalendarValue other, XPathContext context) throws NoDynamicContextException {
        if (getPrimitiveType() != other.getPrimitiveType()) {
            throw new ClassCastException("Cannot compare dates of different types");
            // covers, for example, comparing a gYear to a gYearMonth
        }
        GDateValue v2 = (GDateValue)other;
        if (getTimezoneInMinutes() == other.getTimezoneInMinutes()) {
            // both values are in the same timezone (explicitly or implicitly)
            if (year != v2.year) {
                return IntegerValue.signum(year - v2.year);
            }
            if (month != v2.month) {
                return IntegerValue.signum(month - v2.month);
            }
            if (day != v2.day) {
                return IntegerValue.signum(day - v2.day);
            }
            return 0;
        }
        return toDateTime().compareTo(other.toDateTime(), context);
    }

    /**
     * Convert to DateTime.
     * @return the starting instant of the GDateValue (with the same timezone)
     */

    public DateTimeValue toDateTime() {
        return new DateTimeValue(year, month, day, (byte)0, (byte)0, (byte)0, 0, getTimezoneInMinutes());
    }


    /**
    * Get a component of the value. Returns null if the timezone component is
    * requested and is not present.
    */

    public AtomicValue getComponent(int component) throws XPathException {
        switch (component) {
        case Component.YEAR_ALLOWING_ZERO:
            return IntegerValue.makeIntegerValue(year);
        case Component.YEAR:
            return IntegerValue.makeIntegerValue(year > 0 ? year : year-1);
        case Component.MONTH:
            return IntegerValue.makeIntegerValue(month);
        case Component.DAY:
            return IntegerValue.makeIntegerValue(day);
        case Component.TIMEZONE:
            if (hasTimezone()) {
                return DayTimeDurationValue.fromMilliseconds(60000L * getTimezoneInMinutes());
            } else {
                return null;
            }
        default:
            throw new IllegalArgumentException("Unknown component for date: " + component);
        }
    }

    /**
     * Get a comparison key for this value. Two values are equal if and only if they their comparison
     * keys are equal
     * @param context XPath dynamic evaluation context
     * @throws NoDynamicContextException if the implicit timezone is required and is not available
     * (because the method is being called at compile time)
     */


    public ComparisonKey getComparisonKey(XPathContext context) throws NoDynamicContextException {
        return new ComparisonKey(StandardNames.XS_DATE, toDateTime().normalize(context));
    }

}

// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// This Source Code Form is “Incompatible With Secondary Licenses”, as defined by the Mozilla Public License, v. 2.0.
TOP

Related Classes of client.net.sf.saxon.ce.value.GDateValue

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.