blob: 33a304b2b47ed2878d03bdd8f84b621bff071cdf [file] [log] [blame]
/*
* Copyright 2002-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.axis2.databinding.types;
import java.io.Serializable;
import java.util.Calendar;
/**
* Implementation of the XML Schema type duration. Duration supports a minimum
* fractional second precision of milliseconds.
*
* @see <a href="http://www.w3.org/TR/xmlschema-2/#duration">XML Schema 3.2.6</a>
*/
public class Duration implements Serializable {
private static final long serialVersionUID = -3736760992541369098L;
boolean isNegative;
int years;
int months;
int days;
int hours;
int minutes;
double seconds;
/**
* Default no-arg constructor
*/
public Duration() {
}
/**
* @param negative
* @param aYears
* @param aMonths
* @param aDays
* @param aHours
* @param aMinutes
* @param aSeconds
*/
public Duration(boolean negative, int aYears, int aMonths, int aDays,
int aHours, int aMinutes, double aSeconds) {
isNegative = negative;
years = aYears;
months = aMonths;
days = aDays;
hours = aHours;
minutes = aMinutes;
setSeconds(aSeconds);
}
/**
* Constructs Duration from a String in an xsd:duration format -
* PnYnMnDTnHnMnS.
*
* @param duration String
* @throws SchemaException if the string doesn't parse correctly.
*/
public Duration(String duration) throws IllegalArgumentException {
int position = 1;
int timePosition = duration.indexOf("T");
// P is required but P by itself is invalid
if (duration.indexOf("P") == -1 || duration.equals("P")) {
throw new IllegalArgumentException();
// Messages.getMessage("badDuration"));
}
// if present, time cannot be empty
if (duration.lastIndexOf("T") == duration.length() - 1) {
throw new IllegalArgumentException();
// Messages.getMessage("badDuration"));
}
// check the sign
if (duration.startsWith("-")) {
isNegative = true;
position++;
}
// parse time part
if (timePosition != -1) {
parseTime(duration.substring(timePosition + 1));
} else {
timePosition = duration.length();
}
// parse date part
if (position != timePosition) {
parseDate(duration.substring(position, timePosition));
}
}
/**
* Constructs Duration from a Calendar.
*
* @param calendar Calendar
* @throws IllegalArgumentException if the calendar object does not
* represent any date nor time.
*/
public Duration(boolean negative, Calendar calendar) throws
IllegalArgumentException {
this.isNegative = negative;
this.years = calendar.get(Calendar.YEAR);
this.months = calendar.get(Calendar.MONTH);
this.days = calendar.get(Calendar.DATE);
this.hours = calendar.get(Calendar.HOUR);
this.minutes = calendar.get(Calendar.MINUTE);
this.seconds = calendar.get(Calendar.SECOND);
this.seconds += ((double) calendar.get(Calendar.MILLISECOND)) / 100;
if (years == 0 && months == 0 && days == 0 && hours == 0 &&
minutes == 0 && seconds == 0) {
throw new IllegalArgumentException();
//Messages.getMessage("badCalendarForDuration"));
}
}
/**
* This method parses the time portion of a String that represents
* xsd:duration - nHnMnS.
*
* @param time
* @throws IllegalArgumentException if time does not match pattern
*
*/
public void parseTime(String time) throws IllegalArgumentException {
if (time.length() == 0 || time.indexOf("-") != -1) {
throw new IllegalArgumentException();
//Messages.getMessage("badTimeDuration"));
}
// check if time ends with either H, M, or S
if (!time.endsWith("H") && !time.endsWith("M") && !time.endsWith("S")) {
throw new IllegalArgumentException();
//Messages.getMessage("badTimeDuration"));
}
try {
// parse string and extract hours, minutes, and seconds
int start = 0;
// Hours
int end = time.indexOf("H");
// if there is H in a string but there is no value for hours,
// throw an exception
if (start == end) {
throw new IllegalArgumentException();
//Messages.getMessage("badTimeDuration"));
}
if (end != -1) {
hours = Integer.parseInt(time.substring(0, end));
start = end + 1;
}
// Minutes
end = time.indexOf("M");
// if there is M in a string but there is no value for hours,
// throw an exception
if (start == end) {
throw new IllegalArgumentException();
// Messages.getMessage("badTimeDuration"));
}
if (end != -1) {
minutes = Integer.parseInt(time.substring(start, end));
start = end + 1;
}
// Seconds
end = time.indexOf("S");
// if there is S in a string but there is no value for hours,
// throw an exception
if (start == end) {
throw new IllegalArgumentException();
//Messages.getMessage("badTimeDuration"));
}
if (end != -1) {
setSeconds(Double.parseDouble(time.substring(start, end)));
}
} catch (NumberFormatException e) {
throw new IllegalArgumentException();
//Messages.getMessage("badTimeDuration"));
}
}
/**
* This method parses the date portion of a String that represents
* xsd:duration - nYnMnD.
*
* @param date
* @throws IllegalArgumentException if date does not match pattern
*
*/
public void parseDate(String date) throws IllegalArgumentException {
if (date.length() == 0 || date.indexOf("-") != -1) {
throw new IllegalArgumentException();
//Messages.getMessage("badDateDuration"));
}
// check if date string ends with either Y, M, or D
if (!date.endsWith("Y") && !date.endsWith("M") && !date.endsWith("D")) {
throw new IllegalArgumentException();
//Messages.getMessage("badDateDuration"));
}
// catch any parsing exception
try {
// parse string and extract years, months, days
int start = 0;
int end = date.indexOf("Y");
// if there is Y in a string but there is no value for years,
// throw an exception
if (start == end) {
throw new IllegalArgumentException();
// Messages.getMessage("badDateDuration"));
}
if (end != -1) {
years = Integer.parseInt(date.substring(0, end));
start = end + 1;
}
// months
end = date.indexOf("M");
// if there is M in a string but there is no value for months,
// throw an exception
if (start == end) {
throw new IllegalArgumentException();
//Messages.getMessage("badDateDuration"));
}
if (end != -1) {
months = Integer.parseInt(date.substring(start, end));
start = end + 1;
}
end = date.indexOf("D");
// if there is D in a string but there is no value for days,
// throw an exception
if (start == end) {
throw new IllegalArgumentException();
// Messages.getMessage("badDateDuration"));
}
if (end != -1) {
days = Integer.parseInt(date.substring(start, end));
}
} catch (NumberFormatException e) {
throw new IllegalArgumentException();
//Messages.getMessage("badDateDuration"));
}
}
/**
*
*/
public boolean isNegative() {
return isNegative;
}
/**
*
*/
public int getYears() {
return years;
}
/**
*
*/
public int getMonths() {
return months;
}
/**
*
*/
public int getDays() {
return days;
}
/**
*
*/
public int getHours() {
return hours;
}
/**
*
*/
public int getMinutes() {
return minutes;
}
/**
*
*/
public double getSeconds() {
return seconds;
}
/**
* @param negative
*/
public void setNegative(boolean negative) {
isNegative = negative;
}
/**
* @param years
*/
public void setYears(int years) {
this.years = years;
}
/**
* @param months
*/
public void setMonths(int months) {
this.months = months;
}
/**
* @param days
*/
public void setDays(int days) {
this.days = days;
}
/**
* @param hours
*/
public void setHours(int hours) {
this.hours = hours;
}
/**
* @param minutes
*/
public void setMinutes(int minutes) {
this.minutes = minutes;
}
/**
* @param seconds
* @deprecated use {@link #setSeconds(double) setSeconds(double)}
* instead
*/
public void setSeconds(int seconds) {
this.seconds = seconds;
}
/**
* Sets the seconds. NOTE: The fractional value of seconds is rounded up to
* milliseconds.
*
* @param seconds double
*/
public void setSeconds(double seconds) {
this.seconds = ((double) (Math.round(seconds * 100))) / 100;
}
/**
* This returns the xml representation of an xsd:duration object.
*/
public String toString() {
StringBuffer duration = new StringBuffer();
duration.append("P");
if (years != 0) {
duration.append(years).append("Y");
}
if (months != 0) {
duration.append(months).append("M");
}
if (days != 0) {
duration.append(days).append("D");
}
if (hours != 0 || minutes != 0 || seconds != 0.0) {
duration.append("T");
if (hours != 0) {
duration.append(hours).append("H");
}
if (minutes != 0) {
duration.append(minutes).append("M");
}
if (seconds != 0) {
if (seconds == (int) seconds) {
duration.append((int) seconds).append("S");
} else {
duration.append(seconds).append("S");
}
}
}
if (duration.length() == 1) {
duration.append("T0S");
}
if (isNegative) {
duration.insert(0, "-");
}
return duration.toString();
}
/**
* The equals method compares the time represented by duration object, not
* its string representation.
* Hence, a duration object representing 65 minutes is considered equal to a
* duration object representing 1 hour and 5 minutes.
*
* @param object
*/
public boolean equals(Object object) {
if (!(object instanceof Duration)) {
return false;
}
Duration duration = (Duration) object;
return this.isNegative == duration.isNegative &&
this.getAsCalendar().equals(duration.getAsCalendar());
}
public int hashCode() {
int hashCode = 0;
if (isNegative) {
hashCode++;
}
hashCode += years;
hashCode += months;
hashCode += days;
hashCode += hours;
hashCode += minutes;
hashCode += seconds;
// milliseconds
hashCode += (seconds * 100) % 100;
return hashCode;
}
/**
* Returns duration as a calendar. Due to the way a Calendar class works,
* the values for particular fields may not be the same as obtained through
* getter methods. For example, if a duration's object getMonths
* returns 20, a similar call on a calendar object will return 1 year and
* 8 months.
*
* @return Calendar
*/
public Calendar getAsCalendar() {
return getAsCalendar(Calendar.getInstance());
}
/**
* Returns duration as a calendar. Due to the way a Calendar class works,
* the values for particular fields may not be the same as obtained through
* getter methods. For example, if a Duration's object getMonths
* returns 20, a similar call on a Calendar object will return 1 year and
* 8 months.
*
* @param startTime Calendar
* @return Calendar
*/
public Calendar getAsCalendar(Calendar startTime) {
Calendar ret = (Calendar) startTime.clone();
ret.set(Calendar.YEAR, years);
ret.set(Calendar.MONTH, months);
ret.set(Calendar.DATE, days);
ret.set(Calendar.HOUR, hours);
ret.set(Calendar.MINUTE, minutes);
ret.set(Calendar.SECOND, (int) seconds);
ret.set(Calendar.MILLISECOND,
(int) (seconds * 100 - Math.round(seconds) * 100));
return ret;
}
}