View Javadoc

1   /*
2    *  Copyright 2001-2005 Stephen Colebourne
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   */
16  package org.joda.time.field;
17  
18  import org.joda.time.DateTimeField;
19  import org.joda.time.DateTimeFieldType;
20  import org.joda.time.DurationField;
21  
22  /**
23   * Counterpart remainder datetime field to {@link DividedDateTimeField}. The
24   * field's unit duration is unchanged, but the range duration is scaled
25   * accordingly.
26   * <p>
27   * RemainderDateTimeField is thread-safe and immutable.
28   *
29   * @see DividedDateTimeField
30   *
31   * @author Brian S O'Neill
32   * @since 1.0
33   */
34  public class RemainderDateTimeField extends DecoratedDateTimeField {
35  
36      private static final long serialVersionUID = 5708241235177666790L;
37  
38      // Shared with DividedDateTimeField.
39      final int iDivisor;
40      final DurationField iRangeField;
41  
42      /**
43       * Constructor.
44       * 
45       * @param field  the field to wrap, like "year()".
46       * @param type  the field type this field actually uses
47       * @param divisor  divisor, such as 100 years in a century
48       * @throws IllegalArgumentException if divisor is less than two
49       */
50      public RemainderDateTimeField(DateTimeField field,
51                                    DateTimeFieldType type, int divisor) {
52          super(field, type);
53  
54          if (divisor < 2) {
55              throw new IllegalArgumentException("The divisor must be at least 2");
56          }
57  
58          DurationField rangeField = field.getDurationField();
59          if (rangeField == null) {
60              iRangeField = null;
61          } else {
62              iRangeField = new ScaledDurationField(
63                  rangeField, type.getRangeDurationType(), divisor);
64          }
65  
66          iDivisor = divisor;
67      }
68  
69      /**
70       * Construct a RemainderDateTimeField that compliments the given
71       * DividedDateTimeField.
72       *
73       * @param dividedField  complimentary divided field, like "century()".
74       */
75      public RemainderDateTimeField(DividedDateTimeField dividedField) {
76          this(dividedField, dividedField.getType());
77      }
78  
79      /**
80       * Construct a RemainderDateTimeField that compliments the given
81       * DividedDateTimeField.
82       *
83       * @param dividedField  complimentary divided field, like "century()".
84       * @param type  the field type this field actually uses
85       */
86      public RemainderDateTimeField(DividedDateTimeField dividedField, DateTimeFieldType type) {
87          super(dividedField.getWrappedField(), type);
88          iDivisor = dividedField.iDivisor;
89          iRangeField = dividedField.iDurationField;
90      }
91  
92      //-----------------------------------------------------------------------
93      /**
94       * Get the remainder from the specified time instant.
95       * 
96       * @param instant  the time instant in millis to query.
97       * @return the remainder extracted from the input.
98       */
99      public int get(long instant) {
100         int value = getWrappedField().get(instant);
101         if (value >= 0) {
102             return value % iDivisor;
103         } else {
104             return (iDivisor - 1) + ((value + 1) % iDivisor);
105         }
106     }
107 
108     /**
109      * Add the specified amount to the specified time instant, wrapping around
110      * within the remainder range if necessary. The amount added may be
111      * negative.
112      * 
113      * @param instant  the time instant in millis to update.
114      * @param amount  the amount to add (can be negative).
115      * @return the updated time instant.
116      */
117     public long addWrapField(long instant, int amount) {
118         return set(instant, FieldUtils.getWrappedValue(get(instant), amount, 0, iDivisor - 1));
119     }
120 
121     /**
122      * Set the specified amount of remainder units to the specified time instant.
123      * 
124      * @param instant  the time instant in millis to update.
125      * @param value  value of remainder units to set.
126      * @return the updated time instant.
127      * @throws IllegalArgumentException if value is too large or too small.
128      */
129     public long set(long instant, int value) {
130         FieldUtils.verifyValueBounds(this, value, 0, iDivisor - 1);
131         int divided = getDivided(getWrappedField().get(instant));
132         return getWrappedField().set(instant, divided * iDivisor + value);
133     }
134 
135     /**
136      * Returns a scaled version of the wrapped field's unit duration field.
137      */
138     public DurationField getRangeDurationField() {
139         return iRangeField;
140     }
141 
142     /**
143      * Get the minimum value for the field, which is always zero.
144      * 
145      * @return the minimum value of zero.
146      */
147     public int getMinimumValue() {
148         return 0;
149     }
150 
151     /**
152      * Get the maximum value for the field, which is always one less than the
153      * divisor.
154      * 
155      * @return the maximum value
156      */
157     public int getMaximumValue() {
158         return iDivisor - 1;
159     }
160 
161     public long roundFloor(long instant) {
162         return getWrappedField().roundFloor(instant);
163     }
164 
165     public long roundCeiling(long instant) {
166         return getWrappedField().roundCeiling(instant);
167     }
168 
169     public long roundHalfFloor(long instant) {
170         return getWrappedField().roundHalfFloor(instant);
171     }
172 
173     public long roundHalfCeiling(long instant) {
174         return getWrappedField().roundHalfCeiling(instant);
175     }
176 
177     public long roundHalfEven(long instant) {
178         return getWrappedField().roundHalfEven(instant);
179     }
180 
181     public long remainder(long instant) {
182         return getWrappedField().remainder(instant);
183     }
184 
185     /**
186      * Returns the divisor applied, in the field's units.
187      * 
188      * @return the divisor
189      */
190     public int getDivisor() {
191         return iDivisor;
192     }
193 
194     private int getDivided(int value) {
195         if (value >= 0) {
196             return value / iDivisor;
197         } else {
198             return ((value + 1) / iDivisor) - 1;
199         }
200     }
201 
202 }