Java tutorial
//package com.java2s; /* * Integrated Rule Inference System (IRIS): * An extensible rule inference system for datalog with extensions. * * Copyright (C) 2008 Semantic Technology Institute (STI) Innsbruck, * University of Innsbruck, Technikerstrasse 21a, 6020 Innsbruck, Austria. * * This library 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.1 of the License, or (at your option) any later version. * * This library 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ import java.math.BigDecimal; import java.math.BigInteger; import java.util.Calendar; import java.util.GregorianCalendar; import javax.xml.datatype.DatatypeConstants; import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.Duration; import javax.xml.datatype.XMLGregorianCalendar; public class Main { private static int[] reverseFields = { Calendar.MILLISECOND, Calendar.SECOND, Calendar.MINUTE, Calendar.HOUR_OF_DAY, Calendar.DAY_OF_MONTH, Calendar.MONTH, Calendar.YEAR }; /** An XML data type factory for creating new objects. */ private static DatatypeFactory FACTORY; /** A useful duration value of exactly 1 second. */ private static final Duration DURATION_1_SECOND = FACTORY.newDuration(true, 0, 0, 0, 0, 0, 1); /** * Subtract one positive Duration from another, larger positive Duration. * @param d1 The larger positive duration * @param d2 The smaller positive duration * @return The difference */ private static Duration subtractSmallerPositiveDurationFromLargerPositiveDuration(Duration d1, Duration d2) { BigDecimal s1 = fractionalSeconds(d1); BigDecimal s2 = fractionalSeconds(d2); BigDecimal extraSeconds = s1.subtract(s2); Duration strip1 = stripFractionalSeconds(d1); Duration strip2 = stripFractionalSeconds(d2); Duration stripResult = strip1.subtract(strip2); if (extraSeconds.compareTo(BigDecimal.ZERO) < 0) { stripResult = stripResult.subtract(DURATION_1_SECOND); extraSeconds = extraSeconds.add(BigDecimal.ONE); } BigDecimal properSeconds = BigDecimal.valueOf(stripResult.getSeconds()).add(extraSeconds); return FACTORY.newDuration(true, BigInteger.valueOf(stripResult.getYears()), BigInteger.valueOf(stripResult.getMonths()), BigInteger.valueOf(stripResult.getDays()), BigInteger.valueOf(stripResult.getHours()), BigInteger.valueOf(stripResult.getMinutes()), properSeconds); } /** * Return just the fractional part of the seconds component of a duration object, * i.e. 1:2:34.45 => 0.45 * @param duration The duration object to examine. * @return The fractional part of the seconds field. */ private static BigDecimal fractionalSeconds(Duration duration) { BigDecimal seconds = (BigDecimal) duration.getField(DatatypeConstants.SECONDS); return seconds.subtract(new BigDecimal(seconds.toBigInteger())); } /** * Subtract one Duration from another, avoiding the runtime library bug that gives * incorrect results when using decimal seconds. * @param d1 The first duration * @param d2 The second duration * @return The result of subtracting d2 from d1 */ public static Duration subtract(Duration d1, Duration d2) { boolean sign1 = d1.getSign() >= 0; boolean sign2 = d2.getSign() >= 0; if (sign1 && sign2) { int comparison = d1.compare(d2); comparison = compare(d1, d2); if (comparison >= 0) return subtractSmallerPositiveDurationFromLargerPositiveDuration(d1, d2); else return subtractSmallerPositiveDurationFromLargerPositiveDuration(d2, d1).negate(); } if (!sign1 && !sign2) { d1 = d1.negate(); d2 = d2.negate(); int comparison = d1.compare(d2); comparison = compare(d1, d2); if (comparison < 0) return subtractSmallerPositiveDurationFromLargerPositiveDuration(d2, d1); else return subtractSmallerPositiveDurationFromLargerPositiveDuration(d1, d2).negate(); } if (sign1 && !sign2) return add(d1, d2.negate()); //if( ! sign1 && sign2 ) return add(d2, d1.negate()).negate(); } public static Duration subtract(XMLGregorianCalendar x1, XMLGregorianCalendar x2) { boolean positive = x1.compare(x2) >= 0; if (!positive) { XMLGregorianCalendar temp = x1; x1 = x2; x2 = temp; } BigDecimal s1 = getSeconds(x1); BigDecimal s2 = getSeconds(x2); BigDecimal seconds = s1.subtract(s2); if (seconds.compareTo(BigDecimal.ZERO) < 0) seconds = seconds.add(BigDecimal.valueOf(60)); GregorianCalendar g1 = x1.toGregorianCalendar(); GregorianCalendar g2 = x2.toGregorianCalendar(); int year = 0; for (int f : reverseFields) { if (f == Calendar.YEAR) { int year1 = g1.get(f); int year2 = g2.get(f); year = year1 - year2; } else { subtractField(g1, g2, f); } } return FACTORY.newDuration(positive, BigInteger.valueOf(year), BigInteger.valueOf(g1.get(Calendar.MONTH)), BigInteger.valueOf(g1.get(Calendar.DAY_OF_MONTH) - 1), BigInteger.valueOf(g1.get(Calendar.HOUR_OF_DAY)), BigInteger.valueOf(g1.get(Calendar.MINUTE)), seconds); } /** * Create a new Duration object without any fractional second component. * @param duration The duration object to strip * @return The input Duration with the fractional second part stripped off. */ private static Duration stripFractionalSeconds(Duration duration) { int year = duration.getYears(); int month = duration.getMonths(); int day = duration.getDays(); int hour = duration.getHours(); int minute = duration.getMinutes(); int second = duration.getSeconds(); boolean positive = duration.getSign() >= 0; return FACTORY.newDuration(positive, year, month, day, hour, minute, second); } /** * Add one Duration to another, avoiding the runtime library bug that gives * incorrect results when using decimal seconds. * @param d1 The first duration * @param d2 The second duration * @return The result of adding d1 to d2 */ public static Duration add(Duration d1, Duration d2) { boolean sign1 = d1.getSign() >= 0; boolean sign2 = d2.getSign() >= 0; if (sign1 && sign2) return addPositiveDurations(d1, d2); if (!sign1 && !sign2) return addPositiveDurations(d1.negate(), d2.negate()).negate(); if (sign1 && !sign2) return subtract(d1, d2.negate()); //if( ! sign1 && sign2 ) return subtract(d2, d1.negate()); } public static BigDecimal getSeconds(XMLGregorianCalendar x) { BigDecimal fractional = x.getFractionalSecond(); if (fractional == null) fractional = BigDecimal.ZERO; BigDecimal whole = BigDecimal.valueOf(x.getSecond()); return whole.add(fractional); } /** * Special compare method that gets around the problem in java 1.5, * where years and months are converted to days after arithmetic. * @param d1 First duration * @param d2 Second duration * @return -1 if d1 < d2, 0 if d1 == d2 and +1 if d1 > d2 */ public static int compare(Duration d1, Duration d2) { if (d1 == null && d2 == null) return 0; if (d1 == null) return -1; if (d2 == null) return 1; boolean b1 = d1.getSign() >= 0; boolean b2 = d2.getSign() >= 0; if (!b1 && b2) return -1; if (b1 && !b2) return 1; // Now normalise in case we are running with java 1.5 runtime javax.xml.datatype.Duration n1 = normaliseDays(d1); javax.xml.datatype.Duration n2 = normaliseDays(d2); if (n1.getDays() < n2.getDays()) return -1; if (n1.getDays() > n2.getDays()) return 1; if (n1.getHours() < n2.getHours()) return -1; if (n1.getHours() > n2.getHours()) return 1; if (n1.getMinutes() < n2.getMinutes()) return -1; if (n1.getMinutes() > n2.getMinutes()) return 1; BigDecimal s1 = (BigDecimal) n1.getField(DatatypeConstants.SECONDS); BigDecimal s2 = (BigDecimal) n2.getField(DatatypeConstants.SECONDS); return s1.compareTo(s2); } private static void subtractField(GregorianCalendar g1, GregorianCalendar g2, int field) { // int value1 = g1.get( field ); int value2 = g2.get(field); if (field == Calendar.DAY_OF_MONTH) value2 -= 1; g1.add(field, -value2); } /** * Add two positive Duration objects. * @param d1 The first Duration. * @param d2 The second Duration. * @return The sum of the two durations. */ private static Duration addPositiveDurations(Duration d1, Duration d2) { BigDecimal s1 = fractionalSeconds(d1); BigDecimal s2 = fractionalSeconds(d2); BigDecimal extraSeconds = s1.add(s2); Duration strip1 = stripFractionalSeconds(d1); Duration strip2 = stripFractionalSeconds(d2); Duration stripResult = strip1.add(strip2); if (extraSeconds.compareTo(BigDecimal.ONE) >= 0) { stripResult = stripResult.add(DURATION_1_SECOND); extraSeconds = extraSeconds.subtract(BigDecimal.ONE); } BigDecimal properSeconds = BigDecimal.valueOf(stripResult.getSeconds()).add(extraSeconds); return FACTORY.newDuration(true, BigInteger.valueOf(stripResult.getYears()), BigInteger.valueOf(stripResult.getMonths()), BigInteger.valueOf(stripResult.getDays()), BigInteger.valueOf(stripResult.getHours()), BigInteger.valueOf(stripResult.getMinutes()), properSeconds); } /** * Java runtime 1.5 is inconsistent with its handling of days in Duration objects. * @param duration A duration object to be normalised * @return A day-normalised duration, i.e. all years and months converted to days, * e.g. 1Y 3M 3D => 458 days */ private static javax.xml.datatype.Duration normaliseDays(javax.xml.datatype.Duration duration) { final long DAYS_PER_MONTH = 30; final long DAYS_PER_YEAR = 365; BigInteger days = (BigInteger) duration.getField(DatatypeConstants.DAYS); BigInteger months = (BigInteger) duration.getField(DatatypeConstants.MONTHS); BigInteger years = (BigInteger) duration.getField(DatatypeConstants.YEARS); BigInteger normalisedDays = years.multiply(BigInteger.valueOf(DAYS_PER_YEAR)); normalisedDays = normalisedDays.add(months.multiply(BigInteger.valueOf(DAYS_PER_MONTH))); normalisedDays = normalisedDays.add(days); BigInteger hours = (BigInteger) duration.getField(DatatypeConstants.HOURS); BigInteger minutes = (BigInteger) duration.getField(DatatypeConstants.MINUTES); BigDecimal seconds = (BigDecimal) duration.getField(DatatypeConstants.SECONDS); boolean positive = duration.getSign() >= 0; return FACTORY.newDuration(positive, BigInteger.ZERO, BigInteger.ZERO, normalisedDays, hours, minutes, seconds); } }