/** * Returns a day count for the specified years, months and days. All values must be specified in * their internal representation (undefined values are supported, too). Algorithm is derived from * J R Stockton (http://www.merlyn.demon.co.uk/daycount.htm). * * @param year year * @param month month * @param day days * @return days */ private static BigDecimal days(final long year, final int month, final int day) { final long y = year - (month < 2 ? 1 : 0); final int m = month + (month < 2 ? 13 : 1); final int d = day + 1; return BD365 .multiply(BigDecimal.valueOf(y)) .add(BigDecimal.valueOf(y / 4 - y / 100 + y / 400 - 92 + d + (153 * m - 2) / 5)); }
/** * Initializes the dayTime component. * * @param vl value * @param mt matcher * @param p first matching position * @param ii input info * @throws QueryException query exception */ void dayTime(final byte[] vl, final Matcher mt, final int p, final InputInfo ii) throws QueryException { final long d = mt.group(p) != null ? toLong(mt.group(p + 1), true, ii) : 0; final long h = mt.group(p + 3) != null ? toLong(mt.group(p + 4), true, ii) : 0; final long m = mt.group(p + 5) != null ? toLong(mt.group(p + 6), true, ii) : 0; final BigDecimal s = mt.group(p + 7) != null ? toDecimal(mt.group(p + 8), true, ii) : BigDecimal.ZERO; sec = s.add(BigDecimal.valueOf(d).multiply(DAYSECONDS)) .add(BigDecimal.valueOf(h).multiply(BD3600)) .add(BigDecimal.valueOf(m).multiply(BD60)); if (!mt.group(1).isEmpty()) sec = sec.negate(); final double v = sec.doubleValue(); if (v <= Long.MIN_VALUE || v >= Long.MAX_VALUE) throw DURRANGE_X_X.get(ii, type, vl); }
/** * Returns the date in seconds. * * @return seconds */ final BigDecimal seconds() { int z = tz; if (z == Short.MAX_VALUE) { // [CG] XQuery, DateTime: may be removed final long n = System.currentTimeMillis(); z = Calendar.getInstance().getTimeZone().getOffset(n) / 60000; } return (sec == null ? BigDecimal.ZERO : sec) .add(BigDecimal.valueOf(Math.max(0, hou) * 3600 + Math.max(0, min) * 60 - z * 60)); }
/** * Converts a day count into year, month and day components. Algorithm is derived from J R * Stockton (http://www.merlyn.demon.co.uk/daycount.htm). * * @param days day count * @return result array */ private static long[] ymd(final BigDecimal days) { BigDecimal d = days; BigDecimal t = d.add(BD36525).multiply(BD4).divideToIntegralValue(BD146097).subtract(BigDecimal.ONE); BigDecimal y = BD100.multiply(t); d = d.subtract(BD36524.multiply(t).add(t.divideToIntegralValue(BD4))); t = d.add(BD366).multiply(BD4).divideToIntegralValue(BD1461).subtract(BigDecimal.ONE); y = y.add(t); d = d.subtract(BD365.multiply(t).add(t.divideToIntegralValue(BD4))); final BigDecimal m = BD5.multiply(d).add(BD2).divideToIntegralValue(BD153); d = d.subtract(BD153.multiply(m).add(BD2).divideToIntegralValue(BD5)); long mm = m.longValue(); if (mm > 9) { mm -= 12; y = y.add(BigDecimal.ONE); } return new long[] {y.subtract(BigDecimal.valueOf(ADD_NEG)).longValue(), mm + 2, d.longValue()}; }
/** * Adjusts the timezone. * * @param zone timezone * @param spec indicates if zone has been specified (may be {@code null}) * @param ii input info * @throws QueryException query exception */ void tz(final DTDur zone, final boolean spec, final InputInfo ii) throws QueryException { final short t; if (spec && zone == null) { t = Short.MAX_VALUE; } else { if (zone == null) { final Calendar c = Calendar.getInstance(); t = (short) ((c.get(Calendar.ZONE_OFFSET) + c.get(Calendar.DST_OFFSET)) / 60000); } else { t = (short) (zone.min() + zone.hou() * 60); if (zone.sec().signum() != 0) throw ZONESEC_X.get(ii, zone); if (Math.abs(t) > 60 * 14 || zone.day() != 0) throw INVALZONE_X.get(ii, zone); } // change time if two competing time zones exist if (tz != Short.MAX_VALUE) add(BigDecimal.valueOf(60L * (t - tz))); } tz = t; }
/** * Adds the specified dayTime duration. * * @param add value to be added */ private void add(final BigDecimal add) { // normalized modulo: sc % 60 vs. (-sc + sc % 60 + 60 + sc) % 60 final BigDecimal sc = sec().add(add); sec = sc.signum() >= 0 ? sc.remainder(BD60) : sc.negate().add(sc.remainder(BD60)).add(BD60).add(sc).remainder(BD60); final long mn = Math.max(min(), 0) + div(sc.longValue(), 60); min = (byte) mod(mn, 60); final long ho = Math.max(hou, 0) + div(mn, 60); hou = (byte) mod(ho, 24); final long da = div(ho, 24); final long[] ymd = ymd(days().add(BigDecimal.valueOf(da))); yea = ymd[0]; mon = (byte) ymd[1]; day = (byte) ymd[2]; }