001 /*
002 * Copyright 2001-2005 Stephen Colebourne
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.joda.time.field;
017
018 import org.joda.time.DateTimeFieldType;
019 import org.joda.time.DurationField;
020
021 /**
022 * Precise datetime field, which has a precise unit duration field.
023 * <p>
024 * PreciseDurationDateTimeField is thread-safe and immutable, and its
025 * subclasses must be as well.
026 *
027 * @author Brian S O'Neill
028 * @since 1.0
029 */
030 public abstract class PreciseDurationDateTimeField extends BaseDateTimeField {
031
032 private static final long serialVersionUID = 5004523158306266035L;
033
034 /** The fractional unit in millis */
035 final long iUnitMillis;
036
037 private final DurationField iUnitField;
038
039 /**
040 * Constructor.
041 *
042 * @param type the field type
043 * @param unit precise unit duration, like "days()".
044 * @throws IllegalArgumentException if duration field is imprecise
045 * @throws IllegalArgumentException if unit milliseconds is less than one
046 */
047 public PreciseDurationDateTimeField(DateTimeFieldType type, DurationField unit) {
048 super(type);
049
050 if (!unit.isPrecise()) {
051 throw new IllegalArgumentException("Unit duration field must be precise");
052 }
053
054 iUnitMillis = unit.getUnitMillis();
055 if (iUnitMillis < 1) {
056 throw new IllegalArgumentException("The unit milliseconds must be at least 1");
057 }
058
059 iUnitField = unit;
060 }
061
062 /**
063 * Returns false by default.
064 */
065 public boolean isLenient() {
066 return false;
067 }
068
069 /**
070 * Set the specified amount of units to the specified time instant.
071 *
072 * @param instant the milliseconds from 1970-01-01T00:00:00Z to set in
073 * @param value value of units to set.
074 * @return the updated time instant.
075 * @throws IllegalArgumentException if value is too large or too small.
076 */
077 public long set(long instant, int value) {
078 FieldUtils.verifyValueBounds(this, value, getMinimumValue(),
079 getMaximumValueForSet(instant, value));
080 return instant + (value - get(instant)) * iUnitMillis;
081 }
082
083 /**
084 * This method assumes that this field is properly rounded on
085 * 1970-01-01T00:00:00. If the rounding alignment differs, override this
086 * method as follows:
087 * <pre>
088 * return super.roundFloor(instant + ALIGNMENT_MILLIS) - ALIGNMENT_MILLIS;
089 * </pre>
090 */
091 public long roundFloor(long instant) {
092 if (instant >= 0) {
093 return instant - instant % iUnitMillis;
094 } else {
095 instant += 1;
096 return instant - instant % iUnitMillis - iUnitMillis;
097 }
098 }
099
100 /**
101 * This method assumes that this field is properly rounded on
102 * 1970-01-01T00:00:00. If the rounding alignment differs, override this
103 * method as follows:
104 * <pre>
105 * return super.roundCeiling(instant + ALIGNMENT_MILLIS) - ALIGNMENT_MILLIS;
106 * </pre>
107 */
108 public long roundCeiling(long instant) {
109 if (instant > 0) {
110 instant -= 1;
111 return instant - instant % iUnitMillis + iUnitMillis;
112 } else {
113 return instant - instant % iUnitMillis;
114 }
115 }
116
117 /**
118 * This method assumes that this field is properly rounded on
119 * 1970-01-01T00:00:00. If the rounding alignment differs, override this
120 * method as follows:
121 * <pre>
122 * return super.remainder(instant + ALIGNMENT_MILLIS);
123 * </pre>
124 */
125 public long remainder(long instant) {
126 if (instant >= 0) {
127 return instant % iUnitMillis;
128 } else {
129 return (instant + 1) % iUnitMillis + iUnitMillis - 1;
130 }
131 }
132
133 /**
134 * Returns the duration per unit value of this field. For example, if this
135 * field represents "minute of hour", then the duration field is minutes.
136 *
137 * @return the duration of this field, or UnsupportedDurationField if field
138 * has no duration
139 */
140 public DurationField getDurationField() {
141 return iUnitField;
142 }
143
144 /**
145 * Get the minimum value for the field.
146 *
147 * @return the minimum value
148 */
149 public int getMinimumValue() {
150 return 0;
151 }
152
153 public final long getUnitMillis() {
154 return iUnitMillis;
155 }
156
157 /**
158 * Called by the set method to get the maximum allowed value. By default,
159 * returns getMaximumValue(instant). Override to provide a faster
160 * implementation.
161 */
162 protected int getMaximumValueForSet(long instant, int value) {
163 return getMaximumValue(instant);
164 }
165
166 }