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 }