/**
   * Factory method: create a dateTime value given a date and a time.
   *
   * @param date the date
   * @param time the time
   * @return the dateTime with the given components. If either component is null, returns null
   * @throws XPathException if the timezones are both present and inconsistent
   */
  public static DateTimeValue makeDateTimeValue(DateValue date, TimeValue time)
      throws XPathException {
    if (date == null || time == null) {
      return null;
    }
    DayTimeDurationValue tz1 = (DayTimeDurationValue) date.getComponent(Component.TIMEZONE);
    DayTimeDurationValue tz2 = (DayTimeDurationValue) time.getComponent(Component.TIMEZONE);
    boolean zoneSpecified = (tz1 != null || tz2 != null);
    if (tz1 != null && tz2 != null && !tz1.equals(tz2)) {
      XPathException err = new XPathException("Supplied date and time are in different timezones");
      err.setErrorCode("FORG0008");
      throw err;
    }

    DateTimeValue v = new DateTimeValue();
    v.year = (int) ((Int64Value) date.getComponent(Component.YEAR_ALLOWING_ZERO)).longValue();
    v.month = (byte) ((Int64Value) date.getComponent(Component.MONTH)).longValue();
    v.day = (byte) ((Int64Value) date.getComponent(Component.DAY)).longValue();
    v.hour = (byte) ((Int64Value) time.getComponent(Component.HOURS)).longValue();
    v.minute = (byte) ((Int64Value) time.getComponent(Component.MINUTES)).longValue();
    final BigDecimal secs = ((DecimalValue) time.getComponent(Component.SECONDS)).getDecimalValue();
    v.second = (byte) secs.intValue();
    v.microsecond = secs.multiply(BigDecimal.valueOf(1000000)).intValue() % 1000000;
    if (zoneSpecified) {
      if (tz1 == null) {
        tz1 = tz2;
      }
      v.setTimezoneInMinutes((int) (tz1.getLengthInMicroseconds() / 60000000));
    }
    v.typeLabel = BuiltInAtomicType.DATE_TIME;
    return v;
  }
  /**
   * Return a new dateTime with the same normalized value, but in a different timezone.
   *
   * @param timezone the new timezone offset, in minutes
   * @return the date/time in the new timezone. This will be a new DateTimeValue unless no change
   *     was required to the original value
   */
  public CalendarValue adjustTimezone(int timezone) {
    if (!hasTimezone()) {
      CalendarValue in = (CalendarValue) copyAsSubType(typeLabel);
      in.setTimezoneInMinutes(timezone);
      return in;
    }
    int oldtz = getTimezoneInMinutes();
    if (oldtz == timezone) {
      return this;
    }
    int tz = timezone - oldtz;
    int h = hour;
    int mi = minute;
    mi += tz;
    if (mi < 0 || mi > 59) {
      h += Math.floor(mi / 60.0);
      mi = (mi + 60 * 24) % 60;
    }

    if (h >= 0 && h < 24) {
      return new DateTimeValue(
          year, month, day, (byte) h, (byte) mi, second, microsecond, timezone);
    }

    // Following code is designed to handle the corner case of adjusting from -14:00 to +14:00 or
    // vice versa, which can cause a change of two days in the date
    DateTimeValue dt = this;
    while (h < 0) {
      h += 24;
      DateValue t = DateValue.yesterday(dt.getYear(), dt.getMonth(), dt.getDay());
      dt =
          new DateTimeValue(
              t.getYear(),
              t.getMonth(),
              t.getDay(),
              (byte) h,
              (byte) mi,
              second,
              microsecond,
              timezone);
    }
    if (h > 23) {
      h -= 24;
      DateValue t = DateValue.tomorrow(year, month, day);
      return new DateTimeValue(
          t.getYear(),
          t.getMonth(),
          t.getDay(),
          (byte) h,
          (byte) mi,
          second,
          microsecond,
          timezone);
    }
    return dt;
  }
  /** This method should fail because the value is no close to. */
  @Test
  @NeedReload
  public void should_fail_because_value_is_not_close_to() {
    Table table = new Table(source, "test");
    Changes changes = new Changes(table).setStartPointNow();
    update("update test set var14 = 1 where var1 = 1");
    changes.setEndPointNow();

    try {
      assertThat(changes)
          .change()
          .column("var10")
          .valueAtEndPoint()
          .isCloseTo(
              DateTimeValue.of(DateValue.of(2014, 5, 24), TimeValue.of(9, 46, 31)),
              TimeValue.of(0, 0, 0, 1));
      fail("An exception must be raised");
    } catch (AssertionError e) {
      Assertions.assertThat(e.getMessage())
          .isEqualTo(
              String.format(
                  "[Value at end point of Column at index 9 (column name : VAR10) of Change at index 0 (with primary key : [1]) of Changes on TEST table of 'sa/jdbc:h2:mem:test' source] %n"
                      + "Expecting:%n"
                      + "  <2014-05-24T09:46:30.000000000>%n"
                      + "to be close to: %n"
                      + "  <2014-05-24T09:46:31.000000000> %n"
                      + " with tolerance <00:00:00.000000001>"));
    }
    try {
      assertThat(table)
          .column("var10")
          .value()
          .isCloseTo(
              DateTimeValue.of(DateValue.of(2014, 5, 24), TimeValue.of(9, 46, 31)),
              TimeValue.of(0, 0, 0, 100));
      fail("An exception must be raised");
    } catch (AssertionError e) {
      Assertions.assertThat(e.getMessage())
          .isEqualTo(
              String.format(
                  "[Value at index 0 of Column at index 9 (column name : VAR10) of TEST table] %n"
                      + "Expecting:%n"
                      + "  <2014-05-24T09:46:30.000000000>%n"
                      + "to be close to: %n"
                      + "  <2014-05-24T09:46:31.000000000> %n"
                      + " with tolerance <00:00:00.000000100>"));
    }
  }
 /**
  * Add a duration to a dateTime
  *
  * @param duration the duration to be added (may be negative)
  * @return the new date
  * @throws net.sf.saxon.trans.XPathException if the duration is an xs:duration, as distinct from a
  *     subclass thereof
  */
 public CalendarValue add(DurationValue duration) throws XPathException {
   if (duration instanceof DayTimeDurationValue) {
     long microseconds = ((DayTimeDurationValue) duration).getLengthInMicroseconds();
     BigDecimal seconds =
         BigDecimal.valueOf(microseconds)
             .divide(DecimalValue.BIG_DECIMAL_ONE_MILLION, 6, BigDecimal.ROUND_HALF_EVEN);
     BigDecimal julian = toJulianInstant();
     julian = julian.add(seconds);
     DateTimeValue dt = fromJulianInstant(julian);
     dt.setTimezoneInMinutes(getTimezoneInMinutes());
     return dt;
   } else if (duration instanceof YearMonthDurationValue) {
     int months = ((YearMonthDurationValue) duration).getLengthInMonths();
     int m = (month - 1) + months;
     int y = year + m / 12;
     m = m % 12;
     if (m < 0) {
       m += 12;
       y -= 1;
     }
     m++;
     int d = day;
     while (!DateValue.isValidDate(y, m, d)) {
       d -= 1;
     }
     return new DateTimeValue(
         y, (byte) m, (byte) d, hour, minute, second, microsecond, getTimezoneInMinutes());
   } else {
     XPathException err =
         new XPathException(
             "DateTime arithmetic is not supported on xs:duration, only on its subtypes");
     err.setIsTypeError(true);
     throw err;
   }
 }
 /**
  * Get the Julian instant: a decimal value whose integer part is the Julian day number multiplied
  * by the number of seconds per day, and whose fractional part is the fraction of the second. This
  * method operates on the local time, ignoring the timezone. The caller should call normalize()
  * before calling this method to get a normalized time.
  *
  * @return the Julian instant corresponding to this xs:dateTime value
  */
 public BigDecimal toJulianInstant() {
   int julianDay = DateValue.getJulianDayNumber(year, month, day);
   long julianSecond = julianDay * (24L * 60L * 60L);
   julianSecond += (((hour * 60L + minute) * 60L) + second);
   BigDecimal j = BigDecimal.valueOf(julianSecond);
   if (microsecond == 0) {
     return j;
   } else {
     return j.add(
         BigDecimal.valueOf(microsecond)
             .divide(DecimalValue.BIG_DECIMAL_ONE_MILLION, 6, BigDecimal.ROUND_HALF_EVEN));
   }
 }
 static int hashCode(
     int year,
     byte month,
     byte day,
     byte hour,
     byte minute,
     byte second,
     int microsecond,
     int tzMinutes) {
   int tz = -tzMinutes;
   int h = hour;
   int mi = minute;
   mi += tz;
   if (mi < 0 || mi > 59) {
     h += Math.floor(mi / 60.0);
     mi = (mi + 60 * 24) % 60;
   }
   while (h < 0) {
     h += 24;
     DateValue t = DateValue.yesterday(year, month, day);
     year = t.getYear();
     month = t.getMonth();
     day = t.getDay();
   }
   while (h > 23) {
     h -= 24;
     DateValue t = DateValue.tomorrow(year, month, day);
     year = t.getYear();
     month = t.getMonth();
     day = t.getDay();
   }
   return (year << 4)
       ^ (month << 28)
       ^ (day << 23)
       ^ (h << 18)
       ^ (mi << 13)
       ^ second
       ^ microsecond;
 }
  /** This method tests the {@code isCloseTo} assertion method. */
  @Test
  @NeedReload
  public void test_is_close_to() {
    Table table = new Table(source, "test");
    Changes changes = new Changes(table).setStartPointNow();
    update("update test set var14 = 1 where var1 = 1");
    changes.setEndPointNow();

    ChangeColumnValueAssert changeColumnValueAssert =
        assertThat(changes).change().column("var10").valueAtEndPoint();
    ChangeColumnValueAssert changeColumnValueAssert2 =
        changeColumnValueAssert.isCloseTo(
            DateTimeValue.of(DateValue.of(2014, 5, 24), TimeValue.of(9, 46, 30)),
            TimeValue.of(0, 0, 0));
    Assertions.assertThat(changeColumnValueAssert).isSameAs(changeColumnValueAssert2);

    TableColumnValueAssert tableColumnValueAssert = assertThat(table).column("var10").value();
    TableColumnValueAssert tableColumnValueAssert2 =
        tableColumnValueAssert.isCloseTo(
            DateTimeValue.of(DateValue.of(2014, 5, 24), TimeValue.of(9, 46, 30)),
            TimeValue.of(0, 0, 0));
    Assertions.assertThat(tableColumnValueAssert).isSameAs(tableColumnValueAssert2);
  }
 /**
  * Get the DateTimeValue corresponding to a given Julian instant
  *
  * @param instant the Julian instant: a decimal value whose integer part is the Julian day number
  *     multiplied by the number of seconds per day, and whose fractional part is the fraction of
  *     the second.
  * @return the xs:dateTime value corresponding to the Julian instant. This will always be in
  *     timezone Z.
  */
 public static DateTimeValue fromJulianInstant(BigDecimal instant) {
   BigInteger julianSecond = instant.toBigInteger();
   BigDecimal microseconds =
       instant
           .subtract(new BigDecimal(julianSecond))
           .multiply(DecimalValue.BIG_DECIMAL_ONE_MILLION);
   long js = julianSecond.longValue();
   long jd = js / (24L * 60L * 60L);
   DateValue date = DateValue.dateFromJulianDayNumber((int) jd);
   js = js % (24L * 60L * 60L);
   byte hour = (byte) (js / (60L * 60L));
   js = js % (60L * 60L);
   byte minute = (byte) (js / (60L));
   js = js % (60L);
   return new DateTimeValue(
       date.getYear(),
       date.getMonth(),
       date.getDay(),
       hour,
       minute,
       (byte) js,
       microseconds.intValue(),
       0);
 }
  /**
   * Factory method: create a dateTime value from a supplied string, in ISO 8601 format
   *
   * @param s a string in the lexical space of xs:dateTime
   * @return either a DateTimeValue representing the xs:dateTime supplied, or a ValidationFailure if
   *     the lexical value was invalid
   */
  public static ConversionResult makeDateTimeValue(CharSequence s) {
    // input must have format [-]yyyy-mm-ddThh:mm:ss[.fff*][([+|-]hh:mm | Z)]
    DateTimeValue dt = new DateTimeValue();
    StringTokenizer tok =
        new StringTokenizer(Whitespace.trimWhitespace(s).toString(), "-:.+TZ", true);

    if (!tok.hasMoreElements()) {
      return badDate("too short", s);
    }
    String part = (String) tok.nextElement();
    int era = +1;
    if ("+".equals(part)) {
      return badDate("Date must not start with '+' sign", s);
    } else if ("-".equals(part)) {
      era = -1;
      if (!tok.hasMoreElements()) {
        return badDate("No year after '-'", s);
      }
      part = (String) tok.nextElement();
    }
    int value = DurationValue.simpleInteger(part);
    if (value < 0) {
      return badDate("Non-numeric year component", s);
    }
    dt.year = value * era;
    if (part.length() < 4) {
      return badDate("Year is less than four digits", s);
    }
    if (part.length() > 4 && part.charAt(0) == '0') {
      return badDate("When year exceeds 4 digits, leading zeroes are not allowed", s);
    }
    if (dt.year == 0) {
      return badDate("Year zero is not allowed", s);
    }
    if (era < 0) {
      dt.year++; // internal representation allows a year zero.
    }
    if (!tok.hasMoreElements()) {
      return badDate("Too short", s);
    }
    if (!"-".equals(tok.nextElement())) {
      return badDate("Wrong delimiter after year", s);
    }

    if (!tok.hasMoreElements()) {
      return badDate("Too short", s);
    }
    part = (String) tok.nextElement();
    if (part.length() != 2) {
      return badDate("Month must be two digits", s);
    }
    value = DurationValue.simpleInteger(part);
    if (value < 0) {
      return badDate("Non-numeric month component", s);
    }
    dt.month = (byte) value;
    if (dt.month < 1 || dt.month > 12) {
      return badDate("Month is out of range", s);
    }

    if (!tok.hasMoreElements()) {
      return badDate("Too short", s);
    }
    if (!"-".equals(tok.nextElement())) {
      return badDate("Wrong delimiter after month", s);
    }
    if (!tok.hasMoreElements()) {
      return badDate("Too short", s);
    }
    part = (String) tok.nextElement();
    if (part.length() != 2) {
      return badDate("Day must be two digits", s);
    }
    value = DurationValue.simpleInteger(part);
    if (value < 0) {
      return badDate("Non-numeric day component", s);
    }
    dt.day = (byte) value;
    if (dt.day < 1 || dt.day > 31) {
      return badDate("Day is out of range", s);
    }

    if (!tok.hasMoreElements()) {
      return badDate("Too short", s);
    }
    if (!"T".equals(tok.nextElement())) {
      return badDate("Wrong delimiter after day", s);
    }

    if (!tok.hasMoreElements()) {
      return badDate("Too short", s);
    }
    part = (String) tok.nextElement();
    if (part.length() != 2) {
      return badDate("Hour must be two digits", s);
    }
    value = DurationValue.simpleInteger(part);
    if (value < 0) {
      return badDate("Non-numeric hour component", s);
    }
    dt.hour = (byte) value;
    if (dt.hour > 24) {
      return badDate("Hour is out of range", s);
    }

    if (!tok.hasMoreElements()) {
      return badDate("Too short", s);
    }
    if (!":".equals(tok.nextElement())) {
      return badDate("Wrong delimiter after hour", s);
    }

    if (!tok.hasMoreElements()) {
      return badDate("Too short", s);
    }
    part = (String) tok.nextElement();
    if (part.length() != 2) {
      return badDate("Minute must be two digits", s);
    }
    value = DurationValue.simpleInteger(part);
    if (value < 0) {
      return badDate("Non-numeric minute component", s);
    }
    dt.minute = (byte) value;
    if (dt.minute > 59) {
      return badDate("Minute is out of range", s);
    }
    if (dt.hour == 24 && dt.minute != 0) {
      return badDate("If hour is 24, minute must be 00", s);
    }
    if (!tok.hasMoreElements()) {
      return badDate("Too short", s);
    }
    if (!":".equals(tok.nextElement())) {
      return badDate("Wrong delimiter after minute", s);
    }

    if (!tok.hasMoreElements()) {
      return badDate("Too short", s);
    }
    part = (String) tok.nextElement();
    if (part.length() != 2) {
      return badDate("Second must be two digits", s);
    }
    value = DurationValue.simpleInteger(part);
    if (value < 0) {
      return badDate("Non-numeric second component", s);
    }
    dt.second = (byte) value;

    if (dt.second > 59) {
      return badDate("Second is out of range", s);
    }
    if (dt.hour == 24 && dt.second != 0) {
      return badDate("If hour is 24, second must be 00", s);
    }

    int tz = 0;

    int state = 0;
    while (tok.hasMoreElements()) {
      if (state == 9) {
        return badDate("Characters after the end", s);
      }
      String delim = (String) tok.nextElement();
      if (".".equals(delim)) {
        if (state != 0) {
          return badDate("Decimal separator occurs twice", s);
        }
        if (!tok.hasMoreElements()) {
          return badDate("Decimal point must be followed by digits", s);
        }
        part = (String) tok.nextElement();
        value = DurationValue.simpleInteger(part);
        if (value < 0) {
          return badDate("Non-numeric fractional seconds component", s);
        }
        double fractionalSeconds = Double.parseDouble('.' + part);
        dt.microsecond = (int) (Math.round(fractionalSeconds * 1000000));
        if (dt.hour == 24 && dt.microsecond != 0) {
          return badDate("If hour is 24, fractional seconds must be 0", s);
        }
        state = 1;
      } else if ("Z".equals(delim)) {
        if (state > 1) {
          return badDate("Z cannot occur here", s);
        }
        tz = 0;
        state = 9; // we've finished
        dt.setTimezoneInMinutes(0);
      } else if ("+".equals(delim) || "-".equals(delim)) {
        if (state > 1) {
          return badDate(delim + " cannot occur here", s);
        }
        state = 2;
        if (!tok.hasMoreElements()) {
          return badDate("Missing timezone", s);
        }
        part = (String) tok.nextElement();
        if (part.length() != 2) {
          return badDate("Timezone hour must be two digits", s);
        }
        value = DurationValue.simpleInteger(part);
        if (value < 0) {
          return badDate("Non-numeric timezone hour component", s);
        }
        tz = value;
        if (tz > 14) {
          return badDate("Timezone is out of range (-14:00 to +14:00)", s);
        }
        tz *= 60;

        if ("-".equals(delim)) {
          tz = -tz;
        }

      } else if (":".equals(delim)) {
        if (state != 2) {
          return badDate("Misplaced ':'", s);
        }
        state = 9;
        part = (String) tok.nextElement();
        value = DurationValue.simpleInteger(part);
        if (value < 0) {
          return badDate("Non-numeric timezone minute component", s);
        }
        int tzminute = value;
        if (part.length() != 2) {
          return badDate("Timezone minute must be two digits", s);
        }
        if (tzminute > 59) {
          return badDate("Timezone minute is out of range", s);
        }
        if (tz < 0) {
          tzminute = -tzminute;
        }
        if (Math.abs(tz) == 14 * 60 && tzminute != 0) {
          return badDate("Timezone is out of range (-14:00 to +14:00)", s);
        }
        tz += tzminute;
        dt.setTimezoneInMinutes(tz);
      } else {
        return badDate("Timezone format is incorrect", s);
      }
    }

    if (state == 2 || state == 3) {
      return badDate("Timezone incomplete", s);
    }

    boolean midnight = false;
    if (dt.hour == 24) {
      dt.hour = 0;
      midnight = true;
    }

    // Check that this is a valid calendar date
    if (!DateValue.isValidDate(dt.year, dt.month, dt.day)) {
      return badDate("Non-existent date", s);
    }

    // Adjust midnight to 00:00:00 on the next day
    if (midnight) {
      DateValue t = DateValue.tomorrow(dt.year, dt.month, dt.day);
      dt.year = t.getYear();
      dt.month = t.getMonth();
      dt.day = t.getDay();
    }

    dt.typeLabel = BuiltInAtomicType.DATE_TIME;
    return dt;
  }
Example #10
0
 @Override
 public void visit(DateValue dv) {
   ValueExpression ve = new ValueSpecification(_dateConv, dv.getValue());
   _exprStack.push(ve);
 }
  /**
   * The method <code>normalizeTime</code>
   *
   * @param timeValue a <code>String</code> value
   * @return a <code>String</code> value
   */
  public static String normalizeTime(String timeValue) throws XPathException {
    int hours = 0;
    int mins = 0;
    int secs = 0;
    int mSecs = 0;
    int tzHours = 0;
    int tzMins = 0;
    DecimalFormat df = new DecimalFormat("00");
    DecimalFormat msf = new DecimalFormat("000");
    Matcher m = timeNoTZ.matcher(timeValue);
    if (m.matches()) {
      hours = Integer.valueOf(m.group(1)).intValue();
      mins = Integer.valueOf(m.group(2)).intValue();
      secs = Integer.valueOf(m.group(3)).intValue();
      if (mins >= 60 || mins < 0 || secs >= 60 || secs < 0) {
        throw new XPathException(
            "err:FORG0001: illegal lexical form for date-time-like value '" + timeValue + "'");
      }

      if (hours == 24) {
        if (mins == 0) {
          hours = 0;
        } else {
          throw new XPathException(
              "err:FORG0001: illegal lexical form for date-time-like value '"
                  + timeValue
                  + "'. If hours is 24, minutes must be 00.");
        }
      }
      // fixme!
      timeValue = df.format(hours) + ":" + df.format(mins) + ":" + df.format(secs);
    }

    m = dateTimeNoTZ.matcher(timeValue);
    if (m.matches()) {
      String date = m.group(1);
      DateValue dateValue = null;

      hours = Integer.valueOf(m.group(3)).intValue();
      mins = Integer.valueOf(m.group(4)).intValue();
      secs = Integer.valueOf(m.group(5)).intValue();
      if (mins >= 60 || mins < 0 || secs >= 60 || secs < 0) {
        throw new XPathException(
            "err:FORG0001: illegal lexical form for date-time-like value '" + timeValue + "'");
      }

      if (hours == 24) {
        if (mins == 0) {
          hours = 0;
          dateValue = (DateValue) new DateValue(date).plus(new DayTimeDurationValue("P1D"));
        } else {
          throw new XPathException(
              "err:FORG0001: illegal lexical form for date-time-like value '"
                  + timeValue
                  + "'. If hours is 24, minutes must be 00.");
        }
      }
      // fixme!
      timeValue =
          (dateValue == null ? date : dateValue.getStringValue())
              + m.group(2)
              + df.format(hours)
              + ":"
              + df.format(mins)
              + ":"
              + df.format(secs);
    }

    m = dateTimeMsWTZ.matcher(timeValue);
    if (m.matches()) {
      hours = Integer.valueOf(m.group(2)).intValue();
      mins = Integer.valueOf(m.group(3)).intValue();
      secs = Integer.valueOf(m.group(4)).intValue();
      mSecs = Integer.valueOf(m.group(6)).intValue();
      tzHours = Integer.valueOf(m.group(8)).intValue();
      tzMins = Integer.valueOf(m.group(9)).intValue();
      if (mins >= 60 || mins < 0 || tzMins >= 60 || tzMins < 0) {
        throw new XPathException(
            "err:FORG0001: illegal lexical form for date-time-like value '" + timeValue + "'");
      }

      if (hours == 24) {
        if (mins == 0) {
          hours = 0;
        } else {
          throw new XPathException(
              "err:FORG0001: illegal lexical form for date-time-like value '"
                  + timeValue
                  + "'. If hours is 24, minutes must be 00.");
        }
      }
      // fixme!
      timeValue =
          m.group(1)
              + df.format(hours)
              + ":"
              + df.format(mins)
              + ":"
              + df.format(secs)
              + m.group(5)
              + msf.format(mSecs)
              + m.group(7)
              + df.format(tzHours)
              + ":"
              + df.format(tzMins);
    }

    m = timeMsWTZ.matcher(timeValue);
    if (m.matches()) {
      hours = Integer.valueOf(m.group(1)).intValue();
      mins = Integer.valueOf(m.group(2)).intValue();
      secs = Integer.valueOf(m.group(3)).intValue();
      mSecs = Integer.valueOf(m.group(5)).intValue();
      tzHours = Integer.valueOf(m.group(7)).intValue();
      tzMins = Integer.valueOf(m.group(8)).intValue();
      if (mins >= 60 || mins < 0 || tzMins >= 60 || tzMins < 0) {
        throw new XPathException(
            "err:FORG0001: illegal lexical form for date-time-like value '" + timeValue + "'");
      }

      if (hours == 24) {
        if (mins == 0) {
          hours = 0;
        } else {
          throw new XPathException(
              "err:FORG0001: illegal lexical form for date-time-like value '"
                  + timeValue
                  + "'. If hours is 24, minutes must be 00.");
        }
      }
      timeValue =
          df.format(hours)
              + ":"
              + df.format(mins)
              + ":"
              + df.format(secs)
              + m.group(4)
              + msf.format(mSecs)
              + m.group(6)
              + df.format(tzHours)
              + ":"
              + df.format(tzMins);
    }

    m = gYearWUTCTZ.matcher(timeValue);
    if (m.matches()) {
      tzHours = Integer.valueOf(m.group(3)).intValue();
      tzMins = Integer.valueOf(m.group(4)).intValue();
      if (tzMins >= 60 || tzMins < 0) {
        throw new XPathException(
            "err:FORG0001: illegal lexical form for date-time-like value '" + timeValue + "'");
      }

      if (tzHours == 24) {
        if (tzMins == 0) {
          tzHours = 0;
        } else {
          throw new XPathException(
              "err:FORG0001: illegal lexical form for date-time-like value '"
                  + timeValue
                  + "'. If hours is 24, minutes must be 00.");
        }
      }
      // fixme!
      timeValue = m.group(1) + m.group(2) + df.format(tzHours) + ":" + df.format(tzMins);
    }

    m = gDayWTZ.matcher(timeValue);
    if (m.matches()) {
      tzHours = Integer.valueOf(m.group(3)).intValue();
      tzMins = Integer.valueOf(m.group(4)).intValue();
      if (tzMins >= 60 || tzMins < 0) {
        throw new XPathException(
            "err:FORG0001: illegal lexical form for date-time-like value '" + timeValue + "'");
      }

      if (tzHours == 24) {
        if (tzMins == 0) {
          tzHours = 0;
        } else {
          throw new XPathException(
              "err:FORG0001: illegal lexical form for date-time-like value '"
                  + timeValue
                  + "'. If hours is 24, minutes must be 00.");
        }
      }
      // fixme!
      timeValue = m.group(1) + m.group(2) + df.format(tzHours) + ":" + df.format(tzMins);
    }

    m = gMonthWTZ.matcher(timeValue);
    if (m.matches()) {
      tzHours = Integer.valueOf(m.group(3)).intValue();
      tzMins = Integer.valueOf(m.group(4)).intValue();
      if (tzMins >= 60 || tzMins < 0) {
        throw new XPathException(
            "err:FORG0001: illegal lexical form for date-time-like value '" + timeValue + "'");
      }

      if (tzHours == 24) {
        if (tzMins == 0) {
          tzHours = 0;
        } else {
          throw new XPathException(
              "err:FORG0001: illegal lexical form for date-time-like value '"
                  + timeValue
                  + "'. If hours is 24, minutes must be 00.");
        }
      }
      // fixme!
      timeValue = m.group(1) + m.group(2) + df.format(tzHours) + ":" + df.format(tzMins);
    }

    m = gYearMonthWTZ.matcher(timeValue);
    if (m.matches()) {
      tzHours = Integer.valueOf(m.group(3)).intValue();
      tzMins = Integer.valueOf(m.group(4)).intValue();
      if (tzMins >= 60 || tzMins < 0) {
        throw new XPathException(
            "err:FORG0001: illegal lexical form for date-time-like value '" + timeValue + "'");
      }

      if (tzHours == 24) {
        if (tzMins == 0) {
          tzHours = 0;
        } else {
          throw new XPathException(
              "err:FORG0001: illegal lexical form for date-time-like value '"
                  + timeValue
                  + "'. If hours is 24, minutes must be 00.");
        }
      }
      // fixme!
      timeValue = m.group(1) + m.group(2) + df.format(tzHours) + ":" + df.format(tzMins);
    }

    m = gMonthDayWTZ.matcher(timeValue);
    if (m.matches()) {
      tzHours = Integer.valueOf(m.group(3)).intValue();
      tzMins = Integer.valueOf(m.group(4)).intValue();
      if (tzMins >= 60 || tzMins < 0) {
        throw new XPathException(
            "err:FORG0001: illegal lexical form for date-time-like value '" + timeValue + "'");
      }

      if (tzHours == 24) {
        if (tzMins == 0) {
          tzHours = 0;
        } else {
          throw new XPathException(
              "err:FORG0001: illegal lexical form for date-time-like value '"
                  + timeValue
                  + "'. If hours is 24, minutes must be 00.");
        }
      }
      // fixme!
      timeValue = m.group(1) + m.group(2) + df.format(tzHours) + ":" + df.format(tzMins);
    }

    m = dateWTZ.matcher(timeValue);
    if (m.matches()) {
      hours = Integer.valueOf(m.group(3)).intValue();
      mins = Integer.valueOf(m.group(4)).intValue();
      if (mins >= 60 || mins < 0 || tzMins >= 60 || tzMins < 0) {
        throw new XPathException(
            "err:FORG0001: illegal lexical form for date-time-like value '" + timeValue + "'");
      }

      if (hours == 24) {
        if (mins == 0) {
          hours = 0;
        } else {
          throw new XPathException(
              "err:FORG0001: illegal lexical form for date-time-like value '"
                  + timeValue
                  + "'. If hours is 24, minutes must be 00.");
        }
      }
      // fixme!
      timeValue = m.group(1) + m.group(2) + df.format(hours) + ":" + df.format(mins);
    }
    return timeValue;
  }
Example #12
0
 public void testMinus7() throws XPathException {
   DateValue d1 = new DateValue("2005-10-10"), d2 = new DateValue("2005-10-09");
   DayTimeDurationValue r = (DayTimeDurationValue) d1.minus(d2);
   assertEquals((double) 1 * 24 * 60 * 60, r.getValue(), 0);
   assertEquals(1, r.getPart(DurationValue.DAY));
 }