| .. | .. |
|---|
| 3 | 3 | import java.util.*; |
|---|
| 4 | 4 | import java.text.*; |
|---|
| 5 | 5 | |
|---|
| 6 | | -public class TimeUnit { |
|---|
| 6 | +public class TimeUnit |
|---|
| 7 | +{ |
|---|
| 8 | + public static final TimeUnit YEAR = new TimeUnit("Years", Calendar.YEAR, 365 * 24 * 60 * 60 * 1000L, "yyyy", "yyyy"); |
|---|
| 9 | + public static final TimeUnit MONTH = new TimeUnit("Months", Calendar.MONTH, 30 * 24 * 60 * 60 * 1000L, "MMM", "MMM yyyy"); |
|---|
| 10 | + public static final TimeUnit WEEK = new TimeUnit("Weeks", Calendar.WEEK_OF_YEAR, 7 * 24 * 60 * 60 * 1000L, "d", "MMM d yyyy"); |
|---|
| 11 | + public static final TimeUnit DAY = new TimeUnit("Days", Calendar.DAY_OF_MONTH, 24 * 60 * 60 * 1000L, "d", "MMM d yyyy"); |
|---|
| 12 | + public static final TimeUnit DAY_OF_WEEK = new TimeUnit("Days", Calendar.DAY_OF_WEEK, 24 * 60 * 60 * 1000L, "d", "MMM d yyyy"); |
|---|
| 13 | + public static final TimeUnit HOUR = new TimeUnit("Hours", Calendar.HOUR_OF_DAY, 60 * 60 * 1000L, "HH:mm", "MMM d yyyy HH:mm"); |
|---|
| 14 | + public static final TimeUnit MINUTE = new TimeUnit("Minutes", Calendar.MINUTE, 60 * 1000L, ":mm", "MMM d yyyy HH:mm"); |
|---|
| 15 | + public static final TimeUnit SECOND = new TimeUnit("Seconds", Calendar.SECOND, 1000L, ":ss", "MMM d yyyy HH:mm:ss"); |
|---|
| 16 | + public static final TimeUnit REALTIME = new TimeUnit("Realtime", Calendar.MILLISECOND, 1L, ".SS", "HH:mm:ss.SS"); |
|---|
| 17 | + |
|---|
| 18 | + public static final TimeUnit DECADE = multipleYears(10); |
|---|
| 19 | + public static final TimeUnit CENTURY = multipleYears(100); |
|---|
| 20 | + private static final double DAY_SIZE = 24 * 60 * 60 * 1000L; |
|---|
| 21 | + private int quantity; |
|---|
| 22 | + private long roughSize; |
|---|
| 23 | + private SimpleDateFormat format, fullFormat; |
|---|
| 24 | + private String name; |
|---|
| 25 | + private int calendarCode; |
|---|
| 7 | 26 | |
|---|
| 8 | | - public static final TimeUnit YEAR=new TimeUnit("Years", Calendar.YEAR, 365*24*60*60*1000L, "yyyy", "yyyy"); |
|---|
| 9 | | - public static final TimeUnit MONTH=new TimeUnit("Months", Calendar.MONTH, 30*24*60*60*1000L, "MMM", "MMM yyyy"); |
|---|
| 10 | | - public static final TimeUnit WEEK=new TimeUnit("Weeks", Calendar.WEEK_OF_YEAR, 7*24*60*60*1000L, "d", "MMM d yyyy"); |
|---|
| 11 | | - public static final TimeUnit DAY=new TimeUnit("Days", Calendar.DAY_OF_MONTH, 24*60*60*1000L, "d", "MMM d yyyy"); |
|---|
| 12 | | - public static final TimeUnit DAY_OF_WEEK=new TimeUnit("Days", Calendar.DAY_OF_WEEK, 24*60*60*1000L, "d", "MMM d yyyy"); |
|---|
| 13 | | - public static final TimeUnit HOUR=new TimeUnit("Hours", Calendar.HOUR_OF_DAY, 60*60*1000L, "kk:mm", "MMM d yyyy kk:mm"); |
|---|
| 14 | | - public static final TimeUnit MINUTE=new TimeUnit("Minutes", Calendar.MINUTE, 60*1000L, ":mm", "MMM d yyyy kk:mm"); |
|---|
| 15 | | - public static final TimeUnit SECOND=new TimeUnit("Seconds", Calendar.SECOND, 1000L, ":ss", "MMM d yyyy kk:mm:ss"); |
|---|
| 16 | | - public static final TimeUnit DECADE=multipleYears(10); |
|---|
| 17 | | - public static final TimeUnit CENTURY=multipleYears(100); |
|---|
| 18 | | - |
|---|
| 19 | | - private static final double DAY_SIZE=24*60*60*1000L; |
|---|
| 20 | | - |
|---|
| 21 | | - private int quantity; |
|---|
| 22 | | - private long roughSize; |
|---|
| 23 | | - private SimpleDateFormat format, fullFormat; |
|---|
| 24 | | - private String name; |
|---|
| 25 | | - private int calendarCode; |
|---|
| 26 | | - |
|---|
| 27 | | - private TimeUnit() |
|---|
| 28 | | - { |
|---|
| 29 | | - } |
|---|
| 30 | | - |
|---|
| 31 | | - private TimeUnit(String name, int calendarCode, long roughSize, String formatPattern, String fullFormatPattern) |
|---|
| 32 | | - { |
|---|
| 33 | | - this.name=name; |
|---|
| 34 | | - this.calendarCode=calendarCode; |
|---|
| 35 | | - this.roughSize=roughSize; |
|---|
| 36 | | - format=new SimpleDateFormat(formatPattern); |
|---|
| 37 | | - fullFormat=new SimpleDateFormat(fullFormatPattern); |
|---|
| 38 | | - quantity=1; |
|---|
| 39 | | - } |
|---|
| 40 | | - |
|---|
| 41 | | - public String toString() |
|---|
| 42 | | - { |
|---|
| 43 | | - return "[TimeUnit: "+name+"]"; |
|---|
| 44 | | - } |
|---|
| 27 | + private TimeUnit() |
|---|
| 28 | + { |
|---|
| 29 | + } |
|---|
| 45 | 30 | |
|---|
| 46 | | - public static TimeUnit multipleYears(int numYears) |
|---|
| 47 | | - { |
|---|
| 48 | | - TimeUnit t=new TimeUnit(); |
|---|
| 49 | | - t.name=numYears+" Years"; |
|---|
| 50 | | - t.calendarCode=Calendar.YEAR; |
|---|
| 51 | | - t.roughSize=YEAR.roughSize*numYears; |
|---|
| 52 | | - t.format=YEAR.format; |
|---|
| 53 | | - t.fullFormat=YEAR.fullFormat; |
|---|
| 54 | | - t.quantity=numYears; |
|---|
| 55 | | - return t; |
|---|
| 56 | | - } |
|---|
| 57 | | - |
|---|
| 58 | | - public static TimeUnit multipleWeeks(int num) |
|---|
| 59 | | - { |
|---|
| 60 | | - TimeUnit t=new TimeUnit(); |
|---|
| 61 | | - t.name=num+" Weeks"; |
|---|
| 62 | | - t.calendarCode=Calendar.WEEK_OF_YEAR; |
|---|
| 63 | | - t.roughSize=WEEK.roughSize*num; |
|---|
| 64 | | - t.format=WEEK.format; |
|---|
| 65 | | - t.fullFormat=WEEK.fullFormat; |
|---|
| 66 | | - t.quantity=num; |
|---|
| 67 | | - return t; |
|---|
| 68 | | - } |
|---|
| 69 | | - |
|---|
| 70 | | - public TimeUnit times(int quantity) |
|---|
| 71 | | - { |
|---|
| 72 | | - TimeUnit t=new TimeUnit(); |
|---|
| 73 | | - t.name=quantity+" "+this.name; |
|---|
| 74 | | - t.calendarCode=this.calendarCode; |
|---|
| 75 | | - t.roughSize=this.roughSize*quantity; |
|---|
| 76 | | - t.format=this.format; |
|---|
| 77 | | - t.fullFormat=this.fullFormat; |
|---|
| 78 | | - t.quantity=quantity; |
|---|
| 79 | | - return t; |
|---|
| 80 | | - |
|---|
| 81 | | - } |
|---|
| 31 | + private TimeUnit(String name, int calendarCode, long roughSize, String formatPattern, String fullFormatPattern) |
|---|
| 32 | + { |
|---|
| 33 | + this.name = name; |
|---|
| 34 | + this.calendarCode = calendarCode; |
|---|
| 35 | + this.roughSize = roughSize; |
|---|
| 36 | + format = new SimpleDateFormat(formatPattern); |
|---|
| 37 | + fullFormat = new SimpleDateFormat(fullFormatPattern); |
|---|
| 38 | + quantity = 1; |
|---|
| 39 | + } |
|---|
| 82 | 40 | |
|---|
| 83 | | - |
|---|
| 84 | | - public int numUnitsIn(TimeUnit u) |
|---|
| 85 | | - { |
|---|
| 86 | | - return (int)Math.round(u.getRoughSize()/(double)getRoughSize()); |
|---|
| 87 | | - } |
|---|
| 88 | | - |
|---|
| 89 | | - public boolean isDayOrLess() |
|---|
| 90 | | - { |
|---|
| 91 | | - return roughSize <= 24*60*60*1000L; |
|---|
| 92 | | - } |
|---|
| 93 | | - |
|---|
| 94 | | - public RoughTime roundDown(long timestamp) |
|---|
| 95 | | - { |
|---|
| 96 | | - return round(timestamp, false); |
|---|
| 97 | | - } |
|---|
| 98 | | - |
|---|
| 99 | | - public RoughTime roundUp(long timestamp) |
|---|
| 100 | | - { |
|---|
| 101 | | - return round(timestamp, true); |
|---|
| 102 | | - } |
|---|
| 103 | | - |
|---|
| 104 | | - private static final int[] calendarUnits={Calendar.SECOND, Calendar.MINUTE, Calendar.HOUR_OF_DAY, Calendar.DAY_OF_MONTH, Calendar.MONTH, Calendar.YEAR}; |
|---|
| 105 | | - public RoughTime round(long timestamp, boolean up) |
|---|
| 106 | | - { |
|---|
| 107 | | - Calendar c=TimeUtils.cal(timestamp); |
|---|
| 108 | | - |
|---|
| 109 | | - if (calendarCode==Calendar.WEEK_OF_YEAR ) |
|---|
| 110 | | - { |
|---|
| 111 | | - c.set(Calendar.DAY_OF_WEEK, c.getMinimum(Calendar.DAY_OF_WEEK)); |
|---|
| 112 | | - } |
|---|
| 113 | | - else |
|---|
| 114 | | - { |
|---|
| 115 | | - |
|---|
| 116 | | - // set to minimum all fields of finer granularity. |
|---|
| 117 | | - int roundingCode=calendarCode; |
|---|
| 118 | | - if (calendarCode==Calendar.WEEK_OF_YEAR || calendarCode==Calendar.DAY_OF_WEEK) |
|---|
| 119 | | - roundingCode=Calendar.DAY_OF_MONTH; |
|---|
| 120 | | - for (int i=0; i<calendarUnits.length; i++) |
|---|
| 121 | | - { |
|---|
| 122 | | - if (calendarUnits[i]==roundingCode) |
|---|
| 123 | | - break; |
|---|
| 124 | | - if (i==calendarUnits.length-1) |
|---|
| 125 | | - throw new IllegalArgumentException("Unsupported Calendar Unit: "+calendarCode); |
|---|
| 126 | | - c.set(calendarUnits[i], c.getMinimum(calendarUnits[i])); |
|---|
| 127 | | - } |
|---|
| 128 | | - if (quantity>1) |
|---|
| 129 | | - { |
|---|
| 130 | | - c.set(calendarCode, quantity*(c.get(calendarCode)/quantity)); |
|---|
| 131 | | - } |
|---|
| 132 | | - } |
|---|
| 133 | | - |
|---|
| 134 | | - // if rounding up, then add a unit at current granularity. |
|---|
| 135 | | - if (up) |
|---|
| 136 | | - c.add(calendarCode, quantity); |
|---|
| 137 | | - |
|---|
| 138 | | - return new RoughTime(c.getTimeInMillis(), this); |
|---|
| 139 | | - } |
|---|
| 140 | | - |
|---|
| 141 | | - public int get(long timestamp) |
|---|
| 142 | | - { |
|---|
| 143 | | - Calendar c= TimeUtils.cal(timestamp); |
|---|
| 144 | | - int n=c.get(calendarCode); |
|---|
| 145 | | - return quantity==1 ? n : n%quantity; |
|---|
| 146 | | - } |
|---|
| 147 | | - |
|---|
| 148 | | - public void addTo(RoughTime r) |
|---|
| 149 | | - { |
|---|
| 150 | | - addTo(r,1); |
|---|
| 151 | | - } |
|---|
| 152 | | - |
|---|
| 153 | | - public void addTo(RoughTime r, int times) |
|---|
| 154 | | - { |
|---|
| 155 | | - Calendar c=TimeUtils.cal(r.getTime()); |
|---|
| 156 | | - c.add(calendarCode, quantity*times); |
|---|
| 157 | | - r.setTime(c.getTimeInMillis()); |
|---|
| 158 | | - } |
|---|
| 159 | | - |
|---|
| 160 | | - // Finding the difference between two dates, in a given unit of time, |
|---|
| 161 | | - // is much subtler than you'd think! And annoyingly, the Calendar class does not do |
|---|
| 162 | | - // this for you, even though it actually "knows" how to do so since it |
|---|
| 163 | | - // can add fields. |
|---|
| 164 | | - // |
|---|
| 165 | | - // The most vexing problem is dealing with daylight savings time, |
|---|
| 166 | | - // which means that one day a year has 23 hours and one day has 25 hours. |
|---|
| 167 | | - // We also have to handle the fact that months and years aren't constant lengths. |
|---|
| 168 | | - // |
|---|
| 169 | | - // Rather than write all this ourselves, in this code we |
|---|
| 170 | | - // use the Calendar class to do the heavy lifting. |
|---|
| 171 | | - public long difference(long x, long y) |
|---|
| 172 | | - { |
|---|
| 173 | | - // If this is not one of the hard cases, |
|---|
| 174 | | - // just divide the timespan by the length of time unit. |
|---|
| 175 | | - // Note that we're not worrying about hours and daylight savings time. |
|---|
| 176 | | - if (calendarCode!=Calendar.YEAR && calendarCode!=Calendar.MONTH && |
|---|
| 177 | | - calendarCode!=Calendar.DAY_OF_MONTH && calendarCode!=Calendar.DAY_OF_WEEK && |
|---|
| 178 | | - calendarCode!=Calendar.WEEK_OF_YEAR) |
|---|
| 179 | | - { |
|---|
| 180 | | - return (x-y)/roughSize; |
|---|
| 181 | | - } |
|---|
| 182 | | - |
|---|
| 183 | | - Calendar c1=TimeUtils.cal(x), c2=TimeUtils.cal(y); |
|---|
| 184 | | - int diff=0; |
|---|
| 185 | | - switch (calendarCode) |
|---|
| 186 | | - { |
|---|
| 187 | | - case Calendar.YEAR: |
|---|
| 188 | | - return (c1.get(Calendar.YEAR)-c2.get(Calendar.YEAR))/quantity; |
|---|
| 189 | | - |
|---|
| 190 | | - case Calendar.MONTH: |
|---|
| 191 | | - diff= 12*(c1.get(Calendar.YEAR)-c2.get(Calendar.YEAR))+ |
|---|
| 192 | | - c1.get(Calendar.MONTH)-c2.get(Calendar.MONTH); |
|---|
| 193 | | - return diff/quantity; |
|---|
| 194 | | - |
|---|
| 195 | | - case Calendar.DAY_OF_MONTH: |
|---|
| 196 | | - case Calendar.DAY_OF_WEEK: |
|---|
| 197 | | - case Calendar.DAY_OF_YEAR: |
|---|
| 198 | | - case Calendar.WEEK_OF_MONTH: |
|---|
| 199 | | - case Calendar.WEEK_OF_YEAR: |
|---|
| 200 | | - // This is ugly, but believe me, it beats the alternative methods :-) |
|---|
| 201 | | - // We use the Calendar class's knowledge of daylight savings time. |
|---|
| 202 | | - // and also the fact that if we calculate this naively, then we aren't going |
|---|
| 203 | | - // to be off by more than one in either direction. |
|---|
| 204 | | - int naive=(int)Math.round((x-y)/(double)roughSize); |
|---|
| 205 | | - c2.add(calendarCode, naive*quantity); |
|---|
| 206 | | - if (c1.get(calendarCode)==c2.get(calendarCode)) |
|---|
| 207 | | - return naive/quantity; |
|---|
| 208 | | - c2.add(calendarCode, quantity); |
|---|
| 209 | | - if (c1.get(calendarCode)==c2.get(calendarCode)) |
|---|
| 210 | | - return naive/quantity+1; |
|---|
| 211 | | - return naive/quantity-1; |
|---|
| 212 | | - } |
|---|
| 213 | | - throw new IllegalArgumentException("Unexpected calendar code: "+calendarCode); |
|---|
| 214 | | - } |
|---|
| 41 | + public String toString() |
|---|
| 42 | + { |
|---|
| 43 | + return "[TimeUnit: " + name + "]"; |
|---|
| 44 | + } |
|---|
| 215 | 45 | |
|---|
| 216 | | - public long approxNumInRange(long start, long end) |
|---|
| 217 | | - { |
|---|
| 218 | | - return 1+(end-start)/roughSize; |
|---|
| 219 | | - } |
|---|
| 220 | | - |
|---|
| 221 | | - public long getRoughSize() { |
|---|
| 222 | | - return roughSize; |
|---|
| 223 | | - } |
|---|
| 46 | + public static TimeUnit multipleYears(int numYears) |
|---|
| 47 | + { |
|---|
| 48 | + TimeUnit t = new TimeUnit(); |
|---|
| 49 | + t.name = numYears + " Years"; |
|---|
| 50 | + t.calendarCode = Calendar.YEAR; |
|---|
| 51 | + t.roughSize = YEAR.roughSize * numYears; |
|---|
| 52 | + t.format = YEAR.format; |
|---|
| 53 | + t.fullFormat = YEAR.fullFormat; |
|---|
| 54 | + t.quantity = numYears; |
|---|
| 55 | + return t; |
|---|
| 56 | + } |
|---|
| 224 | 57 | |
|---|
| 225 | | - public String format(Date date) |
|---|
| 226 | | - { |
|---|
| 227 | | - return format.format(date); |
|---|
| 228 | | - } |
|---|
| 58 | + public static TimeUnit multipleWeeks(int num) |
|---|
| 59 | + { |
|---|
| 60 | + TimeUnit t = new TimeUnit(); |
|---|
| 61 | + t.name = num + " Weeks"; |
|---|
| 62 | + t.calendarCode = Calendar.WEEK_OF_YEAR; |
|---|
| 63 | + t.roughSize = WEEK.roughSize * num; |
|---|
| 64 | + t.format = WEEK.format; |
|---|
| 65 | + t.fullFormat = WEEK.fullFormat; |
|---|
| 66 | + t.quantity = num; |
|---|
| 67 | + return t; |
|---|
| 68 | + } |
|---|
| 229 | 69 | |
|---|
| 230 | | - public String formatFull(Date date) |
|---|
| 231 | | - { |
|---|
| 232 | | - return fullFormat.format(date); |
|---|
| 233 | | - } |
|---|
| 70 | + public TimeUnit times(int quantity) |
|---|
| 71 | + { |
|---|
| 72 | + TimeUnit t = new TimeUnit(); |
|---|
| 73 | + t.name = quantity + " " + this.name; |
|---|
| 74 | + t.calendarCode = this.calendarCode; |
|---|
| 75 | + t.roughSize = this.roughSize * quantity; |
|---|
| 76 | + t.format = this.format; |
|---|
| 77 | + t.fullFormat = this.fullFormat; |
|---|
| 78 | + t.quantity = quantity; |
|---|
| 79 | + return t; |
|---|
| 234 | 80 | |
|---|
| 235 | | - public String formatFull(long timestamp) |
|---|
| 236 | | - { |
|---|
| 237 | | - return fullFormat.format(new Date(timestamp)); |
|---|
| 238 | | - } |
|---|
| 81 | + } |
|---|
| 239 | 82 | |
|---|
| 240 | | - public String getName() { |
|---|
| 241 | | - return name; |
|---|
| 242 | | - } |
|---|
| 83 | + public int numUnitsIn(TimeUnit u) |
|---|
| 84 | + { |
|---|
| 85 | + return (int) Math.round(u.getRoughSize() / (double) getRoughSize()); |
|---|
| 86 | + } |
|---|
| 87 | + |
|---|
| 88 | + public boolean isDayOrLess() |
|---|
| 89 | + { |
|---|
| 90 | + return roughSize <= 24 * 60 * 60 * 1000L; |
|---|
| 91 | + } |
|---|
| 92 | + |
|---|
| 93 | + public RoughTime roundDown(long timestamp) |
|---|
| 94 | + { |
|---|
| 95 | + return round(timestamp, false); |
|---|
| 96 | + } |
|---|
| 97 | + |
|---|
| 98 | + public RoughTime roundUp(long timestamp) |
|---|
| 99 | + { |
|---|
| 100 | + return round(timestamp, true); |
|---|
| 101 | + } |
|---|
| 102 | + private static final int[] calendarUnits = |
|---|
| 103 | + { |
|---|
| 104 | + Calendar.MILLISECOND, Calendar.SECOND, Calendar.MINUTE, Calendar.HOUR_OF_DAY, Calendar.DAY_OF_MONTH, Calendar.MONTH, Calendar.YEAR |
|---|
| 105 | + }; |
|---|
| 106 | + |
|---|
| 107 | + public RoughTime round(long timestamp, boolean up) |
|---|
| 108 | + { |
|---|
| 109 | + Calendar c = TimeUtils.cal(timestamp); |
|---|
| 110 | + |
|---|
| 111 | + if (calendarCode == Calendar.WEEK_OF_YEAR) |
|---|
| 112 | + { |
|---|
| 113 | + c.set(Calendar.DAY_OF_WEEK, c.getMinimum(Calendar.DAY_OF_WEEK)); |
|---|
| 114 | + } else |
|---|
| 115 | + { |
|---|
| 116 | + |
|---|
| 117 | + // set to minimum all fields of finer granularity. |
|---|
| 118 | + int roundingCode = calendarCode; |
|---|
| 119 | + if (calendarCode == Calendar.WEEK_OF_YEAR || calendarCode == Calendar.DAY_OF_WEEK) |
|---|
| 120 | + { |
|---|
| 121 | + roundingCode = Calendar.DAY_OF_MONTH; |
|---|
| 122 | + } |
|---|
| 123 | + for (int i = 0; i < calendarUnits.length; i++) |
|---|
| 124 | + { |
|---|
| 125 | + if (calendarUnits[i] == roundingCode) |
|---|
| 126 | + { |
|---|
| 127 | + break; |
|---|
| 128 | + } |
|---|
| 129 | + if (i == calendarUnits.length - 1) |
|---|
| 130 | + { |
|---|
| 131 | + //throw new IllegalArgumentException("Unsupported Calendar Unit: " + calendarCode); |
|---|
| 132 | + } |
|---|
| 133 | + c.set(calendarUnits[i], c.getMinimum(calendarUnits[i])); |
|---|
| 134 | + } |
|---|
| 135 | + if (quantity > 1) |
|---|
| 136 | + { |
|---|
| 137 | + c.set(calendarCode, quantity * (c.get(calendarCode) / quantity)); |
|---|
| 138 | + } |
|---|
| 139 | + } |
|---|
| 140 | + |
|---|
| 141 | + // if rounding up, then add a unit at current granularity. |
|---|
| 142 | + if (up) |
|---|
| 143 | + { |
|---|
| 144 | + c.add(calendarCode, quantity); |
|---|
| 145 | + } |
|---|
| 146 | + |
|---|
| 147 | + return new RoughTime(c.getTimeInMillis(), this); |
|---|
| 148 | + } |
|---|
| 149 | + |
|---|
| 150 | + public int get(long timestamp) |
|---|
| 151 | + { |
|---|
| 152 | + Calendar c = TimeUtils.cal(timestamp); |
|---|
| 153 | + int n = c.get(calendarCode); |
|---|
| 154 | + return quantity == 1 ? n : n % quantity; |
|---|
| 155 | + } |
|---|
| 156 | + |
|---|
| 157 | + public void addTo(RoughTime r) |
|---|
| 158 | + { |
|---|
| 159 | + addTo(r, 1); |
|---|
| 160 | + } |
|---|
| 161 | + |
|---|
| 162 | + public void addTo(RoughTime r, int times) |
|---|
| 163 | + { |
|---|
| 164 | + Calendar c = TimeUtils.cal(r.getTime()); |
|---|
| 165 | + c.add(calendarCode, quantity * times); |
|---|
| 166 | + r.setTime(c.getTimeInMillis()); |
|---|
| 167 | + } |
|---|
| 168 | + |
|---|
| 169 | + // Finding the difference between two dates, in a given unit of time, |
|---|
| 170 | + // is much subtler than you'd think! And annoyingly, the Calendar class does not do |
|---|
| 171 | + // this for you, even though it actually "knows" how to do so since it |
|---|
| 172 | + // can add fields. |
|---|
| 173 | + // |
|---|
| 174 | + // The most vexing problem is dealing with daylight savings time, |
|---|
| 175 | + // which means that one day a year has 23 hours and one day has 25 hours. |
|---|
| 176 | + // We also have to handle the fact that months and years aren't constant lengths. |
|---|
| 177 | + // |
|---|
| 178 | + // Rather than write all this ourselves, in this code we |
|---|
| 179 | + // use the Calendar class to do the heavy lifting. |
|---|
| 180 | + public long difference(long x, long y) |
|---|
| 181 | + { |
|---|
| 182 | + // If this is not one of the hard cases, |
|---|
| 183 | + // just divide the timespan by the length of time unit. |
|---|
| 184 | + // Note that we're not worrying about hours and daylight savings time. |
|---|
| 185 | + if (calendarCode != Calendar.YEAR && calendarCode != Calendar.MONTH |
|---|
| 186 | + && calendarCode != Calendar.DAY_OF_MONTH && calendarCode != Calendar.DAY_OF_WEEK |
|---|
| 187 | + && calendarCode != Calendar.WEEK_OF_YEAR) |
|---|
| 188 | + { |
|---|
| 189 | + return (x - y) / roughSize; |
|---|
| 190 | + } |
|---|
| 191 | + |
|---|
| 192 | + Calendar c1 = TimeUtils.cal(x), c2 = TimeUtils.cal(y); |
|---|
| 193 | + int diff = 0; |
|---|
| 194 | + switch (calendarCode) |
|---|
| 195 | + { |
|---|
| 196 | + case Calendar.YEAR: |
|---|
| 197 | + return (c1.get(Calendar.YEAR) - c2.get(Calendar.YEAR)) / quantity; |
|---|
| 198 | + |
|---|
| 199 | + case Calendar.MONTH: |
|---|
| 200 | + diff = 12 * (c1.get(Calendar.YEAR) - c2.get(Calendar.YEAR)) |
|---|
| 201 | + + c1.get(Calendar.MONTH) - c2.get(Calendar.MONTH); |
|---|
| 202 | + return diff / quantity; |
|---|
| 203 | + |
|---|
| 204 | + case Calendar.DAY_OF_MONTH: |
|---|
| 205 | + case Calendar.DAY_OF_WEEK: |
|---|
| 206 | + case Calendar.DAY_OF_YEAR: |
|---|
| 207 | + case Calendar.WEEK_OF_MONTH: |
|---|
| 208 | + case Calendar.WEEK_OF_YEAR: |
|---|
| 209 | + // This is ugly, but believe me, it beats the alternative methods :-) |
|---|
| 210 | + // We use the Calendar class's knowledge of daylight savings time. |
|---|
| 211 | + // and also the fact that if we calculate this naively, then we aren't going |
|---|
| 212 | + // to be off by more than one in either direction. |
|---|
| 213 | + int naive = (int) Math.round((x - y) / (double) roughSize); |
|---|
| 214 | + c2.add(calendarCode, naive * quantity); |
|---|
| 215 | + if (c1.get(calendarCode) == c2.get(calendarCode)) |
|---|
| 216 | + { |
|---|
| 217 | + return naive / quantity; |
|---|
| 218 | + } |
|---|
| 219 | + c2.add(calendarCode, quantity); |
|---|
| 220 | + if (c1.get(calendarCode) == c2.get(calendarCode)) |
|---|
| 221 | + { |
|---|
| 222 | + return naive / quantity + 1; |
|---|
| 223 | + } |
|---|
| 224 | + return naive / quantity - 1; |
|---|
| 225 | + } |
|---|
| 226 | + throw new IllegalArgumentException("Unexpected calendar code: " + calendarCode); |
|---|
| 227 | + } |
|---|
| 228 | + |
|---|
| 229 | + public long approxNumInRange(long start, long end) |
|---|
| 230 | + { |
|---|
| 231 | + return 1 + (end - start) / roughSize; |
|---|
| 232 | + } |
|---|
| 233 | + |
|---|
| 234 | + public long getRoughSize() |
|---|
| 235 | + { |
|---|
| 236 | + return roughSize; |
|---|
| 237 | + } |
|---|
| 238 | + |
|---|
| 239 | + public String format(Date date) |
|---|
| 240 | + { |
|---|
| 241 | + return format.format(date); |
|---|
| 242 | + } |
|---|
| 243 | + |
|---|
| 244 | + public String formatFull(Date date) |
|---|
| 245 | + { |
|---|
| 246 | + return fullFormat.format(date); |
|---|
| 247 | + } |
|---|
| 248 | + |
|---|
| 249 | + public String formatFull(long timestamp) |
|---|
| 250 | + { |
|---|
| 251 | + return fullFormat.format(new Date(timestamp)); |
|---|
| 252 | + } |
|---|
| 253 | + |
|---|
| 254 | + public String getName() |
|---|
| 255 | + { |
|---|
| 256 | + return name; |
|---|
| 257 | + } |
|---|
| 243 | 258 | } |
|---|