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 import org.joda.time.DurationFieldType; 021 022 /** 023 * Abstract datetime field class that defines its own DurationField, which 024 * delegates back into this ImpreciseDateTimeField. 025 * <p> 026 * This DateTimeField is useful for defining DateTimeFields that are composed 027 * of imprecise durations. If both duration fields are precise, then a 028 * {@link PreciseDateTimeField} should be used instead. 029 * <p> 030 * When defining imprecise DateTimeFields where a matching DurationField is 031 * already available, just extend BaseDateTimeField directly so as not to 032 * create redundant DurationField instances. 033 * <p> 034 * ImpreciseDateTimeField is thread-safe and immutable, and its subclasses must 035 * be as well. 036 * 037 * @author Brian S O'Neill 038 * @see PreciseDateTimeField 039 * @since 1.0 040 */ 041 public abstract class ImpreciseDateTimeField extends BaseDateTimeField { 042 043 private static final long serialVersionUID = 7190739608550251860L; 044 045 final long iUnitMillis; 046 private final DurationField iDurationField; 047 048 /** 049 * Constructor. 050 * 051 * @param type the field type 052 * @param unitMillis the average duration unit milliseconds 053 */ 054 public ImpreciseDateTimeField(DateTimeFieldType type, long unitMillis) { 055 super(type); 056 iUnitMillis = unitMillis; 057 iDurationField = new LinkedDurationField(type.getDurationType()); 058 } 059 060 public abstract int get(long instant); 061 062 public abstract long set(long instant, int value); 063 064 public abstract long add(long instant, int value); 065 066 public abstract long add(long instant, long value); 067 068 /** 069 * Computes the difference between two instants, as measured in the units 070 * of this field. Any fractional units are dropped from the result. Calling 071 * getDifference reverses the effect of calling add. In the following code: 072 * 073 * <pre> 074 * long instant = ... 075 * int v = ... 076 * int age = getDifference(add(instant, v), instant); 077 * </pre> 078 * 079 * The value 'age' is the same as the value 'v'. 080 * <p> 081 * The default implementation call getDifferenceAsLong and converts the 082 * return value to an int. 083 * 084 * @param minuendInstant the milliseconds from 1970-01-01T00:00:00Z to 085 * subtract from 086 * @param subtrahendInstant the milliseconds from 1970-01-01T00:00:00Z to 087 * subtract off the minuend 088 * @return the difference in the units of this field 089 */ 090 public int getDifference(long minuendInstant, long subtrahendInstant) { 091 return FieldUtils.safeToInt(getDifferenceAsLong(minuendInstant, subtrahendInstant)); 092 } 093 094 /** 095 * Computes the difference between two instants, as measured in the units 096 * of this field. Any fractional units are dropped from the result. Calling 097 * getDifference reverses the effect of calling add. In the following code: 098 * 099 * <pre> 100 * long instant = ... 101 * long v = ... 102 * long age = getDifferenceAsLong(add(instant, v), instant); 103 * </pre> 104 * 105 * The value 'age' is the same as the value 'v'. 106 * <p> 107 * The default implementation performs a guess-and-check algorithm using 108 * getDurationField().getUnitMillis() and the add() method. Subclasses are 109 * encouraged to provide a more efficient implementation. 110 * 111 * @param minuendInstant the milliseconds from 1970-01-01T00:00:00Z to 112 * subtract from 113 * @param subtrahendInstant the milliseconds from 1970-01-01T00:00:00Z to 114 * subtract off the minuend 115 * @return the difference in the units of this field 116 */ 117 public long getDifferenceAsLong(long minuendInstant, long subtrahendInstant) { 118 if (minuendInstant < subtrahendInstant) { 119 return -getDifferenceAsLong(subtrahendInstant, minuendInstant); 120 } 121 122 long difference = (minuendInstant - subtrahendInstant) / iUnitMillis; 123 if (add(subtrahendInstant, difference) < minuendInstant) { 124 do { 125 difference++; 126 } while (add(subtrahendInstant, difference) <= minuendInstant); 127 difference--; 128 } else if (add(subtrahendInstant, difference) > minuendInstant) { 129 do { 130 difference--; 131 } while (add(subtrahendInstant, difference) > minuendInstant); 132 } 133 return difference; 134 } 135 136 public final DurationField getDurationField() { 137 return iDurationField; 138 } 139 140 public abstract DurationField getRangeDurationField(); 141 142 public abstract long roundFloor(long instant); 143 144 protected final long getDurationUnitMillis() { 145 return iUnitMillis; 146 } 147 148 private final class LinkedDurationField extends BaseDurationField { 149 private static final long serialVersionUID = -203813474600094134L; 150 151 LinkedDurationField(DurationFieldType type) { 152 super(type); 153 } 154 155 public boolean isPrecise() { 156 return false; 157 } 158 159 public long getUnitMillis() { 160 return iUnitMillis; 161 } 162 163 public int getValue(long duration, long instant) { 164 return ImpreciseDateTimeField.this 165 .getDifference(instant + duration, instant); 166 } 167 168 public long getValueAsLong(long duration, long instant) { 169 return ImpreciseDateTimeField.this 170 .getDifferenceAsLong(instant + duration, instant); 171 } 172 173 public long getMillis(int value, long instant) { 174 return ImpreciseDateTimeField.this.add(instant, value) - instant; 175 } 176 177 public long getMillis(long value, long instant) { 178 return ImpreciseDateTimeField.this.add(instant, value) - instant; 179 } 180 181 public long add(long instant, int value) { 182 return ImpreciseDateTimeField.this.add(instant, value); 183 } 184 185 public long add(long instant, long value) { 186 return ImpreciseDateTimeField.this.add(instant, value); 187 } 188 189 public int getDifference(long minuendInstant, long subtrahendInstant) { 190 return ImpreciseDateTimeField.this 191 .getDifference(minuendInstant, subtrahendInstant); 192 } 193 194 public long getDifferenceAsLong(long minuendInstant, long subtrahendInstant) { 195 return ImpreciseDateTimeField.this 196 .getDifferenceAsLong(minuendInstant, subtrahendInstant); 197 } 198 } 199 200 }