
net.fortuna.ical4j.model.Dur Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bw-ical4j-cl Show documentation
Show all versions of bw-ical4j-cl Show documentation
A fork of iCal4j with customizations for Bedework.
The newest version!
/**
* Copyright (c) 2010, Ben Fortuna
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* o Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* o Neither the name of Ben Fortuna nor the names of any other contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.fortuna.ical4j.model;
import java.io.IOException;
import java.io.Serializable;
import java.util.Calendar;
import java.util.Date;
import java.util.StringTokenizer;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* $Id: Dur.java,v 1.25 2010/03/06 12:57:24 fortuna Exp $
*
* Created on 20/06/2005
*
* Represents a duration of time in iCalendar. Note that according to RFC2445 durations represented in weeks are
* mutually exclusive of other duration fields.
*
*
* 4.3.6 Duration
*
* Value Name: DURATION
*
* Purpose: This value type is used to identify properties that contain
* a duration of time.
*
* Formal Definition: The value type is defined by the following
* notation:
*
* dur-value = (["+"] / "-") "P" (dur-date / dur-time / dur-week)
*
* dur-date = dur-day [dur-time]
* dur-time = "T" (dur-hour / dur-minute / dur-second)
* dur-week = 1*DIGIT "W"
* dur-hour = 1*DIGIT "H" [dur-minute]
* dur-minute = 1*DIGIT "M" [dur-second]
* dur-second = 1*DIGIT "S"
* dur-day = 1*DIGIT "D"
*
*
* @author Ben Fortuna
*/
public class Dur implements Comparable, Serializable {
private static final long serialVersionUID = 5013232281547134583L;
private static final int DAYS_PER_WEEK = 7;
private static final int SECONDS_PER_MINUTE = 60;
private static final int MINUTES_PER_HOUR = 60;
private static final int HOURS_PER_DAY = 24;
private static final int DAYS_PER_YEAR = 365;
private transient Log log = LogFactory.getLog(Dur.class);
private boolean negative;
private int weeks;
private int days;
private int hours;
private int minutes;
private int seconds;
/**
* Constructs a new duration instance from a string representation.
* @param value a string representation of a duration
*/
public Dur(final String value) {
negative = false;
weeks = 0;
days = 0;
hours = 0;
minutes = 0;
seconds = 0;
String token = null;
String prevToken = null;
final StringTokenizer t = new StringTokenizer(value, "+-PWDTHMS", true);
while (t.hasMoreTokens()) {
prevToken = token;
token = t.nextToken();
if ("+".equals(token)) {
negative = false;
}
else if ("-".equals(token)) {
negative = true;
}
else if ("P".equals(token)) {
// does nothing..
if (log.isDebugEnabled()) {
log.debug("Redundant [P] token ignored.");
}
}
else if ("W".equals(token)) {
weeks = Integer.parseInt(prevToken);
}
else if ("D".equals(token)) {
days = Integer.parseInt(prevToken);
}
else if ("T".equals(token)) {
// does nothing..
if (log.isDebugEnabled()) {
log.debug("Redundant [T] token ignored.");
}
}
else if ("H".equals(token)) {
hours = Integer.parseInt(prevToken);
}
else if ("M".equals(token)) {
minutes = Integer.parseInt(prevToken);
}
else if ("S".equals(token)) {
seconds = Integer.parseInt(prevToken);
}
}
}
/**
* Constructs a new duration from the specified weeks.
* @param weeks a duration in weeks.
*/
public Dur(final int weeks) {
this.weeks = Math.abs(weeks);
this.days = 0;
this.hours = 0;
this.minutes = 0;
this.seconds = 0;
this.negative = weeks < 0;
}
/**
* Constructs a new duration from the specified arguments.
* @param days duration in days
* @param hours duration in hours
* @param minutes duration in minutes
* @param seconds duration in seconds
*/
public Dur(final int days, final int hours, final int minutes,
final int seconds) {
if (!(days >= 0 && hours >= 0 && minutes >= 0 && seconds >= 0)
&& !(days <= 0 && hours <= 0 && minutes <= 0 && seconds <= 0)) {
throw new IllegalArgumentException("Invalid duration representation");
}
this.weeks = 0;
this.days = Math.abs(days);
this.hours = Math.abs(hours);
this.minutes = Math.abs(minutes);
this.seconds = Math.abs(seconds);
this.negative = days < 0 || hours < 0 || minutes < 0 || seconds < 0;
}
/**
* Constructs a new duration representing the time between the two specified dates. The end date may precede the
* start date in order to represent a negative duration.
* @param date1 the first date of the duration
* @param date2 the second date of the duration
*/
public Dur(final Date date1, final Date date2) {
Date start = null;
Date end = null;
// Negative range? (start occurs after end)
negative = date1.compareTo(date2) > 0;
if (negative) {
// Swap the dates (which eliminates the need to bother with
// negative after this!)
start = date2;
end = date1;
}
else {
start = date1;
end = date2;
}
final Calendar startCal = Calendar.getInstance();
startCal.setTime(start);
final Calendar endCal = Calendar.getInstance();
endCal.setTime(end);
// Init our duration interval (which is in units that evolve as we
// compute, below)
int dur = 0;
// Count days to get to the right year (loop in the very rare chance
// that a leap year causes us to come up short)
int nYears = endCal.get(Calendar.YEAR) - startCal.get(Calendar.YEAR);
while (nYears > 0) {
startCal.add(Calendar.DATE, DAYS_PER_YEAR * nYears);
dur += DAYS_PER_YEAR * nYears;
nYears = endCal.get(Calendar.YEAR) - startCal.get(Calendar.YEAR);
}
// Count days to get to the right day
dur += endCal.get(Calendar.DAY_OF_YEAR)
- startCal.get(Calendar.DAY_OF_YEAR);
// Count hours to get to right hour
dur *= HOURS_PER_DAY; // days -> hours
dur += endCal.get(Calendar.HOUR_OF_DAY)
- startCal.get(Calendar.HOUR_OF_DAY);
// ... to the right minute
dur *= MINUTES_PER_HOUR; // hours -> minutes
dur += endCal.get(Calendar.MINUTE) - startCal.get(Calendar.MINUTE);
// ... and second
dur *= SECONDS_PER_MINUTE; // minutes -> seconds
dur += endCal.get(Calendar.SECOND) - startCal.get(Calendar.SECOND);
// Now unwind our units
seconds = dur % SECONDS_PER_MINUTE;
dur = dur / SECONDS_PER_MINUTE; // seconds -> minutes (drop remainder seconds)
minutes = dur % MINUTES_PER_HOUR;
dur /= MINUTES_PER_HOUR; // minutes -> hours (drop remainder minutes)
hours = dur % HOURS_PER_DAY;
dur /= HOURS_PER_DAY; // hours -> days (drop remainder hours)
days = dur;
weeks = 0;
// Special case for week-only representation
if (seconds == 0 && minutes == 0 && hours == 0
&& (days % DAYS_PER_WEEK) == 0) {
weeks = days / DAYS_PER_WEEK;
days = 0;
}
}
/**
* Returns a date representing the end of this duration from the specified start date.
* @param start the date to start the duration
* @return the end of the duration as a date
*/
public final Date getTime(final Date start) {
final Calendar cal = Calendar.getInstance();
cal.setTime(start);
if (isNegative()) {
cal.add(Calendar.WEEK_OF_YEAR, -weeks);
cal.add(Calendar.DAY_OF_WEEK, -days);
cal.add(Calendar.HOUR_OF_DAY, -hours);
cal.add(Calendar.MINUTE, -minutes);
cal.add(Calendar.SECOND, -seconds);
}
else {
cal.add(Calendar.WEEK_OF_YEAR, weeks);
cal.add(Calendar.DAY_OF_WEEK, days);
cal.add(Calendar.HOUR_OF_DAY, hours);
cal.add(Calendar.MINUTE, minutes);
cal.add(Calendar.SECOND, seconds);
}
return cal.getTime();
}
/**
* Provides a negation of this instance.
* @return a Dur instance that represents a negation of this instance
*/
public final Dur negate() {
final Dur negated = new Dur(days, hours, minutes, seconds);
negated.weeks = weeks;
negated.negative = !negative;
return negated;
}
/**
* Add two durations. Durations may only be added if they are both positive
* or both negative durations.
* @param duration the duration to add to this duration
* @return a new instance representing the sum of the two durations.
*/
public final Dur add(final Dur duration) {
if ((!isNegative() && duration.isNegative())
|| (isNegative() && !duration.isNegative())) {
throw new IllegalArgumentException(
"Cannot add a negative and a positive duration");
}
Dur sum = null;
if (weeks > 0 && duration.weeks > 0) {
sum = new Dur(weeks + duration.weeks);
}
else {
int daySum = (weeks > 0) ? weeks * DAYS_PER_WEEK + days : days;
int hourSum = hours;
int minuteSum = minutes;
int secondSum = seconds;
if ((secondSum + duration.seconds) / SECONDS_PER_MINUTE > 0) {
minuteSum += (secondSum + duration.seconds) / SECONDS_PER_MINUTE;
secondSum = (secondSum + duration.seconds) % SECONDS_PER_MINUTE;
}
else {
secondSum += duration.seconds;
}
if ((minuteSum + duration.minutes) / MINUTES_PER_HOUR > 0) {
hourSum += (minuteSum + duration.minutes) / MINUTES_PER_HOUR;
minuteSum = (minuteSum + duration.minutes) % MINUTES_PER_HOUR;
}
else {
minuteSum += duration.minutes;
}
if ((hourSum + duration.hours) / HOURS_PER_DAY > 0) {
daySum += (hourSum + duration.hours) / HOURS_PER_DAY;
hourSum = (hourSum + duration.hours) % HOURS_PER_DAY;
}
else {
hourSum += duration.hours;
}
daySum += (duration.weeks > 0) ? duration.weeks * DAYS_PER_WEEK
+ duration.days : duration.days;
sum = new Dur(daySum, hourSum, minuteSum, secondSum);
}
sum.negative = negative;
return sum;
}
/**
* {@inheritDoc}
*/
public final String toString() {
final StringBuffer b = new StringBuffer();
if (negative) {
b.append('-');
}
b.append('P');
if (weeks > 0) {
b.append(weeks);
b.append('W');
}
else {
if (days > 0) {
b.append(days);
b.append('D');
}
if (hours > 0 || minutes > 0 || seconds > 0) {
b.append('T');
if (hours > 0) {
b.append(hours);
b.append('H');
}
if (minutes > 0) {
b.append(minutes);
b.append('M');
}
if (seconds > 0) {
b.append(seconds);
b.append('S');
}
}
// handle case of zero length duration
if ((hours + minutes + seconds + days + weeks) == 0) {
b.append("T0S");
}
}
return b.toString();
}
/**
* {@inheritDoc}
*/
public final int compareTo(final Object arg0) {
return compareTo((Dur) arg0);
}
/**
* Compares this duration with another, acording to their length.
* @param arg0 another duration instance
* @return a postive value if this duration is longer, zero if the duration
* lengths are equal, otherwise a negative value
*/
public final int compareTo(final Dur arg0) {
int result;
if (isNegative() != arg0.isNegative()) {
// return Boolean.valueOf(isNegative()).compareTo(Boolean.valueOf(arg0.isNegative()));
// for pre-java 1.5 compatibility..
if (isNegative()) {
return Integer.MIN_VALUE;
}
else {
return Integer.MAX_VALUE;
}
}
else if (getWeeks() != arg0.getWeeks()) {
result = getWeeks() - arg0.getWeeks();
}
else if (getDays() != arg0.getDays()) {
result = getDays() - arg0.getDays();
}
else if (getHours() != arg0.getHours()) {
result = getHours() - arg0.getHours();
}
else if (getMinutes() != arg0.getMinutes()) {
result = getMinutes() - arg0.getMinutes();
}
else {
result = getSeconds() - arg0.getSeconds();
}
// invert sense of all tests if both durations are negative
if (isNegative()) {
return -result;
}
else {
return result;
}
}
/**
* {@inheritDoc}
*/
public boolean equals(final Object obj) {
if (obj instanceof Dur) {
return ((Dur) obj).compareTo(this) == 0;
}
return super.equals(obj);
}
/**
* {@inheritDoc}
*/
public int hashCode() {
return new HashCodeBuilder().append(weeks).append(days).append(
hours).append(minutes).append(seconds).append(negative).toHashCode();
}
/**
* @return Returns the days.
*/
public final int getDays() {
return days;
}
/**
* @return Returns the hours.
*/
public final int getHours() {
return hours;
}
/**
* @return Returns the minutes.
*/
public final int getMinutes() {
return minutes;
}
/**
* @return Returns the negative.
*/
public final boolean isNegative() {
return negative;
}
/**
* @return Returns the seconds.
*/
public final int getSeconds() {
return seconds;
}
/**
* @return Returns the weeks.
*/
public final int getWeeks() {
return weeks;
}
/**
* @param stream
* @throws IOException
* @throws ClassNotFoundException
*/
private void readObject(final java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException {
stream.defaultReadObject();
log = LogFactory.getLog(Dur.class);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy