1 package net.sf.saxon.value; 2 import net.sf.saxon.expr.XPathContext; 3 import net.sf.saxon.om.FastStringBuffer; 4 import net.sf.saxon.trans.DynamicError; 5 import net.sf.saxon.trans.XPathException; 6 import net.sf.saxon.type.ItemType; 7 import net.sf.saxon.type.Type; 8 9 import java.util.StringTokenizer ; 10 11 14 15 public final class SecondsDurationValue extends DurationValue implements Comparable { 16 17 20 21 private SecondsDurationValue() { 22 } 23 24 28 29 public SecondsDurationValue(CharSequence s) throws XPathException { 30 31 StringTokenizer tok = new StringTokenizer (trimWhitespace(s).toString(), "-+.PDTHMS", true); 32 try { 33 if (!tok.hasMoreElements()) badDuration("empty string", s); 34 String part = (String )tok.nextElement(); 35 if ("+".equals(part)) { 36 part = (String )tok.nextElement(); 37 } else if ("-".equals(part)) { 38 negative = true; 39 part = (String )tok.nextElement(); 40 } 41 if (!"P".equals(part)) badDuration("missing 'P'", s); 42 int state = 0; 43 while (tok.hasMoreElements()) { 44 part = (String )tok.nextElement(); 45 if ("T".equals(part)) { 46 state = 4; 47 part = (String )tok.nextElement(); 48 } 49 int value = Integer.parseInt(part); 50 if (!tok.hasMoreElements()) badDuration("missing unit letter at end", s); 51 char delim = ((String )tok.nextElement()).charAt(0); 52 switch (delim) { 53 case 'D': 54 if (state > 2) badDuration("D is out of sequence", s); 55 days = value; 56 state = 3; 57 break; 58 case 'H': 59 if (state != 4) badDuration("H is out of sequence", s); 60 hours = value; 61 state = 5; 62 break; 63 case 'M': 64 if (state < 4 || state > 5) badDuration("M is out of sequence", s); 65 minutes = value; 66 state = 6; 67 break; 68 case '.': 69 if (state < 4 || state > 6) badDuration("misplaced decimal point", s); 70 seconds = value; 71 state = 7; 72 break; 73 case 'S': 74 if (state < 4 || state > 7) badDuration("S is out of sequence", s); 75 if (state==7) { 76 while (part.length() < 6) part += "0"; 77 if (part.length() > 6) part = part.substring(0, 6); 78 microseconds = Integer.parseInt(part); 79 } else { 80 seconds = value; 81 } 82 state = 8; 83 break; 84 default: 85 badDuration("misplaced " + delim, s); 86 } 87 } 88 89 normalize(); 90 91 } catch (NumberFormatException err) { 92 badDuration("non-numeric or out-of-range component", s); 93 } 94 } 95 96 99 100 public SecondsDurationValue(int sign, int days, int hours, int minutes, int seconds, int microseconds) { 101 this.negative = (sign<0); 102 this.years = 0; 103 this.months = 0; 104 this.days = days; 105 this.hours = hours; 106 this.minutes = minutes; 107 this.seconds = seconds; 108 this.microseconds = microseconds; 109 } 110 111 115 116 public CharSequence getStringValueCS() { 117 118 120 double length = getLengthInSeconds(); 121 if (length<0) length = -length; 122 123 long secs = (long)Math.floor(length); 124 long micros = (int)((length % 1.0) * 1000000); 125 126 long s = secs % 60; 127 long m = secs / 60; 128 long h = m / 60; 129 m = m % 60; 130 long d = h / 24; 131 h = h % 24; 132 133 FastStringBuffer sb = new FastStringBuffer(32); 134 if (negative) { 135 sb.append('-'); 136 } 137 sb.append('P'); 138 if (d != 0) { 139 sb.append(d + "D"); 140 } 141 if ( d==0 || h!=0 || m!=0 || s!=0 || micros!=0) { 142 sb.append('T'); 143 } 144 if (h != 0) { 145 sb.append(h + "H"); 146 } 147 if (m != 0) { 148 sb.append(m + "M"); 149 } 150 if (s != 0 || micros != 0 || (d==0 && m==0 && h==0)) { 151 if (micros == 0) { 152 sb.append(s + "S"); 153 } else { 154 long ms = (s * 1000000) + micros; 155 String mss = ms + ""; 156 if (s == 0) { 157 mss = "0000000" + mss; 158 mss = mss.substring(mss.length()-7); 159 } 160 sb.append(mss.substring(0, mss.length()-6)); 161 sb.append('.'); 162 int lastSigDigit = mss.length()-1; 163 while (mss.charAt(lastSigDigit) == '0') { 164 lastSigDigit--; 165 } 166 sb.append(mss.substring(mss.length()-6, lastSigDigit+1)); 167 sb.append('S'); 168 } 169 } 170 return sb; 171 } 172 173 176 177 public void normalize() throws DynamicError { 178 long seconds2 = seconds; 179 long minutes2 = minutes; 180 long hours2 = hours; 181 long days2 = days; 182 if (microseconds >= 1000000) { 183 seconds2 += (microseconds / 1000000); 184 microseconds = microseconds % 1000000; 185 } 186 if (seconds >= 60) { 187 minutes2 += (seconds2 / 60); 188 seconds2 = (int)(seconds2 % 60); 189 } 190 if (minutes2 >= 60) { 191 hours2 += (minutes2 / 60); 192 minutes2 = (int)(minutes2 % 60); 193 } 194 if (hours2 >= 24) { 195 days2 += (hours2 / 24); 196 if (days2 > Integer.MAX_VALUE || days2 < Integer.MIN_VALUE) { 197 throw new DynamicError("Duration exceeds implementation-defined limits"); 198 } 199 hours2 = (int)(hours2 % 24); 200 } 201 days = (int)days2; 202 hours = (int)hours2; 203 minutes = (int)minutes2; 204 seconds = (int)seconds2; 205 } 206 207 210 211 public double getLengthInSeconds() { 212 double a = days; 213 a = a*24 + hours; 214 a = a*60 + minutes; 215 a = a*60 + seconds; 216 a += ((double)microseconds / 1000000); 217 return (negative ? -a : a); 219 } 220 221 224 225 public long getLengthInMilliseconds() { 226 long a = days; 227 a = a*24 + hours; 228 a = a*60 + minutes; 229 a = a*60 + seconds; 230 a = a*1000 + (microseconds / 1000); 231 return (negative ? -a : a); 232 } 233 234 237 238 public long getLengthInMicroseconds() { 239 long a = days; 240 a = a*24 + hours; 241 a = a*60 + minutes; 242 a = a*60 + seconds; 243 a = a*1000000 + microseconds; 244 return (negative ? -a : a); 245 } 246 247 248 251 252 public static SecondsDurationValue fromSeconds(double seconds) throws XPathException { 253 SecondsDurationValue sdv = new SecondsDurationValue(); 254 sdv.negative = (seconds<0); 255 sdv.seconds = (int)(seconds<0 ? -seconds : seconds); 256 sdv.microseconds = (int)((seconds % 1.0) * 1000000); 257 sdv.normalize(); 258 return sdv; 259 } 260 261 264 265 public static SecondsDurationValue fromMilliseconds(long milliseconds) throws XPathException { 266 SecondsDurationValue sdv = new SecondsDurationValue(); 267 sdv.negative = (milliseconds<0); 268 milliseconds = Math.abs(milliseconds); 269 long seconds = milliseconds/1000; 270 sdv.days = (int)(seconds / (3600*24)); 271 sdv.seconds = (int)(seconds % (3600*24)); 272 sdv.microseconds = (int)(milliseconds % 1000) * 1000; 273 sdv.normalize(); 274 return sdv; 275 } 276 277 280 281 public static SecondsDurationValue fromMicroseconds(long microseconds) throws XPathException { 282 SecondsDurationValue sdv = new SecondsDurationValue(); 283 sdv.negative = (microseconds<0); 284 microseconds = Math.abs(microseconds); 285 long seconds = microseconds/1000000L; 286 sdv.days = (int)(seconds / (3600*24)); 287 sdv.seconds = (int)(seconds % (3600*24)); 288 sdv.microseconds = (int)(microseconds % 1000000L); 289 sdv.normalize(); 290 return sdv; 291 } 292 293 294 297 298 public DurationValue multiply(double n, XPathContext context) throws XPathException { 299 double m = (double)getLengthInMicroseconds(); 300 double product = n*m; 301 if (Double.isInfinite(product) || product > Long.MAX_VALUE || product < Long.MIN_VALUE) { 302 DynamicError err = new DynamicError("Overflow when multiplying/dividing a duration by a number"); 303 err.setErrorCode("FODT0002"); 304 err.setXPathContext(context); 305 throw err; 306 } 307 return fromMicroseconds((long)product); 308 } 309 310 316 public DoubleValue divide(DurationValue other, XPathContext context) throws XPathException { 317 if (other instanceof SecondsDurationValue) { 318 long v1 = this.getLengthInMicroseconds(); 319 long v2 = ((SecondsDurationValue)other).getLengthInMicroseconds(); 320 long mask = (long)1; 322 while ((v1&mask) == 0 && ((v2&mask) == 0 && (v1 != 0) && (v2 != 0))) { 323 v1 = v1/2; 324 v2 = v2/2; 325 } 326 return new DoubleValue( 327 ((double)v1) / (double)v2); 328 } else { 329 throw new DynamicError("Cannot divide two durations of different type"); 330 } 331 } 332 333 336 337 public DurationValue add(DurationValue other, XPathContext context) throws XPathException { 338 if (other instanceof SecondsDurationValue) { 339 return fromMicroseconds(this.getLengthInMicroseconds() + 340 ((SecondsDurationValue)other).getLengthInMicroseconds()); 341 } else { 342 throw new DynamicError("Cannot add two durations of different type"); 343 } 344 } 345 346 349 350 public DurationValue subtract(DurationValue other, XPathContext context) throws XPathException { 351 if (other instanceof SecondsDurationValue) { 352 return fromMicroseconds(this.getLengthInMicroseconds() - 353 ((SecondsDurationValue)other).getLengthInMicroseconds()); 354 } else { 355 throw new DynamicError("Cannot add two durations of different type"); 356 } 357 } 358 359 369 370 public int compareTo(Object other) { 371 if (other instanceof SecondsDurationValue) { 372 long diff = this.getLengthInMicroseconds() - ((SecondsDurationValue)other).getLengthInMicroseconds(); 373 if (diff < 0) { 374 return -1; 375 } else if (diff > 0) { 376 return +1; 377 } else { 378 return 0; 379 } 380 } else { 381 throw new ClassCastException ("Cannot compare a dayTimeDuration to an object of class " 382 + other.getClass()); 383 } 384 } 385 386 387 391 392 public ItemType getItemType() { 393 return Type.DAY_TIME_DURATION_TYPE; 394 } 395 396 399 400 public Object convertToJava(Class target, XPathContext context) throws XPathException { 401 if (target.isAssignableFrom(DurationValue.class)) { 402 return this; 403 } else if (target==String .class || target==CharSequence .class) { 404 return getStringValue(); 405 } else if (target==Object .class) { 406 return getStringValue(); 407 } else { 408 throw new DynamicError("Conversion of dayTimeDuration to " + target.getName() + 409 " is not supported"); 410 } 411 } 412 413 } 414 415 433 | Popular Tags |