/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2008, Open Source Geospatial Foundation (OSGeo)
*
* 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;
* version 2.1 of the License.
*
* 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.
*/
package org.geotools.temporal.object;
import org.geotools.util.Utilities;
import org.geotools.util.SimpleInternationalString;
import org.opengis.temporal.PeriodDuration;
import org.opengis.util.InternationalString;
/**
* Uses the format specified by ISO 8601 for exchanging information
* about the duration of a period.
*
* @author Mehdi Sidhoum (Geomatys)
*
* @source $URL$
*/
public class DefaultPeriodDuration extends DefaultDuration implements PeriodDuration {
private static final InternationalString DESIGNATOR = new SimpleInternationalString("P");
private InternationalString years;
private InternationalString months;
private InternationalString weeks;
private InternationalString days;
private static final InternationalString TIME_INDICATOR = new SimpleInternationalString("T");
private InternationalString hours;
private InternationalString minutes;
private InternationalString seconds;
/**
* Creates a new instances of PeriodDuration.
* @param years
* @param months
* @param weeks
* @param days
* @param hours
* @param minutes
* @param seconds
*/
public DefaultPeriodDuration(InternationalString years, InternationalString months, InternationalString week, InternationalString days,
InternationalString hours, InternationalString minutes, InternationalString seconds) {
this.years = years;
this.months = months;
this.weeks = week;
this.days = days;
this.hours = hours;
this.minutes = minutes;
this.seconds = seconds;
}
/**
* Creates a new instance of PeriodDuration from a long value passed in parameter.
* if the long contains milliseconds, this will be ignored because there is no MilliSeconds specified in the string format PnYnMnDTnHnMnS, see ISO 8601.
* @param durationInMilliSeconds
*/
public DefaultPeriodDuration(long durationInMilliSeconds) {
long yearMS = 31536000000L;
long monthMS = 2628000000L;
long weekMS = 604800000L;
long dayMS = 86400000L;
long hourMS = 3600000L;
long minMS = 60000L;
long secondMS = 1000L;
InternationalString _years = null;
InternationalString _months = null;
InternationalString _week = null;
InternationalString _days = null;
InternationalString _hours = null;
InternationalString _minutes = null;
InternationalString _seconds = null;
long temp = durationInMilliSeconds / yearMS;
if (temp >= 1) {
_years = new SimpleInternationalString(String.valueOf(temp));
durationInMilliSeconds -= temp * yearMS;
}
this.years = _years;
temp = durationInMilliSeconds / monthMS;
if (temp >= 1) {
_months = new SimpleInternationalString(String.valueOf(temp));
durationInMilliSeconds -= temp * monthMS;
}
this.months = _months;
temp = durationInMilliSeconds / weekMS;
if (temp >= 1) {
_week = new SimpleInternationalString(String.valueOf(temp));
durationInMilliSeconds -= temp * weekMS;
}
this.weeks = _week;
//we look if the gap is more than one day (86400000 ms)
temp = durationInMilliSeconds / dayMS;
if (temp >= 1) {
_days = new SimpleInternationalString(String.valueOf(temp));
durationInMilliSeconds -= temp * dayMS;
}
this.days = _days;
temp = durationInMilliSeconds / hourMS;
if (temp >= 1) {
_hours = new SimpleInternationalString(String.valueOf(temp));
durationInMilliSeconds -= temp * hourMS;
}
this.hours = _hours;
temp = durationInMilliSeconds / minMS;
if (temp >= 1) {
_minutes = new SimpleInternationalString(String.valueOf(temp));
durationInMilliSeconds -= temp * minMS;
}
this.minutes = _minutes;
temp = durationInMilliSeconds / secondMS;
if (temp >= 1) {
_seconds = new SimpleInternationalString(String.valueOf(temp));
durationInMilliSeconds -= temp * secondMS;
}
this.seconds = _seconds;
/*if (durationInMilliSeconds != 0) {
throw new IllegalArgumentException("PeriodDuration can't be found at the Millisecond precision in the pattern PnYnMnDTnHnMnS specified by ISO 8601.");
}*/
}
/**
* A mandatory element which designates that the returned string
* represents the duration of a period.
*/
public InternationalString getDesignator() {
return DESIGNATOR;
}
/**
* A positive integer, followed by the character "Y",
* which indicated the number of years in the period.
*/
public InternationalString getYears() {
return years;
}
/**
* A positive integer, followed by the character "M",
* which indicated the number of months in the period.
*/
public InternationalString getMonths() {
return months;
}
/**
* A positive integer, followed by the character "D",
* which indicated the number of days in the period.
*/
public InternationalString getDays() {
return days;
}
/**
* Included whenever the sequence includes values for
* units less than a day.
*/
public InternationalString getTimeIndicator() {
return TIME_INDICATOR;
}
/**
* A positive integer, followed by the character "H",
* which indicated the number of hours in the period.
*/
public InternationalString getHours() {
return hours;
}
/**
* A positive integer, followed by the character "M",
* which indicated the number of minutes in the period.
*/
public InternationalString getMinutes() {
return minutes;
}
/**
* A positive integer, followed by the character "S",
* which indicated the number of seconds in the period.
*/
public InternationalString getSeconds() {
return seconds;
}
public void setYears(InternationalString years) {
this.years = years;
}
public void setMonths(InternationalString months) {
this.months = months;
}
public void setDays(InternationalString days) {
this.days = days;
}
public void setHours(InternationalString hours) {
this.hours = hours;
}
public void setMinutes(InternationalString minutes) {
this.minutes = minutes;
}
public void setSeconds(InternationalString seconds) {
this.seconds = seconds;
}
public InternationalString getWeek() {
return weeks;
}
public void setWeek(InternationalString week) {
this.weeks = week;
}
/**
* Returns a duration in long. note there is no starting instant to accurate the returned value.
* @return
*/
public long getTimeInMillis() {
String periodDescription = this.toString();
long yearMS = 31536000000L;
long monthMS = 2628000000L;
long weekMS = 604800000L;
long dayMS = 86400000L;
long hourMS = 3600000L;
long minMS = 60000L;
long secondMS = 1000L;
long response = 0;
//removing the 'P' character
periodDescription = periodDescription.substring(1);
//if the period contains years (31536000000 ms) the response will be incremented
if (periodDescription.indexOf('Y') != -1) {
int nbYear = Integer.parseInt(periodDescription.substring(0, periodDescription.indexOf('Y')));
response += nbYear * yearMS;
periodDescription = periodDescription.substring(periodDescription.indexOf('Y') + 1);
}
//if the period contains months (2628000000 ms)
if ((periodDescription.indexOf('M') != -1 && (periodDescription.indexOf('T') == -1)) ||
((periodDescription.indexOf('T') != -1) &&
(periodDescription.indexOf('M') < periodDescription.indexOf('T')) &&
((periodDescription.indexOf('M') != -1)))) {
int nbMonth = Integer.parseInt(periodDescription.substring(0, periodDescription.indexOf('M')));
response += nbMonth * monthMS;
periodDescription = periodDescription.substring(periodDescription.indexOf('M') + 1);
}
//if the period contains weeks (604800000 ms)
if (periodDescription.indexOf('W') != -1) {
int nbWeek = Integer.parseInt(periodDescription.substring(0, periodDescription.indexOf('W')));
response += nbWeek * weekMS;
periodDescription = periodDescription.substring(periodDescription.indexOf('W') + 1);
}
//if the period contains days (86400000 ms)
if (periodDescription.indexOf('D') != -1) {
int nbDay = Integer.parseInt(periodDescription.substring(0, periodDescription.indexOf('D')));
response += nbDay * dayMS;
periodDescription = periodDescription.substring(periodDescription.indexOf('D') + 1);
}
// removing 'T' character if exists
if (periodDescription.indexOf('T') != -1) {
periodDescription = periodDescription.substring(1);
}
//if the period contains hours (3600000 ms)
if (periodDescription.indexOf('H') != -1) {
int nbHour = Integer.parseInt(periodDescription.substring(0, periodDescription.indexOf('H')));
response += nbHour * hourMS;
periodDescription = periodDescription.substring(periodDescription.indexOf('H') + 1);
}
//if the period contains minutes (60000 ms)
if (periodDescription.indexOf('M') != -1) {
int nbMin = Integer.parseInt(periodDescription.substring(0, periodDescription.indexOf('M')));
response += nbMin * minMS;
periodDescription = periodDescription.substring(periodDescription.indexOf('M') + 1);
}
//if the period contains seconds (1000 ms)
if (periodDescription.indexOf('S') != -1) {
int nbSec = Integer.parseInt(periodDescription.substring(0, periodDescription.indexOf('S')));
response += nbSec * secondMS;
periodDescription = periodDescription.substring(periodDescription.indexOf('S') + 1);
}
if (periodDescription.length() != 0) {
throw new IllegalArgumentException("The period duration string is malformed");
}
return response;
}
@Override
public boolean equals(final Object object) {
if (object == this) {
return true;
}
if (object instanceof DefaultPeriodDuration) {
final DefaultPeriodDuration that = (DefaultPeriodDuration) object;
return Utilities.equals(this.days, that.days) &&
Utilities.equals(this.hours, that.hours) &&
Utilities.equals(this.minutes, that.minutes) &&
Utilities.equals(this.months, that.months) &&
Utilities.equals(this.seconds, that.seconds) &&
Utilities.equals(this.years, that.years);
}
return false;
}
@Override
public int hashCode() {
int hash = 5;
hash = 37 * hash + (this.days != null ? this.days.hashCode() : 0);
hash = 37 * hash + (this.hours != null ? this.hours.hashCode() : 0);
hash = 37 * hash + (this.minutes != null ? this.minutes.hashCode() : 0);
hash = 37 * hash + (this.months != null ? this.months.hashCode() : 0);
hash = 37 * hash + (this.seconds != null ? this.seconds.hashCode() : 0);
hash = 37 * hash + (this.years != null ? this.years.hashCode() : 0);
return hash;
}
@Override
/**
* Returns a duration value String in format 8601. the pattern is PnYnMnDTnHnMnS.
*/
public String toString() {
StringBuilder s = new StringBuilder();
s.append(DESIGNATOR);
if (years != null) {
s.append(years).append("Y");
}
if (months != null) {
s.append(months).append("M");
}
if (weeks != null) {
s.append(weeks).append("W");
}
if (days != null) {
s.append(days).append("D");
}
if (hours != null || minutes != null || seconds != null) {
s.append(TIME_INDICATOR);
}
if (hours != null) {
s.append(hours).append("H");
}
if (minutes != null) {
s.append(minutes).append("M");
}
if (seconds != null) {
s.append(seconds).append("S");
}
return s.toString();
}
}