51 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
52 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
53 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
54 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
55 */
56 package tck.java.time.chrono;
57
58 import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH;
59 import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR;
60 import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH;
61 import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR;
62 import static java.time.temporal.ChronoField.DAY_OF_MONTH;
63 import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
64 import static java.time.temporal.ChronoField.YEAR_OF_ERA;
65
66 import java.io.Serializable;
67
68 import java.time.DateTimeException;
69 import java.time.LocalDate;
70 import java.time.Period;
71 import java.time.chrono.ChronoLocalDate;
72 import java.time.temporal.ChronoField;
73 import java.time.temporal.ChronoUnit;
74 import java.time.temporal.Temporal;
75 import java.time.temporal.TemporalField;
76 import java.time.temporal.TemporalUnit;
77 import java.time.temporal.ValueRange;
78 import java.time.Year;
79
80 /**
81 * A date in the Coptic calendar system.
82 * <p>
83 * This implements {@code ChronoLocalDate} for the {@link CopticChronology Coptic calendar}.
84 *
85 * <h4>Implementation notes</h4>
86 * This class is immutable and thread-safe.
87 */
88 public final class CopticDate
89 implements ChronoLocalDate<CopticDate>, Serializable {
90
91 /**
92 * Serialization version.
93 */
94 private static final long serialVersionUID = -7920528871688876868L;
95 /**
96 * The difference between the Coptic and Coptic epoch day count.
97 */
98 private static final int EPOCH_DAY_DIFFERENCE = 574971 + 40587;
184 default:
185 return 30;
186 }
187 }
188
189 @Override
190 public ValueRange range(TemporalField field) {
191 if (field instanceof ChronoField) {
192 if (isSupported(field)) {
193 ChronoField f = (ChronoField) field;
194 switch (f) {
195 case DAY_OF_MONTH: return ValueRange.of(1, lengthOfMonth());
196 case DAY_OF_YEAR: return ValueRange.of(1, lengthOfYear());
197 case ALIGNED_WEEK_OF_MONTH: return ValueRange.of(1, month == 13 ? 1 : 5);
198 case YEAR:
199 case YEAR_OF_ERA: return (prolepticYear <= 0 ?
200 ValueRange.of(1, Year.MAX_VALUE + 1) : ValueRange.of(1, Year.MAX_VALUE)); // TODO
201 }
202 return getChronology().range(f);
203 }
204 throw new DateTimeException("Unsupported field: " + field.getName());
205 }
206 return field.rangeRefinedBy(this);
207 }
208
209 @Override
210 public long getLong(TemporalField field) {
211 if (field instanceof ChronoField) {
212 switch ((ChronoField) field) {
213 case DAY_OF_WEEK: return Math.floorMod(toEpochDay() + 3, 7) + 1;
214 case ALIGNED_DAY_OF_WEEK_IN_MONTH: return ((day - 1) % 7) + 1;
215 case ALIGNED_DAY_OF_WEEK_IN_YEAR: return ((get(ChronoField.DAY_OF_YEAR) - 1) % 7) + 1;
216 case DAY_OF_MONTH: return day;
217 case DAY_OF_YEAR: return (month - 1) * 30 + day;
218 case EPOCH_DAY: return toEpochDay();
219 case ALIGNED_WEEK_OF_MONTH: return ((day - 1) / 7) + 1;
220 case ALIGNED_WEEK_OF_YEAR: return ((get(ChronoField.DAY_OF_YEAR) - 1) / 7) + 1;
221 case MONTH_OF_YEAR: return month;
222 case YEAR_OF_ERA: return (prolepticYear >= 1 ? prolepticYear : 1 - prolepticYear);
223 case YEAR: return prolepticYear;
224 case ERA: return (prolepticYear >= 1 ? 1 : 0);
225 }
226 throw new DateTimeException("Unsupported field: " + field.getName());
227 }
228 return field.getFrom(this);
229 }
230
231 @Override
232 public CopticDate with(TemporalField field, long newValue) {
233 if (field instanceof ChronoField) {
234 ChronoField f = (ChronoField) field;
235 f.checkValidValue(newValue); // TODO: validate value
236 int nvalue = (int) newValue;
237 switch (f) {
238 case DAY_OF_WEEK: return plusDays(newValue - get(ChronoField.DAY_OF_WEEK));
239 case ALIGNED_DAY_OF_WEEK_IN_MONTH: return plusDays(newValue - getLong(ALIGNED_DAY_OF_WEEK_IN_MONTH));
240 case ALIGNED_DAY_OF_WEEK_IN_YEAR: return plusDays(newValue - getLong(ALIGNED_DAY_OF_WEEK_IN_YEAR));
241 case DAY_OF_MONTH: return resolvePreviousValid(prolepticYear, month, nvalue);
242 case DAY_OF_YEAR: return resolvePreviousValid(prolepticYear, ((nvalue - 1) / 30) + 1, ((nvalue - 1) % 30) + 1);
243 case EPOCH_DAY: return ofEpochDay(nvalue);
244 case ALIGNED_WEEK_OF_MONTH: return plusDays((newValue - getLong(ALIGNED_WEEK_OF_MONTH)) * 7);
245 case ALIGNED_WEEK_OF_YEAR: return plusDays((newValue - getLong(ALIGNED_WEEK_OF_YEAR)) * 7);
246 case MONTH_OF_YEAR: return resolvePreviousValid(prolepticYear, nvalue, day);
247 case YEAR_OF_ERA: return resolvePreviousValid(prolepticYear >= 1 ? nvalue : 1 - nvalue, month, day);
248 case YEAR: return resolvePreviousValid(nvalue, month, day);
249 case ERA: return resolvePreviousValid(1 - prolepticYear, month, day);
250 }
251 throw new DateTimeException("Unsupported field: " + field.getName());
252 }
253 return field.adjustInto(this, newValue);
254 }
255
256 //-----------------------------------------------------------------------
257 @Override
258 public CopticDate plus(long amountToAdd, TemporalUnit unit) {
259 if (unit instanceof ChronoUnit) {
260 ChronoUnit f = (ChronoUnit) unit;
261 switch (f) {
262 case DAYS: return plusDays(amountToAdd);
263 case WEEKS: return plusDays(Math.multiplyExact(amountToAdd, 7));
264 case MONTHS: return plusMonths(amountToAdd);
265 case YEARS: return plusYears(amountToAdd);
266 case DECADES: return plusYears(Math.multiplyExact(amountToAdd, 10));
267 case CENTURIES: return plusYears(Math.multiplyExact(amountToAdd, 100));
268 case MILLENNIA: return plusYears(Math.multiplyExact(amountToAdd, 1000));
269 }
270 throw new DateTimeException(unit.getName() + " not valid for CopticDate");
271 }
272 return unit.addTo(this, amountToAdd);
273 }
274
275 //-----------------------------------------------------------------------
276 private CopticDate plusYears(long years) {
277 return plusMonths(Math.multiplyExact(years, 13));
278 }
279
280 private CopticDate plusMonths(long months) {
281 if (months == 0) {
282 return this;
283 }
284 long curEm = prolepticYear * 13L + (month - 1);
285 long calcEm = Math.addExact(curEm, months);
286 int newYear = Math.toIntExact(Math.floorDiv(calcEm, 13));
287 int newMonth = (int)Math.floorMod(calcEm, 13) + 1;
288 return resolvePreviousValid(newYear, newMonth, day);
289 }
290
|
51 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
52 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
53 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
54 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
55 */
56 package tck.java.time.chrono;
57
58 import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH;
59 import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR;
60 import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH;
61 import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR;
62 import static java.time.temporal.ChronoField.DAY_OF_MONTH;
63 import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
64 import static java.time.temporal.ChronoField.YEAR_OF_ERA;
65
66 import java.io.Serializable;
67
68 import java.time.DateTimeException;
69 import java.time.LocalDate;
70 import java.time.Period;
71 import java.time.Year;
72 import java.time.chrono.ChronoLocalDate;
73 import java.time.temporal.ChronoField;
74 import java.time.temporal.ChronoUnit;
75 import java.time.temporal.Temporal;
76 import java.time.temporal.TemporalField;
77 import java.time.temporal.TemporalUnit;
78 import java.time.temporal.ValueRange;
79 import java.time.temporal.UnsupportedTemporalTypeException;
80
81 /**
82 * A date in the Coptic calendar system.
83 * <p>
84 * This implements {@code ChronoLocalDate} for the {@link CopticChronology Coptic calendar}.
85 *
86 * <h4>Implementation notes</h4>
87 * This class is immutable and thread-safe.
88 */
89 public final class CopticDate
90 implements ChronoLocalDate<CopticDate>, Serializable {
91
92 /**
93 * Serialization version.
94 */
95 private static final long serialVersionUID = -7920528871688876868L;
96 /**
97 * The difference between the Coptic and Coptic epoch day count.
98 */
99 private static final int EPOCH_DAY_DIFFERENCE = 574971 + 40587;
185 default:
186 return 30;
187 }
188 }
189
190 @Override
191 public ValueRange range(TemporalField field) {
192 if (field instanceof ChronoField) {
193 if (isSupported(field)) {
194 ChronoField f = (ChronoField) field;
195 switch (f) {
196 case DAY_OF_MONTH: return ValueRange.of(1, lengthOfMonth());
197 case DAY_OF_YEAR: return ValueRange.of(1, lengthOfYear());
198 case ALIGNED_WEEK_OF_MONTH: return ValueRange.of(1, month == 13 ? 1 : 5);
199 case YEAR:
200 case YEAR_OF_ERA: return (prolepticYear <= 0 ?
201 ValueRange.of(1, Year.MAX_VALUE + 1) : ValueRange.of(1, Year.MAX_VALUE)); // TODO
202 }
203 return getChronology().range(f);
204 }
205 throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
206 }
207 return field.rangeRefinedBy(this);
208 }
209
210 @Override
211 public long getLong(TemporalField field) {
212 if (field instanceof ChronoField) {
213 switch ((ChronoField) field) {
214 case DAY_OF_WEEK: return Math.floorMod(toEpochDay() + 3, 7) + 1;
215 case ALIGNED_DAY_OF_WEEK_IN_MONTH: return ((day - 1) % 7) + 1;
216 case ALIGNED_DAY_OF_WEEK_IN_YEAR: return ((get(ChronoField.DAY_OF_YEAR) - 1) % 7) + 1;
217 case DAY_OF_MONTH: return day;
218 case DAY_OF_YEAR: return (month - 1) * 30 + day;
219 case EPOCH_DAY: return toEpochDay();
220 case ALIGNED_WEEK_OF_MONTH: return ((day - 1) / 7) + 1;
221 case ALIGNED_WEEK_OF_YEAR: return ((get(ChronoField.DAY_OF_YEAR) - 1) / 7) + 1;
222 case MONTH_OF_YEAR: return month;
223 case YEAR_OF_ERA: return (prolepticYear >= 1 ? prolepticYear : 1 - prolepticYear);
224 case YEAR: return prolepticYear;
225 case ERA: return (prolepticYear >= 1 ? 1 : 0);
226 }
227 throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
228 }
229 return field.getFrom(this);
230 }
231
232 @Override
233 public CopticDate with(TemporalField field, long newValue) {
234 if (field instanceof ChronoField) {
235 ChronoField f = (ChronoField) field;
236 f.checkValidValue(newValue); // TODO: validate value
237 int nvalue = (int) newValue;
238 switch (f) {
239 case DAY_OF_WEEK: return plusDays(newValue - get(ChronoField.DAY_OF_WEEK));
240 case ALIGNED_DAY_OF_WEEK_IN_MONTH: return plusDays(newValue - getLong(ALIGNED_DAY_OF_WEEK_IN_MONTH));
241 case ALIGNED_DAY_OF_WEEK_IN_YEAR: return plusDays(newValue - getLong(ALIGNED_DAY_OF_WEEK_IN_YEAR));
242 case DAY_OF_MONTH: return resolvePreviousValid(prolepticYear, month, nvalue);
243 case DAY_OF_YEAR: return resolvePreviousValid(prolepticYear, ((nvalue - 1) / 30) + 1, ((nvalue - 1) % 30) + 1);
244 case EPOCH_DAY: return ofEpochDay(nvalue);
245 case ALIGNED_WEEK_OF_MONTH: return plusDays((newValue - getLong(ALIGNED_WEEK_OF_MONTH)) * 7);
246 case ALIGNED_WEEK_OF_YEAR: return plusDays((newValue - getLong(ALIGNED_WEEK_OF_YEAR)) * 7);
247 case MONTH_OF_YEAR: return resolvePreviousValid(prolepticYear, nvalue, day);
248 case YEAR_OF_ERA: return resolvePreviousValid(prolepticYear >= 1 ? nvalue : 1 - nvalue, month, day);
249 case YEAR: return resolvePreviousValid(nvalue, month, day);
250 case ERA: return resolvePreviousValid(1 - prolepticYear, month, day);
251 }
252 throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
253 }
254 return field.adjustInto(this, newValue);
255 }
256
257 //-----------------------------------------------------------------------
258 @Override
259 public CopticDate plus(long amountToAdd, TemporalUnit unit) {
260 if (unit instanceof ChronoUnit) {
261 ChronoUnit f = (ChronoUnit) unit;
262 switch (f) {
263 case DAYS: return plusDays(amountToAdd);
264 case WEEKS: return plusDays(Math.multiplyExact(amountToAdd, 7));
265 case MONTHS: return plusMonths(amountToAdd);
266 case YEARS: return plusYears(amountToAdd);
267 case DECADES: return plusYears(Math.multiplyExact(amountToAdd, 10));
268 case CENTURIES: return plusYears(Math.multiplyExact(amountToAdd, 100));
269 case MILLENNIA: return plusYears(Math.multiplyExact(amountToAdd, 1000));
270 }
271 throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
272 }
273 return unit.addTo(this, amountToAdd);
274 }
275
276 //-----------------------------------------------------------------------
277 private CopticDate plusYears(long years) {
278 return plusMonths(Math.multiplyExact(years, 13));
279 }
280
281 private CopticDate plusMonths(long months) {
282 if (months == 0) {
283 return this;
284 }
285 long curEm = prolepticYear * 13L + (month - 1);
286 long calcEm = Math.addExact(curEm, months);
287 int newYear = Math.toIntExact(Math.floorDiv(calcEm, 13));
288 int newMonth = (int)Math.floorMod(calcEm, 13) + 1;
289 return resolvePreviousValid(newYear, newMonth, day);
290 }
291
|