Package org.exist.xquery.value

Source Code of org.exist.xquery.value.DayTimeDurationValue

/*
*  eXist Open Source Native XML Database
*  Copyright (C) 2001-06 Wolfgang M. Meier
*  wolfgang@exist-db.org
*  http://exist.sourceforge.net
*  This program is free software; you can redistribute it and/or
*  modify it under the terms of the GNU Lesser General Public License
*  as published by the Free Software Foundation; either version 2
*  of the License, or (at your option) 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
*  GNU Lesser General Public License for more details.
*  You should have received a copy of the GNU Lesser General Public License
*  along with this program; if not, write to the Free Software
*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*  $Id$
*/

package org.exist.xquery.value;

import java.math.BigDecimal;
import java.math.BigInteger;

import javax.xml.datatype.DatatypeConstants;
import javax.xml.datatype.Duration;

import org.exist.util.FastStringBuffer;
import org.exist.util.FloatingPointConverter;
import org.exist.xquery.ErrorCodes;
import org.exist.xquery.XPathException;

/**
* @author <a href="mailto:piotr@ideanest.com">Piotr Kaminski</a>
*/
public class DayTimeDurationValue extends OrderedDurationValue {

  public static final Duration CANONICAL_ZERO_DURATION =
    TimeUtils.getInstance().newDuration(true, null, null, null, null, null, ZERO_DECIMAL);
 
  DayTimeDurationValue(Duration duration) throws XPathException {
    super(duration);
    if (duration.isSet(DatatypeConstants.YEARS) || duration.isSet(DatatypeConstants.MONTHS))
      {throw new XPathException(ErrorCodes.XPTY0004, "the value '" + duration + "' is not an xdt:dayTimeDuration since it specifies year or month values");}
  }

  public DayTimeDurationValue(long millis) throws XPathException {
    this(TimeUtils.getInstance().newDurationDayTime(millis));
  }
 
  public DayTimeDurationValue(String str) throws XPathException {
    this(createDurationDayTime(StringValue.trimWhitespace(str)));
  }

  private static Duration createDurationDayTime(String str) throws XPathException {
    try {
      return TimeUtils.getInstance().newDurationDayTime(str);
    } catch (final IllegalArgumentException e) {
      throw new XPathException(ErrorCodes.FORG0001, "cannot construct " + Type.getTypeName(Type.DAY_TIME_DURATION) +
          " from \"" + str + "\"");           
    }
  }
 
  public DurationValue wrap() {
    return this;
  }

  public int getType() {
    return Type.DAY_TIME_DURATION;
  }
 
  public double getValue() {
    double value = duration.getDays();
    value = value * 24 + duration.getHours();
    value = value * 60 + duration.getMinutes();
    final Number n = duration.getField(DatatypeConstants.SECONDS);
    value = value * 60 + (n == null ? 0 : n.doubleValue());
    return value * duration.getSign();
  }
 
  public long getValueInMilliseconds() {
    return (long) (getValue() * 1000);
  }
 
  protected Duration canonicalZeroDuration() {
    return CANONICAL_ZERO_DURATION;
  }
 
  public String getStringValue() {
    final Duration canonicalDuration = getCanonicalDuration();
   
    final int d = canonicalDuration.getDays();
    final int h = canonicalDuration.getHours();
    final int m = canonicalDuration.getMinutes();
    Number s = canonicalDuration.getField(DatatypeConstants.SECONDS);
        if (s == null)
          {s = Integer.valueOf(0);}
 
    //Copied from Saxon 8.6.1   
        final FastStringBuffer sb = new FastStringBuffer(32);
        if (canonicalDuration.getSign() < 0) {
            sb.append('-');
        }
        sb.append('P');       
        if (d != 0) {
            sb.append(d + "D");
        }
        if ( d==0 || h!=0 || m!=0 || s.intValue() != 0) {
            sb.append('T');
        }
        if (h != 0) {
            sb.append(h + "H");
        }
        if (m != 0) {
            sb.append(m + "M");
        }
        if ((s.intValue() != 0) || (d==0 && m==0 && h==0)) {
          //TODO : ugly -> factorize
          //sb.append(Integer.toString(s.intValue()));
          //double ms = s.doubleValue() - s.intValue();
          //if (ms != 0.0) {
          //  sb.append(".");
          //  sb.append(Double.toString(ms).substring(2));           
          //}
        //0 is a dummy parameter
        FloatingPointConverter.appendFloat(sb, s.floatValue()).getNormalizedString(0)
          sb.append("S");             
          /*
            if (micros == 0) {
                sb.append(s + "S");
            } else {
                long ms = (s * 1000000) + micros;
                String mss = ms + "";
                if (s == 0) {
                    mss = "0000000" + mss;
                    mss = mss.substring(mss.length()-7);
                }
                sb.append(mss.substring(0, mss.length()-6));
                sb.append('.');
                int lastSigDigit = mss.length()-1;
                while (mss.charAt(lastSigDigit) == '0') {
                    lastSigDigit--;
                }
                sb.append(mss.substring(mss.length()-6, lastSigDigit+1));
                sb.append('S');
            }
            */
        }
        //End of copy       
        return sb.toString();
       
  }
 
  public AtomicValue convertTo(int requiredType) throws XPathException {
    switch(requiredType) {
      case Type.ITEM:
      case Type.ATOMIC:
      case Type.DAY_TIME_DURATION:
        return new DayTimeDurationValue(getCanonicalDuration());
      case Type.STRING: {
        final DayTimeDurationValue dtdv = new DayTimeDurationValue(getCanonicalDuration());
        return new StringValue(dtdv.getStringValue());
      }
      case Type.DURATION:
        return new DurationValue(TimeUtils.getInstance().newDuration(
            duration.getSign() >= 0, null, null,
            (BigInteger) duration.getField(DatatypeConstants.DAYS),
            (BigInteger) duration.getField(DatatypeConstants.HOURS),
            (BigInteger) duration.getField(DatatypeConstants.MINUTES),
            (BigDecimal) duration.getField(DatatypeConstants.SECONDS)));
      case Type.YEAR_MONTH_DURATION:
        return new YearMonthDurationValue(YearMonthDurationValue.CANONICAL_ZERO_DURATION);       
      //case Type.DOUBLE:
        //return new DoubleValue(monthsValueSigned().doubleValue());
        //return new DoubleValue(Double.NaN);
      //case Type.DECIMAL:
        //return new DecimalValue(monthsValueSigned().doubleValue()); 
      case Type.UNTYPED_ATOMIC : {
        final DayTimeDurationValue dtdv = new DayTimeDurationValue(getCanonicalDuration());
        return new UntypedAtomicValue(dtdv.getStringValue());
      }
      default:
        throw new XPathException(ErrorCodes.XPTY0004, "cannot cast '" +
            Type.getTypeName(this.getItemType()) + "(\"" + getStringValue() + "\")' to " +
            Type.getTypeName(requiredType));
    }
  }
 
  protected DurationValue createSameKind(Duration dur) throws XPathException {
    return new DayTimeDurationValue(dur);
  }
 
  /*
  public ComputableValue plus(ComputableValue other) throws XPathException {
    try {
      return super.plus(other);
    } catch (IllegalArgumentException e) {
        throw new XPathException("Operand to plus should be of type xdt:dayTimeDuration, xs:time, " +
          "xs:date or xs:dateTime; got: " +
          Type.getTypeName(other.getType()));
    }
  }
  */
 
  public ComputableValue mult(ComputableValue other) throws XPathException {
    if (other instanceof NumericValue) {
      //If $arg2 is NaN an error is raised [err:FOCA0005]
      if (((NumericValue)other).isNaN()) {
        throw new XPathException(ErrorCodes.FOCA0005, "Operand is not a number");       
      }   
      //If $arg2 is positive or negative infinity, the result overflows
      if (((NumericValue)other).isInfinite()) {
        throw new XPathException(ErrorCodes.FODT0002, "Multiplication by infinity overflow");   
      }   
    }   
    final BigDecimal factor = numberToBigDecimal(other, "Operand to mult should be of numeric type; got: ");
    final boolean isFactorNegative = factor.signum() < 0;
    final DayTimeDurationValue product = new DayTimeDurationValue(duration.multiply(factor.abs()));
    if (isFactorNegative)
      {return new DayTimeDurationValue(product.negate().getCanonicalDuration());}
    return new DayTimeDurationValue(product.getCanonicalDuration());
   
  }

  public ComputableValue div(ComputableValue other) throws XPathException {   
    if (other.getType() == Type.DAY_TIME_DURATION) {   
      final DecimalValue a = new DecimalValue(secondsValueSigned());
      final DecimalValue b = new DecimalValue(((DayTimeDurationValue)other).secondsValueSigned());
      return new DecimalValue(a.value.divide(b.value, 20, BigDecimal.ROUND_HALF_UP));
    }   
    if (other instanceof NumericValue) {
      if (((NumericValue)other).isNaN()) {
        throw new XPathException(ErrorCodes.FOCA0005, "Operand is not a number");       
      }
      //If $arg2 is positive or negative infinity, the result is a zero-length duration
      if (((NumericValue)other).isInfinite()) {
        return new DayTimeDurationValue("PT0S");
      }
      //If $arg2 is positive or negative zero, the result overflows and is handled as discussed in 10.1.1 Limits and Precision
      if (((NumericValue)other).isZero()) {
        throw new XPathException(ErrorCodes.FODT0002, "Division by zero");
      }
    }
    final BigDecimal divisor = numberToBigDecimal(other, "Operand to div should be of xdt:dayTimeDuration or numeric type; got: ");
    final boolean isDivisorNegative = divisor.signum() < 0;
    final BigDecimal secondsValueSigned = secondsValueSigned();
    final DayTimeDurationValue quotient = fromDecimalSeconds(secondsValueSigned.divide(divisor.abs(), Math.max(Math.max(3, secondsValueSigned.scale()), divisor.scale()), BigDecimal.ROUND_HALF_UP));
    if (isDivisorNegative)
      {return new DayTimeDurationValue(quotient.negate().getCanonicalDuration());}
    return new DayTimeDurationValue(quotient.getCanonicalDuration());   
  }

  private DayTimeDurationValue fromDecimalSeconds(BigDecimal x) throws XPathException {   
    return new DayTimeDurationValue(TimeUtils.getInstance().newDuration(
        x.signum() >= 0, null, null, null, null, null, x.abs()));
 
  }

    public boolean effectiveBooleanValue() throws XPathException {
        throw new XPathException(ErrorCodes.FORG0006, "value of type " + Type.getTypeName(getType()) +
            " has no boolean value.");
    }
}
TOP

Related Classes of org.exist.xquery.value.DayTimeDurationValue

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.