Home » xmlbeans-2.5.0-src » org.apache » xmlbeans » [javadoc | source]

    1   /*   Copyright 2004 The Apache Software Foundation
    2    *
    3    *   Licensed under the Apache License, Version 2.0 (the "License");
    4    *   you may not use this file except in compliance with the License.
    5    *   You may obtain a copy of the License at
    6    *
    7    *       http://www.apache.org/licenses/LICENSE-2.0
    8    *
    9    *   Unless required by applicable law or agreed to in writing, software
   10    *   distributed under the License is distributed on an "AS IS" BASIS,
   11    *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   12    *   See the License for the specific language governing permissions and
   13    *  limitations under the License.
   14    */
   15   
   16   package org.apache.xmlbeans;
   17   
   18   import java.math.BigDecimal;
   19   
   20   /**
   21    * Represents an XML Schema-compatible duration.
   22    * <p>
   23    * A duration is made up of a number of years, months, days, hours,
   24    * minutes, seconds, and fractions of seconds. See the
   25    * XML Schema specification
   26    * <a target="_blank" href="http://www.w3.org/TR/xmlschema-2/#duration">section on xs:duration</a>
   27    * for details on the rules for
   28    * <a target="_blank" href="http://www.w3.org/TR/xmlschema-2/#duration-order">comparing durations</a> and
   29    * <a target="_blank" href="http://www.w3.org/TR/xmlschema-2/#adding-durations-to-dateTimes">adding durations to dates</a>.
   30    */
   31   public final class GDuration implements GDurationSpecification, java.io.Serializable
   32   {
   33       private static final long serialVersionUID = 1L;
   34       
   35       private int _sign;
   36       private int _CY;
   37       private int _M;
   38       private int _D;
   39       private int _h;
   40       private int _m;
   41       private int _s;
   42       private BigDecimal _fs;
   43   
   44       /**
   45        * Constructs an empty GDuration representing zero seconds.
   46        */
   47       public GDuration()
   48       {
   49           _sign = +1;
   50           _fs = GDate._zero;
   51       }
   52   
   53       private static final int SEEN_NOTHING = 0;
   54       private static final int SEEN_YEAR = 1;
   55       private static final int SEEN_MONTH = 2;
   56       private static final int SEEN_DAY = 3;
   57       private static final int SEEN_HOUR = 4;
   58       private static final int SEEN_MINUTE = 5;
   59       private static final int SEEN_SECOND = 6;
   60   
   61       /**
   62        * Constructs a GDuration from a lexical
   63        * representation. The lexical space contains the
   64        * union of the lexical spaces of all the schema
   65        * date/time types (except for duration).
   66        */
   67       public GDuration(CharSequence str)
   68       {
   69           // Form:        -PnYnMnDTnHnMnS
   70           // (where each n may be preceded by a - for us, and the whole may be -)
   71   
   72           // first trim XML whitespace
   73           int len = str.length();
   74           int start = 0;
   75           while (len > 0 && GDate.isSpace(str.charAt(len - 1)))
   76               len -= 1;
   77           while (start < len && GDate.isSpace(str.charAt(start)))
   78               start += 1;
   79   
   80           _sign = 1;
   81           boolean tmark = false;
   82   
   83           if (start < len && str.charAt(start) == '-')
   84           {
   85               _sign = -1;
   86               start += 1;
   87           }
   88   
   89           if (start >= len || str.charAt(start) != 'P')
   90               throw new IllegalArgumentException("duration must begin with P");
   91   
   92           start += 1;
   93   
   94           int seen = SEEN_NOTHING;
   95           _fs = GDate._zero;
   96   
   97           for (;start < len; start += 1)
   98           {
   99               boolean negval = false;
  100               char ch = str.charAt(start);
  101               if (ch == 'T')
  102               {
  103                   if (tmark)
  104                       throw new IllegalArgumentException("duration must have no more than one T'");
  105                   if (seen > SEEN_DAY)
  106                       throw new IllegalArgumentException("T in duration must precede time fields");
  107                   seen = SEEN_DAY;
  108                   tmark = true;
  109                   start += 1;
  110                   if (start >= len)
  111                       throw new IllegalArgumentException("illegal duration");
  112                   ch = str.charAt(start);
  113               }
  114               if (ch == '-')
  115               {
  116                   negval = true;
  117                   if (start == len)
  118                       throw new IllegalArgumentException("illegal duration");
  119                   start += 1;
  120                   ch = str.charAt(start);
  121               }
  122               if (!GDate.isDigit(ch))
  123                   throw new IllegalArgumentException("illegal duration");
  124               int value = GDate.digitVal(ch);
  125               for (;;)
  126               {
  127                   start += 1;
  128                   ch = (start < len) ? str.charAt(start) : '\0';
  129                   if (!GDate.isDigit(ch))
  130                       break;
  131                   value = value * 10 + GDate.digitVal(ch);
  132               }
  133               if (ch == '.')
  134               {
  135                   int i = start;
  136                   do i += 1;
  137                   while (i < len && GDate.isDigit(ch = str.charAt(i)));
  138                   _fs = new BigDecimal(str.subSequence(start, i).toString());
  139                   if (i >= len || ch != 'S')
  140                       throw new IllegalArgumentException("illegal duration");
  141                   start = i;
  142               }
  143               if (negval)
  144                   value = -value;
  145               switch (seen)
  146               {
  147                   case SEEN_NOTHING:
  148                       if (ch == 'Y')
  149                       {
  150                           seen = SEEN_YEAR;
  151                           _CY = value;
  152                           break;
  153                       } // fallthrough
  154                   case SEEN_YEAR:
  155                       if (ch == 'M')
  156                       {
  157                           seen = SEEN_MONTH;
  158                           _M = value;
  159                           break;
  160                       } // fallthrough
  161                   case SEEN_MONTH:
  162                       if (ch == 'D')
  163                       {
  164                           seen = SEEN_DAY;
  165                           _D = value;
  166                           break;
  167                       } // fallthrough
  168                   case SEEN_DAY:
  169                       if (ch == 'H')
  170                       {
  171                           if (!tmark)
  172                               throw new IllegalArgumentException("time in duration must follow T");
  173                           seen = SEEN_HOUR;
  174                           _h = value;
  175                           break;
  176                       } // fallthrough
  177                   case SEEN_HOUR:
  178                       if (ch == 'M')
  179                       {
  180                           if (!tmark)
  181                               throw new IllegalArgumentException("time in duration must follow T");
  182                           seen = SEEN_MINUTE;
  183                           _m = value;
  184                           break;
  185                       } // fallthrough
  186                   case SEEN_MINUTE:
  187                       if (ch == 'S')
  188                       {
  189                           if (!tmark)
  190                               throw new IllegalArgumentException("time in duration must follow T");
  191                           seen = SEEN_SECOND;
  192                           _s = value;
  193                           break;
  194                       } // fallthrough
  195                   default:
  196                       throw new IllegalArgumentException("duration must specify Y M D T H M S in order");
  197               }
  198           }
  199   
  200           if ( seen == SEEN_NOTHING )
  201               throw new IllegalArgumentException("duration must contain at least one number and its designator: " + str);
  202       }
  203   
  204       /**
  205        * Constructs a GDuration with the specified sign,
  206        * year, month, day, hours, minutes, seconds, and optional
  207        * fractional seconds.
  208        * @param sign +1 for a positive duration, -1 for a negative duration
  209        * @throws java.lang.IllegalArgumentException if the sign is not 1 or -1
  210        */
  211       public GDuration(
  212               int sign,
  213               int year,
  214               int month,
  215               int day,
  216               int hour,
  217               int minute,
  218               int second,
  219               BigDecimal fraction)
  220       {
  221           if (sign != 1 && sign != -1)
  222               throw new IllegalArgumentException();
  223           _sign = sign;
  224           _CY = year;
  225           _M = month;
  226           _D = day;
  227           _h = hour;
  228           _m = minute;
  229           _s = second;
  230           _fs = fraction == null ? GDate._zero : fraction;
  231       }
  232   
  233       /**
  234        * Constructs a GDuration from another GDurationSpecification.
  235        */
  236       public GDuration(GDurationSpecification gDuration)
  237       {
  238           _sign = gDuration.getSign();
  239           _CY = gDuration.getYear();
  240           _M = gDuration.getMonth();
  241           _D = gDuration.getDay();
  242           _h = gDuration.getHour();
  243           _m = gDuration.getMinute();
  244           _s = gDuration.getSecond();
  245           _fs = gDuration.getFraction();
  246       }
  247   
  248       /**
  249        * Builds another GDate with the same value
  250        * as this one.
  251        */
  252       public Object clone()
  253       {
  254           return new GDuration(this);
  255       }
  256   
  257       /**
  258        * All GDuration instances return true.
  259        */
  260       public final boolean isImmutable()
  261       {
  262           return true;
  263       }
  264   
  265       /**
  266        * Returns the sign of the duration: +1 is forwards
  267        * and -1 is backwards in time.
  268        */
  269       public final int getSign()
  270           { return _sign; }
  271   
  272       /**
  273        * Gets the year component.
  274        */
  275       public final int getYear()
  276           { return _CY;  }
  277   
  278       /**
  279        * Gets the month-of-year component.
  280        */
  281       public final int getMonth()
  282           { return _M;  }
  283   
  284       /**
  285        * Gets the day-of-month component.
  286        */
  287       public final int getDay()
  288           { return _D; }
  289   
  290       /**
  291        * Gets the hour-of-day component.
  292        */
  293       public final int getHour()
  294           { return _h; }
  295   
  296       /**
  297        * Gets the minute-of-hour component.
  298        */
  299       public final int getMinute()
  300           { return _m; }
  301   
  302       /**
  303        * Gets the second-of-minute component.
  304        */
  305       public final int getSecond()
  306           { return _s; }
  307   
  308   
  309       /**
  310        * Gets the fraction-of-second. Range from 0 (inclusive) to 1 (exclusive).
  311        */
  312       public BigDecimal getFraction()
  313           { return _fs; }
  314   
  315       /**
  316        * Returns true if all of the individual components
  317        * of the duration are nonnegative.
  318        */
  319       public boolean isValid()
  320       {
  321           return GDurationBuilder.isValidDuration(this);
  322       }
  323   
  324       /**
  325        * Comparison to another GDuration.
  326        * <ul>
  327        * <li>Returns -1 if this < duration. (less-than)
  328        * <li>Returns 0 if this == duration. (equal)
  329        * <li>Returns 1 if this > duration. (greater-than)
  330        * <li>Returns 2 if this <> duration. (incomparable)
  331        * </ul>
  332        * Two instances are incomparable if they have different amounts
  333        * of information.
  334        */
  335       public final int compareToGDuration(GDurationSpecification duration)
  336       {
  337           return GDurationBuilder.compareDurations(this, duration);
  338       }
  339   
  340       /**
  341        * The natural string representation of the duration.
  342        * <p>
  343        * Any components that are zero are omitted. Note that if the duration
  344        * is invalid, i.e., it has negative components, those negative
  345        * components are serialized out here. To check for validity, use
  346        * the isValid() method; and to normalize most durations to a valid
  347        * form use the normalize() method.
  348        */
  349       public String toString()
  350       {
  351           return GDurationBuilder.formatDuration(this);
  352       }
  353   
  354       /**
  355        * Returns a new GDuration which is the sum of this one and the
  356        * supplied duration.  Does a fieldwise addition, with no normalization.
  357        */
  358       public GDuration add(GDurationSpecification duration)
  359       {
  360           int sign = _sign * duration.getSign();
  361           return _add(duration, sign);
  362       }
  363   
  364       /**
  365        * Returns a new GDuration which is the result of subtracting
  366        * the supplied duration from this one.  Does a fieldwise
  367        * subtraction, with no normalization.
  368        */
  369       public GDuration subtract(GDurationSpecification duration)
  370       {
  371           int sign = -_sign * duration.getSign();
  372           return _add(duration, sign);
  373       }
  374   
  375       private GDuration _add(GDurationSpecification duration, int sign)
  376       {
  377           GDuration result = new GDuration(this);
  378           result._CY += sign * duration.getYear();
  379           result._M += sign * duration.getMonth();
  380           result._D += sign * duration.getDay();
  381           result._h += sign * duration.getHour();
  382           result._m += sign * duration.getMinute();
  383           result._s += sign * duration.getSecond();
  384   
  385           if (duration.getFraction().signum() == 0)
  386               return result;
  387   
  388           if (result._fs.signum() == 0 && sign == 1)
  389               result._fs = duration.getFraction();
  390           else
  391               result._fs = sign > 0 ?
  392                       result._fs.add(duration.getFraction()) :
  393                       result._fs.subtract(duration.getFraction());
  394           return result;
  395       }
  396   
  397       /**
  398        * Two GDurations are equal if all their fields are equal.
  399        * The equals function does not apply normalizatin.
  400        */
  401       public boolean equals(Object obj)
  402       {
  403           if (obj == this)
  404               return true;
  405           if (!(obj instanceof GDuration))
  406               return false;
  407   
  408           GDuration duration = (GDuration)obj;
  409           return (_sign == duration.getSign() &&
  410                   _CY == duration.getYear() &&
  411                   _M == duration.getMonth() &&
  412                   _D == duration.getDay() &&
  413                   _h == duration.getHour() &&
  414                   _m == duration.getMinute() &&
  415                   _s == duration.getSecond() &&
  416                   _fs.equals(duration.getFraction()));
  417       }
  418   
  419       public int hashCode()
  420       {
  421           return (_s +
  422                   _m * (60 + 7) +
  423                   _h * (60 * 60 + 7) +
  424                   _D * (60 * 60 * 24 + 7) +
  425                   _M * (60 * 60 * 24 * 31 + 7) +
  426                   _CY *(60 * 60 * 24 * 372 + 7) +
  427                   _sign * 11917049);
  428       }
  429   
  430   }

Home » xmlbeans-2.5.0-src » org.apache » xmlbeans » [javadoc | source]