src/net/fortuna/ical4j/model/Period.java

Tue, 10 Feb 2015 18:12:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 10 Feb 2015 18:12:00 +0100
changeset 0
fb9019fb1bf7
child 4
45d57ecba757
permissions
-rw-r--r--

Import initial revisions of existing project AndroidCaldavSyncAdapater,
forked from upstream repository at 27e8a0f8495c92e0780d450bdf0c7cec77a03a55.

     1 /**
     2  * Copyright (c) 2012, Ben Fortuna
     3  * All rights reserved.
     4  *
     5  * Redistribution and use in source and binary forms, with or without
     6  * modification, are permitted provided that the following conditions
     7  * are met:
     8  *
     9  *  o Redistributions of source code must retain the above copyright
    10  * notice, this list of conditions and the following disclaimer.
    11  *
    12  *  o Redistributions in binary form must reproduce the above copyright
    13  * notice, this list of conditions and the following disclaimer in the
    14  * documentation and/or other materials provided with the distribution.
    15  *
    16  *  o Neither the name of Ben Fortuna nor the names of any other contributors
    17  * may be used to endorse or promote products derived from this software
    18  * without specific prior written permission.
    19  *
    20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
    24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
    25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
    27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
    28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
    29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    31  */
    32 package net.fortuna.ical4j.model;
    34 import java.text.ParseException;
    35 import java.util.Date;
    37 import org.apache.commons.lang.builder.EqualsBuilder;
    38 import org.apache.commons.lang.builder.HashCodeBuilder;
    40 /**
    41  * $Id$ [Apr 14, 2004]
    42  *
    43  * Defines a period of time. A period may be specified as either a start date
    44  * and end date, or a start date and duration. NOTE: End dates and durations are
    45  * implicitly derived when not explicitly specified. This means that you cannot
    46  * rely on the returned values from the getters to deduce whether a period has
    47  * an explicit end date or duration.
    48  * 
    49  * @author Ben Fortuna
    50  */
    51 public class Period extends DateRange implements Comparable {
    53     private static final long serialVersionUID = 7321090422911676490L;
    55     private Dur duration;
    57     /**
    58      * Constructor.
    59      * 
    60      * @param aValue
    61      *            a string representation of a period
    62      * @throws ParseException
    63      *             where the specified string is not a valid representation
    64      */
    65     public Period(final String aValue) throws ParseException {
    66         super(parseStartDate(aValue), parseEndDate(aValue, true));
    68         // period may end in either a date-time or a duration..
    69         try {
    70             parseEndDate(aValue, false);
    71         }
    72         catch (ParseException pe) {
    73             // duration = DurationFormat.getInstance().parse(aValue);
    74             duration = parseDuration(aValue);
    75         }
    76         normalise();
    77     }
    79     /**
    80      * Constructs a new period with the specied start and end date.
    81      * 
    82      * @param start
    83      *            the start date of the period
    84      * @param end
    85      *            the end date of the period
    86      */
    87     public Period(final DateTime start, final DateTime end) {
    88         super(start, end);
    89         normalise();
    90     }
    92     /**
    93      * Constructs a new period with the specified start date and duration.
    94      * 
    95      * @param start
    96      *            the start date of the period
    97      * @param duration
    98      *            the duration of the period
    99      */
   100     public Period(final DateTime start, final Dur duration) {
   101         super(start, new DateTime(duration.getTime(start)));
   102         this.duration = duration;
   103         normalise();
   104     }
   106     private static DateTime parseStartDate(String value) throws ParseException {
   107         return new DateTime(value.substring(0, value.indexOf('/')));
   108     }
   110     private static DateTime parseEndDate(String value, boolean resolve) throws ParseException {
   111         DateTime end = null;
   112         try {
   113             end = new DateTime(value.substring(value.indexOf('/') + 1));
   114         }
   115         catch (ParseException e) {
   116             if (resolve) {
   117                 final Dur duration = parseDuration(value);
   118                 end = new DateTime(duration.getTime(parseStartDate(value)));
   119             }
   120             else {
   121                 throw e;
   122             }
   123         }
   124         return end;
   125     }
   127     private static Dur parseDuration(String value) {
   128         return new Dur(value.substring(value.indexOf('/') + 1));
   129     }
   131     private void normalise() {
   132         // ensure the end timezone is the same as the start..
   133         if (getStart().isUtc()) {
   134             getEnd().setUtc(true);
   135         }
   136         else {
   137             getEnd().setTimeZone(getStart().getTimeZone());
   138         }
   139     }
   141     /**
   142      * Returns the duration of this period. If an explicit duration is not
   143      * specified, the duration is derived from the end date.
   144      * 
   145      * @return the duration of this period in milliseconds.
   146      */
   147     public final Dur getDuration() {
   148         if (duration == null) {
   149             return new Dur(getStart(), getEnd());
   150         }
   151         return duration;
   152     }
   154     /**
   155      * Returns the end date of this period. If an explicit end date is not
   156      * specified, the end date is derived from the duration.
   157      * 
   158      * @return the end date of this period.
   159      */
   160     public final DateTime getEnd() {
   161         return (DateTime) getRangeEnd();
   162     }
   164     /**
   165      * @return Returns the start.
   166      */
   167     public final DateTime getStart() {
   168         return (DateTime) getRangeStart();
   169     }
   171     /**
   172      * @param date a date to test for inclusion
   173      * @param inclusive indicates if the start and end of the period are included in the test
   174      * @return true if the specified date occurs within the current period
   175      * @deprecated use {@link Period#includes(Date, int)} instead.
   176      */
   177     public final boolean includes(final Date date, final boolean inclusive) {
   178         if (inclusive) {
   179             return includes(date, INCLUSIVE_START | INCLUSIVE_END);
   180         }
   181         else {
   182             return includes(date, 0);
   183         }
   184     }
   186     /**
   187      * Creates a period that encompasses both this period and another one. If
   188      * the other period is null, return a copy of this period. NOTE: Resulting
   189      * periods are specified by explicitly setting a start date and end date
   190      * (i.e. durations are implied).
   191      * 
   192      * @param period
   193      *            the period to add to this one
   194      * @return a period
   195      */
   196     public final Period add(final Period period) {
   197         DateTime newPeriodStart = null;
   198         DateTime newPeriodEnd = null;
   200         if (period == null) {
   201             newPeriodStart = getStart();
   202             newPeriodEnd = getEnd();
   203         }
   204         else {
   205             if (getStart().before(period.getStart())) {
   206                 newPeriodStart = getStart();
   207             }
   208             else {
   209                 newPeriodStart = period.getStart();
   210             }
   211             if (getEnd().after(period.getEnd())) {
   212                 newPeriodEnd = getEnd();
   213             }
   214             else {
   215                 newPeriodEnd = period.getEnd();
   216             }
   217         }
   219         return new Period(newPeriodStart, newPeriodEnd);
   220     }
   222     /**
   223      * Creates a set of periods resulting from the subtraction of the specified
   224      * period from this one. If the specified period is completely contained
   225      * in this period, the resulting list will contain two periods. Otherwise
   226      * it will contain one. If the specified period does not interest this period
   227      * a list containing this period is returned. If this period is completely
   228      * contained within the specified period an empty period list is returned.
   229      * @param period a period to subtract from this one
   230      * @return a list containing zero, one or two periods.
   231      */
   232     public final PeriodList subtract(final Period period) {
   233         final PeriodList result = new PeriodList();
   235         if (period.contains(this)) {
   236             return result;
   237         }
   238         else if (!period.intersects(this)) {
   239             result.add(this);
   240             return result;
   241         }
   243         DateTime newPeriodStart;
   244         DateTime newPeriodEnd;
   245         if (!period.getStart().after(getStart())) {
   246             newPeriodStart = period.getEnd();
   247             newPeriodEnd = getEnd();
   248         }
   249         else if (!period.getEnd().before(getEnd())) {
   250             newPeriodStart = getStart();
   251             newPeriodEnd = period.getStart();
   252         }
   253         else {
   254             // subtraction consumed by this period..
   255             // initialise and add head period..
   256             newPeriodStart = getStart();
   257             newPeriodEnd = period.getStart();
   258             result.add(new Period(newPeriodStart, newPeriodEnd));
   259             // initialise tail period..
   260             newPeriodStart = period.getEnd();
   261             newPeriodEnd = getEnd();
   262         }
   263         result.add(new Period(newPeriodStart, newPeriodEnd));
   264         return result;
   265     }
   267     /**
   268      * An empty period is one that consumes no time.
   269      * @return true if this period consumes no time, otherwise false
   270      */
   271     public final boolean isEmpty() {
   272         return getStart().equals(getEnd());
   273     }
   275     /**
   276      * Updates the start and (possible) end times of this period to reflect
   277      * the specified UTC timezone status.
   278      * @param utc indicates whether the period is in UTC time
   279      */
   280     public void setUtc(final boolean utc) {
   281         getStart().setUtc(utc);
   282         getEnd().setUtc(utc);
   283     }
   285     /**
   286      * Updates the start and (possible) end times of this period to reflect
   287      * the specified timezone status.
   288      * @param timezone a timezone for the period
   289      */
   290     public final void setTimeZone(final TimeZone timezone) {
   291         getStart().setUtc(false);
   292         getStart().setTimeZone(timezone);
   293         getEnd().setUtc(false);
   294         getEnd().setTimeZone(timezone);
   295     }
   297     /**
   298      * {@inheritDoc}
   299      */
   300     public final String toString() {
   301         final StringBuffer b = new StringBuffer();
   302         b.append(getStart());
   303         b.append('/');
   304         if (duration == null) {
   305             b.append(getEnd());
   306         }
   307         else {
   308             // b.append(DurationFormat.getInstance().format(duration));
   309             b.append(duration);
   310         }
   311         return b.toString();
   312     }
   314     /**
   315      * {@inheritDoc}
   316      */
   317     public final int compareTo(final Object arg0) {
   318         return compareTo((Period) arg0);
   319     }
   321     /**
   322      * Compares the specified period with this period.
   323      * 
   324      * @param arg0 a period to compare with this one
   325      * @return a postive value if this period is greater, negative if the other is
   326      * greater, or zero if they are equal
   327      */
   328     public final int compareTo(final Period arg0) {
   329         // Throws documented exception if type is wrong or parameter is null
   330         if (arg0 == null) {
   331             throw new ClassCastException("Cannot compare this object to null");
   332         }
   333         final int startCompare = getStart().compareTo(arg0.getStart());
   334         if (startCompare != 0) {
   335             return startCompare;
   336         }
   337         // start dates are equal, compare end dates..
   338         else if (duration == null) {
   339             final int endCompare = getEnd().compareTo(arg0.getEnd());
   340             if (endCompare != 0) {
   341                 return endCompare;
   342             }
   343         }
   344         // ..or durations
   345         return getDuration().compareTo(arg0.getDuration());
   346     }
   348     /**
   349      * {@inheritDoc}
   350      */
   351     public final boolean equals(final Object o) {
   352         if (this == o) {
   353             return true;
   354         }
   355         if (!(o instanceof Period)) {
   356             return false;
   357         }
   359         final Period period = (Period) o;
   360         return new EqualsBuilder().append(getStart(), period.getStart())
   361             .append(getEnd(), period.getEnd()).isEquals();
   362     }
   364     /**
   365      * {@inheritDoc}
   366      */
   367     public final int hashCode() {
   368         return new HashCodeBuilder().append(getStart())
   369             .append((duration == null) ? (Object) getEnd() : duration).toHashCode();
   370     }
   371 }

mercurial