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

net.sf.saxon.value.SaxonDuration Maven / Gradle / Ivy

There is a newer version: 12.5
Show newest version
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2018-2022 Saxonica Limited
// 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.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package net.sf.saxon.value;

import net.sf.saxon.expr.sort.XPathComparable;
import net.sf.saxon.functions.AccessorFn;
import net.sf.saxon.lib.NamespaceConstant;
import net.sf.saxon.trans.NoDynamicContextException;
import net.sf.saxon.trans.XPathException;

import javax.xml.datatype.DatatypeConstants;
import javax.xml.datatype.Duration;
import javax.xml.namespace.QName;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Calendar;

/**
 * Saxon implementation of the JAXP class javax.xml.datatype.Duration. This is currently used only by the XQJ
 * interface for XQuery: the normal representation of a duration in Saxon is the class {@link DurationValue}.
 * 

The JAXP specification for this class defines it in terms of XML Schema 1.0 semantics. This defines a structure * with six independent components (year, month, day, hour, minute, second). This implementation is more aligned * to the XPath 2.0 semantics of the data type, which essentially defines duration as an integer number of months plus * a decimal number of seconds.

*/ public class SaxonDuration extends Duration { private final DurationValue duration; /** * Create a SaxonDuration that wraps a supplied DurationValue * * @param duration the value to be wrapped. */ public SaxonDuration(DurationValue duration) { this.duration = duration; } /** * Get the underlying DurationValue * * @return the underlying DurationValue */ public DurationValue getDurationValue() { return duration; } /** * Get the type of this duration, as one of the values xs:duration, xs:dayTimeDuration, or * xs:yearMonthDuration. (Note that the XML Schema namespace URI is used, whereas the current * implementation of the superclass uses a provisional URI allocated in a 2003 W3C working draft) * * @return the type of this duration, as one of the values xs:duration, xs:dayTimeDuration, or * xs:yearMonthDuration */ @Override public QName getXMLSchemaType() { if (duration instanceof DayTimeDurationValue) { return new QName(NamespaceConstant.SCHEMA, "dayTimeDuration"); } else if (duration instanceof YearMonthDurationValue) { return new QName(NamespaceConstant.SCHEMA, "yearMonthDuration"); } else { return new QName(NamespaceConstant.SCHEMA, "duration"); } } /** * Returns the sign of this duration in -1,0, or 1. * * @return -1 if this duration is negative, 0 if the duration is zero, * and 1 if the duration is positive. */ @Override public int getSign() { return duration.signum(); } /** * Gets the value of a field. *

Fields of a duration object may contain arbitrary large value. * Therefore this method is designed to return a {@link Number} object.

*

In case of YEARS, MONTHS, DAYS, HOURS, and MINUTES, the returned * number will be a non-negative integer. In case of seconds, * the returned number may be a non-negative decimal value.

*

The Saxon implementation of duration uses normalized values. This means * that the YEARS and DAYS fields may be arbitrarily large, but other * components will be limited in size: for example MINUTES will never * exceed 60 and MONTHS will never exceed 12.

* * @param field one of the six Field constants (YEARS, MONTHS, DAYS, HOURS, * MINUTES, or SECONDS.) * @return If the specified field is present, this method returns * a non-null non-negative {@link Number} object that * represents its value. If it is not present, return null. * For YEARS, MONTHS, DAYS, HOURS, and MINUTES, this method * returns a {@link java.math.BigInteger} object. For SECONDS, this * method returns a {@link java.math.BigDecimal}. * @throws NullPointerException If the field is null. */ @Override public Number getField(DatatypeConstants.Field field) { if (field == DatatypeConstants.YEARS) { return BigInteger.valueOf(((Int64Value) duration.getComponent(AccessorFn.Component.YEAR)).longValue()); } else if (field == DatatypeConstants.MONTHS) { return BigInteger.valueOf(((Int64Value) duration.getComponent(AccessorFn.Component.MONTH)).longValue()); } else if (field == DatatypeConstants.DAYS) { return BigInteger.valueOf(((Int64Value) duration.getComponent(AccessorFn.Component.DAY)).longValue()); } else if (field == DatatypeConstants.HOURS) { return BigInteger.valueOf(((Int64Value) duration.getComponent(AccessorFn.Component.HOURS)).longValue()); } else if (field == DatatypeConstants.MINUTES) { return BigInteger.valueOf(((Int64Value) duration.getComponent(AccessorFn.Component.MINUTES)).longValue()); } else if (field == DatatypeConstants.SECONDS) { return ((BigDecimalValue) duration.getComponent(AccessorFn.Component.SECONDS)).getDecimalValue(); } else { throw new IllegalArgumentException("Invalid field"); } } /** * Checks if a field is set. In this implementation, all fields are always set. * * @param field one of the six Field constants (YEARS, MONTHS, DAYS, HOURS, * MINUTES, or SECONDS.) * @return This implementation always returns true. */ @Override public boolean isSet(DatatypeConstants.Field field) { return true; } /** *

Computes a new duration whose value is this+rhs.

*

This implementation follows the XPath semantics. This means that the operation will fail * if the duration is not a yearMonthDuration or a dayTimeDuration * * @param rhs Duration to add to this Duration * @return non-null valid Duration object. * @throws NullPointerException If the rhs parameter is null. * @throws IllegalStateException If the durations are not both dayTimeDurations, or * both yearMonthDurations. * @see #subtract(javax.xml.datatype.Duration) */ @Override public Duration add(Duration rhs) { try { return new SaxonDuration(duration.add(((SaxonDuration) rhs).duration)); } catch (XPathException e) { throw new IllegalStateException(e.getMessage()); } } /** *

Computes a new duration whose value is this-rhs.

*

This implementation follows the XPath semantics. This means that the operation will fail * if the duration is not a yearMonthDuration or a dayTimeDuration. * * @param rhs Duration to subtract from this Duration * @return non-null valid Duration object. * @throws NullPointerException If the rhs parameter is null. * @throws IllegalStateException If the durations are not both dayTimeDurations, or * both yearMonthDurations. * @see #add(javax.xml.datatype.Duration) */ @Override public Duration subtract(Duration rhs) { try { return new SaxonDuration(duration.subtract(((SaxonDuration) rhs).duration)); } catch (XPathException e) { throw new IllegalStateException(e.getMessage()); } } /** * Adds this duration to a {@link java.util.Calendar} object. *

Calls {@link java.util.Calendar#add(int, int)} in the * order of YEARS, MONTHS, DAYS, HOURS, MINUTES, SECONDS, and MILLISECONDS * if those fields are present. Because the {@link java.util.Calendar} class * uses int to hold values, there are cases where this method * won't work correctly (for example if values of fields * exceed the range of int.)

*

Also, since this duration class is a Gregorian duration, this * method will not work correctly if the given {@link java.util.Calendar} * object is based on some other calendar systems.

*

Any fractional parts of this Duration object * beyond milliseconds will be simply ignored. For example, if * this duration is "P1.23456S", then 1 is added to SECONDS, * 234 is added to MILLISECONDS, and the rest will be unused.

*

Note that because {@link java.util.Calendar#add(int, int)} is using * int, Duration with values beyond the * range of int in its fields * will cause overflow/underflow to the given {@link java.util.Calendar}. * {@link javax.xml.datatype.XMLGregorianCalendar#add(javax.xml.datatype.Duration)} provides the same * basic operation as this method while avoiding * the overflow/underflow issues.

* * @param calendar A calendar object whose value will be modified. * @throws NullPointerException if the calendar parameter is null. */ @Override public void addTo(Calendar calendar) { int sign = getSign(); if (sign == 0) { return; } calendar.add(Calendar.YEAR, getYears() * sign); calendar.add(Calendar.MONTH, getMonths() * sign); calendar.add(Calendar.DAY_OF_MONTH, getDays() * sign); calendar.add(Calendar.HOUR_OF_DAY, getHours() * sign); calendar.add(Calendar.MINUTE, getMinutes() * sign); calendar.add(Calendar.SECOND, (int) ((Int64Value) duration.getComponent(AccessorFn.Component.WHOLE_SECONDS)).longValue() * sign); calendar.add(Calendar.MILLISECOND, (int) ((Int64Value) duration.getComponent(AccessorFn.Component.MICROSECONDS)).longValue() * sign / 1000); } /** * Computes a new duration whose value is factor times * longer than the value of this duration. *

This implementation follows the XPath semantics. This means that it is defined * only on yearMonthDuration and dayTimeDuration. Other cases produce an IllegalStateException.

* * @param factor to multiply by * @return returns a non-null valid Duration object * @throws IllegalStateException if operation produces fraction in * the months field. * @throws NullPointerException if the factor parameter is * null. */ @Override public Duration multiply(BigDecimal factor) { try { return new SaxonDuration(duration.multiply(factor.doubleValue())); } catch (XPathException e) { throw new IllegalStateException(e.getMessage()); } } /** * Returns a new Duration object whose * value is -this. *

Since the Duration class is immutable, this method * doesn't change the value of this object. It simply computes * a new Duration object and returns it.

* * @return always return a non-null valid Duration object. */ @Override public Duration negate() { return new SaxonDuration(duration.negate()); } /** *

Converts the years and months fields into the days field * by using a specific time instant as the reference point.

*

This implementation does not support this method

* * @param startTimeInstant Calendar reference point. * @return Duration of years and months of this Duration as days. * @throws NullPointerException If the startTimeInstant parameter is null. * @throws UnsupportedOperationException Always thrown by this implementation. */ @Override public Duration normalizeWith(Calendar startTimeInstant) { throw new UnsupportedOperationException(); } /** *

Partial order relation comparison with this Duration instance.

*

This implementation follows the XPath semantics. This means that the result is defined only * for dayTimeDuration and yearMonthDuration values, and the result is never indeterminate.

*

Return:

*
    *
  • {@link javax.xml.datatype.DatatypeConstants#LESSER} * if this Duration is shorter than duration parameter
  • *
  • {@link javax.xml.datatype.DatatypeConstants#EQUAL} * if this Duration is equal to duration parameter
  • *
  • {@link javax.xml.datatype.DatatypeConstants#GREATER} * if this Duration is longer than duration parameter
  • *
  • {@link javax.xml.datatype.DatatypeConstants#INDETERMINATE} * if a conclusive partial order relation cannot be determined
  • *
* * @param rhs duration to compare * @return the relationship between this Durationand duration parameter as * {@link javax.xml.datatype.DatatypeConstants#LESSER}, * {@link javax.xml.datatype.DatatypeConstants#EQUAL}, * {@link javax.xml.datatype.DatatypeConstants#GREATER} * or {@link javax.xml.datatype.DatatypeConstants#INDETERMINATE}. * @throws UnsupportedOperationException If the underlying implementation * cannot reasonably process the request, e.g. W3C XML Schema allows for * arbitrarily large/small/precise values, the request may be beyond the * implementations capability. * @throws NullPointerException if duration is null. * @throws IllegalArgumentException if the operands are not dayTimeDuration or yearMonthDuration values. * @see #isShorterThan(javax.xml.datatype.Duration) * @see #isLongerThan(javax.xml.datatype.Duration) */ @Override public int compare(/*@NotNull*/ Duration rhs) { if (!(rhs instanceof SaxonDuration)) { throw new IllegalArgumentException("Supplied duration is not a SaxonDuration"); } try { XPathComparable c0 = duration.getXPathComparable(null, 0); XPathComparable c1 = ((SaxonDuration) rhs).duration.getXPathComparable(null, 0); return c0.compareTo(c1); } catch (NoDynamicContextException e) { throw new AssertionError(e); } } /** * Returns a hash code consistent with the definition of the equals method. * * @see Object#hashCode() */ public int hashCode() { return duration.hashCode(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy