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.DateTimeFieldType; |
19 | import org.joda.time.DurationField; |
20 | |
21 | /** |
22 | * Precise datetime field, which has a precise unit duration field. |
23 | * <p> |
24 | * PreciseDurationDateTimeField is thread-safe and immutable, and its |
25 | * subclasses must be as well. |
26 | * |
27 | * @author Brian S O'Neill |
28 | * @since 1.0 |
29 | */ |
30 | public abstract class PreciseDurationDateTimeField extends BaseDateTimeField { |
31 | |
32 | private static final long serialVersionUID = 5004523158306266035L; |
33 | |
34 | /** The fractional unit in millis */ |
35 | final long iUnitMillis; |
36 | |
37 | private final DurationField iUnitField; |
38 | |
39 | /** |
40 | * Constructor. |
41 | * |
42 | * @param type the field type |
43 | * @param unit precise unit duration, like "days()". |
44 | * @throws IllegalArgumentException if duration field is imprecise |
45 | * @throws IllegalArgumentException if unit milliseconds is less than one |
46 | */ |
47 | public PreciseDurationDateTimeField(DateTimeFieldType type, DurationField unit) { |
48 | super(type); |
49 | |
50 | if (!unit.isPrecise()) { |
51 | throw new IllegalArgumentException("Unit duration field must be precise"); |
52 | } |
53 | |
54 | iUnitMillis = unit.getUnitMillis(); |
55 | if (iUnitMillis < 1) { |
56 | throw new IllegalArgumentException("The unit milliseconds must be at least 1"); |
57 | } |
58 | |
59 | iUnitField = unit; |
60 | } |
61 | |
62 | /** |
63 | * Returns false by default. |
64 | */ |
65 | public boolean isLenient() { |
66 | return false; |
67 | } |
68 | |
69 | /** |
70 | * Set the specified amount of units to the specified time instant. |
71 | * |
72 | * @param instant the milliseconds from 1970-01-01T00:00:00Z to set in |
73 | * @param value value of units to set. |
74 | * @return the updated time instant. |
75 | * @throws IllegalArgumentException if value is too large or too small. |
76 | */ |
77 | public long set(long instant, int value) { |
78 | FieldUtils.verifyValueBounds(this, value, getMinimumValue(), |
79 | getMaximumValueForSet(instant, value)); |
80 | return instant + (value - get(instant)) * iUnitMillis; |
81 | } |
82 | |
83 | /** |
84 | * This method assumes that this field is properly rounded on |
85 | * 1970-01-01T00:00:00. If the rounding alignment differs, override this |
86 | * method as follows: |
87 | * <pre> |
88 | * return super.roundFloor(instant + ALIGNMENT_MILLIS) - ALIGNMENT_MILLIS; |
89 | * </pre> |
90 | */ |
91 | public long roundFloor(long instant) { |
92 | if (instant >= 0) { |
93 | return instant - instant % iUnitMillis; |
94 | } else { |
95 | instant += 1; |
96 | return instant - instant % iUnitMillis - iUnitMillis; |
97 | } |
98 | } |
99 | |
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 | } |