1 22 23 package org.xquark.schema.datatypes; 24 25 import java.text.ParseException ; 26 27 public class Duration implements Comparable { 28 29 private static final String RCSRevision = "$Revision: 1.1 $"; 30 private static final String RCSName = "$Name: $"; 31 32 private static long MILLISINMIN = 60000L; 33 private static long MILLISINHOUR = MILLISINMIN * 60; 34 private static long MILLISINDAY = MILLISINHOUR * 24; 35 private static int MONTHSINYEAR = 12; 36 private static int[] MINDAYSINMONTHS = { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334 }; 37 private static int[] MAXDAYSINMONTHS = { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337 }; 38 private static int[] POWERSOFTEN = { 1, 10, 100, 1000 }; 39 private static int MILLISECOND_FIELD = 1 << 0; 40 private static int MINUTE_FIELD = 1 << 1; 41 private static int HOUR_FIELD = 1 << 2; 42 private static int DAY_FIELD = 1 << 3; 43 private static int MONTH_FIELD = 1 << 4; 44 private static int YEAR_FIELD = 1 << 5; 45 private static int SIGN_FIELD = 1 << 6; 46 47 private int fields = 0; 48 private int sign = 1; 49 private int year = 0; 50 private int month = 0; 51 private int day = 0; 52 private int hour = 0; 53 private int minute = 0; 54 private long millisecond = 0; 55 56 public Duration(String value) throws ParseException { 57 parseDuration(value); } 59 60 public Duration(int sign, int year, int month, int day, int hour, int minute, long millisecond) { 61 this.sign = sign; 62 this.year = year; 63 this.month = month; 64 this.day = day; 65 this.hour = hour; 66 this.minute = minute; 67 this.millisecond = millisecond; 68 } 69 70 79 public int compareTo(Object obj) throws ClassCastException , IllegalArgumentException { 80 return compareTo((Duration) obj); 81 } 82 83 private int compareTo(Duration other) throws IllegalArgumentException { 84 if (this.sign < other.sign) { 85 return -1; 86 } else if (this.sign > other.sign) { 87 return 1; 88 } else { 89 long deltaMillis = this.getDayTime()-other.getDayTime(); 90 int deltaMonths = this.getYearMonth()-other.getYearMonth(); 91 if (deltaMonths == 0) { 92 return (deltaMillis == 0) ? 0 : ((deltaMillis < 0) ? -this.sign : this.sign); 93 } else if (deltaMillis == 0) { 94 return (deltaMonths < 0) ? -this.sign : this.sign; 95 } else { 96 long min = 0; 97 long max = 0; 98 if (deltaMonths > 0) { 99 min = getMinDaysFromMonths(deltaMonths) * MILLISINDAY; 100 max = getMaxDaysFromMonths(deltaMonths) * MILLISINDAY; 101 } else { 102 max = -getMinDaysFromMonths(-deltaMonths) * MILLISINDAY; 103 min = -getMaxDaysFromMonths(-deltaMonths) * MILLISINDAY; 104 } 105 if (max+deltaMillis < 0) 106 return -this.sign; 107 else if (min+deltaMillis > 0) 108 return this.sign; 109 else 110 throw new IllegalArgumentException ("Indeterminate comparison result for these arguments"); 111 } 112 } 113 } 114 115 private int getYearMonth() { 116 return year * MONTHSINYEAR + month; 117 } 118 119 private long getDayTime() { 120 return day * MILLISINDAY + hour * MILLISINHOUR + minute * MILLISINMIN + millisecond; 121 } 122 123 private static int getMinDaysFromMonths(int nMonths) { 124 int m = nMonths % MONTHSINYEAR; 125 int y = nMonths / MONTHSINYEAR; 126 return y * 365 + MINDAYSINMONTHS[m] + getMinLeapYears(y + ((m > 0) ? 1 : 0)); 127 } 128 129 private static int getMaxDaysFromMonths(int nMonths) { 130 int m = nMonths % MONTHSINYEAR; 131 int y = nMonths / MONTHSINYEAR; 132 return y * 365 + MAXDAYSINMONTHS[m] + getMaxLeapYears(y); 133 } 134 135 private static int getMinLeapYears(int y) { 136 if (y < 8) 137 return 0; 138 else if (y < 300) 139 return y / 4 - (y / 100 + 1); 140 else if (y < 400) 141 return y / 4 - y / 100; 142 else 143 return y / 400 * 97 + getMinLeapYears(y % 400); 144 } 145 146 private static int getMaxLeapYears(int y) { 147 int part = (y % 4 == 0) ? 0 : 1; 148 if (y < 200) 149 return y / 4 + part; 150 else if (y < 400) 151 return y / 4 + part - (y / 100 - 1); 152 else 153 return y / 400 * 97 + getMaxLeapYears(y % 400); 154 } 155 156 public boolean equals(Object obj) { 157 if (this == obj) 158 return true; 159 if (!(obj instanceof Duration)) 160 return false; 161 Duration other = (Duration) obj; 162 return this.sign == other.sign 163 && this.getYearMonth() == other.getYearMonth() 164 && this.getDayTime() == other.getDayTime(); 165 } 166 167 public int hashCode() { 168 long m = getDayTime(); 169 int highMillis = (int) (m >> 32); 170 int lowMillis = (int) (m & 0x00000000ffffffffL); 171 return sign ^ getYearMonth() ^ highMillis ^ lowMillis; 172 } 173 174 private void setField(int field) { 175 fields |= field; 176 } 177 178 private boolean hasField(int field) { 179 return (fields & field) != 0; 180 } 181 182 public String toString() { 183 StringBuffer print = new StringBuffer (20); 184 if (sign == -1) 185 print.append('-'); 186 print.append('P'); 187 if (hasField(YEAR_FIELD)) { 188 print.append(year); 189 print.append('Y'); 190 } 191 if (hasField(MONTH_FIELD)) { 192 print.append(month); 193 print.append('M'); 194 } 195 if (hasField(DAY_FIELD)) { 196 print.append(day); 197 print.append('D'); 198 } 199 boolean inTime = false; 200 if (hasField(HOUR_FIELD)) { 201 print.append('T'); 202 print.append(hour); 203 print.append('H'); 204 inTime = true; 205 } 206 if (hasField(MINUTE_FIELD)) { 207 if (!inTime) 208 print.append('T'); 209 print.append(minute); 210 print.append('M'); 211 inTime = true; 212 } 213 if (hasField(MILLISECOND_FIELD)) { 214 if (!inTime) 215 print.append('T'); 216 print.append(millisecond / 1000); 217 int millis = (int) millisecond % 1000; 218 if (millis > 0) { 219 print.append('.'); 220 if (millis < 10) { 221 print.append("00"); 222 print.append(millis); 223 } else if (millis < 100) { 224 print.append("0"); 225 print.append(millis); 226 } else { 227 print.append(millis); 228 } 229 int len = print.length(); 230 while (print.charAt(len-1) == '0') { 231 print.setLength(len-1); 232 len--; 233 } 234 } 235 print.append('S'); 236 } 237 return print.toString(); 238 } 239 240 private void parseDuration(String value) throws ParseException { 241 int len = value.length(); 242 int index = 0; 243 int fieldIndex = 0; 244 if (len <= 2) 245 throw new ParseException ("Invalid duration specification: " + value, index); 246 if (value.charAt(index) == '-') { 247 sign = -1; 248 index++; 249 setField(SIGN_FIELD); 250 } 251 if (value.charAt(index) != 'P') 252 throw new ParseException ("Invalid duration specification: " + value, index); 253 index++; 254 while (index < len && value.charAt(index) != 'T') { 255 int val = 0; 256 int second = -1; 257 int count = 0; 258 char c = 0; 259 while (index < len) { 260 c = value.charAt(index++); 261 if (!Character.isDigit(c)) break; 262 val *= 10; 263 val += ((int) c - (int) '0'); 264 count++; 265 } 266 if (c == 'Y') { 267 if (count == 0 || fieldIndex > 0) 268 throw new ParseException ("Invalid duration specification: " + value, index); 269 year = val; 270 fieldIndex = 1; 271 setField(YEAR_FIELD); 272 } else if (c == 'M') { 273 if (count == 0 || fieldIndex > 1) 274 throw new ParseException ("Invalid duration specification: " + value, index); 275 month = val; 276 fieldIndex = 2; 277 setField(MONTH_FIELD); 278 } else if (count == 0 || c == 'D') { 279 if (fieldIndex > 2) 280 throw new ParseException ("Invalid duration specification: " + value, index); 281 day = val; 282 fieldIndex = 3; 283 setField(DAY_FIELD); 284 } else { 285 throw new ParseException ("Invalid duration specification: " + value, index); 286 } 287 } 288 if (index < len) { 289 index++; 290 while (index < len) { 291 int val = 0; 292 int second = -1; 293 int count = 0; 294 char c = 0; 295 while (index < len) { 296 c = value.charAt(index++); 297 if (!Character.isDigit(c)) break; 298 val *= 10; 299 val += ((int) c - (int) '0'); 300 count++; 301 } 302 if (c == 'H') { 303 if (count == 0 || fieldIndex > 3) 304 throw new ParseException ("Invalid duration specification: " + value, index); 305 hour = val; 306 fieldIndex = 4; 307 setField(HOUR_FIELD); 308 } else if (c == 'M') { 309 if (count == 0 || fieldIndex > 4) 310 throw new ParseException ("Invalid duration specification: " + value, index); 311 minute = val; 312 fieldIndex = 5; 313 setField(MINUTE_FIELD); 314 } else if (c == '.') { 315 if (count == 0 || fieldIndex > 5) 316 throw new ParseException ("Invalid duration specification: " + value, index); 317 second = val; 318 fieldIndex = 6; 319 } else if (c == 'S') { 320 if (count == 0 || fieldIndex > 6) 321 throw new ParseException ("Invalid duration specification: " + value, index); 322 if (second != -1) { 323 if (count > 3) { 324 val = (int)(val/Math.pow(10, count-3)); 326 } else { 327 val *= POWERSOFTEN[3 - count]; 328 } 329 millisecond = 1000*second+val; 330 } else { 331 millisecond = 1000*val; 332 } 333 fieldIndex = 7; 334 setField(MILLISECOND_FIELD); 335 } else { 336 throw new ParseException ("Invalid duration specification: " + value, index); 337 } 338 } 339 if (fieldIndex < 4 || fieldIndex == 6) 340 throw new ParseException ("Invalid duration specification: " + value, index); 341 } else if (fieldIndex == 0) { 342 throw new ParseException ("Invalid duration specification: " + value, index); 343 } 344 } 345 } 346 | Popular Tags |