1 16 package org.apache.commons.lang.time; 17 18 import org.apache.commons.lang.StringUtils; 19 20 import java.util.Calendar ; 21 import java.util.Date ; 22 import java.util.TimeZone ; 23 24 47 public class DurationFormatUtils { 48 49 55 public DurationFormatUtils() { 56 super(); 57 } 58 59 66 public static final String ISO_EXTENDED_FORMAT_PATTERN = "'P'yyyy'Y'M'M'd'DT'H'H'm'M's.S'S'"; 67 68 78 public static String formatDurationHMS(long durationMillis) { 79 return formatDuration(durationMillis, "H:mm:ss.SSS"); 80 } 81 82 93 public static String formatDurationISO(long durationMillis) { 94 return formatDuration(durationMillis, ISO_EXTENDED_FORMAT_PATTERN, false); 95 } 96 97 108 public static String formatDuration(long durationMillis, String format) { 109 return formatDuration(durationMillis, format, true); 110 } 111 112 125 public static String formatDuration(long durationMillis, String format, boolean padWithZeros) { 126 127 Token[] tokens = lexx(format); 128 129 int days = 0; 130 int hours = 0; 131 int minutes = 0; 132 int seconds = 0; 133 int milliseconds = 0; 134 135 if (Token.containsTokenWithValue(tokens, d) ) { 136 days = (int) (durationMillis / DateUtils.MILLIS_PER_DAY); 137 durationMillis = durationMillis - (days * DateUtils.MILLIS_PER_DAY); 138 } 139 if (Token.containsTokenWithValue(tokens, H) ) { 140 hours = (int) (durationMillis / DateUtils.MILLIS_PER_HOUR); 141 durationMillis = durationMillis - (hours * DateUtils.MILLIS_PER_HOUR); 142 } 143 if (Token.containsTokenWithValue(tokens, m) ) { 144 minutes = (int) (durationMillis / DateUtils.MILLIS_PER_MINUTE); 145 durationMillis = durationMillis - (minutes * DateUtils.MILLIS_PER_MINUTE); 146 } 147 if (Token.containsTokenWithValue(tokens, s) ) { 148 seconds = (int) (durationMillis / DateUtils.MILLIS_PER_SECOND); 149 durationMillis = durationMillis - (seconds * DateUtils.MILLIS_PER_SECOND); 150 } 151 if (Token.containsTokenWithValue(tokens, S) ) { 152 milliseconds = (int) durationMillis; 153 } 154 155 return format(tokens, 0, 0, days, hours, minutes, seconds, milliseconds, padWithZeros); 156 } 157 158 169 public static String formatDurationWords( 170 long durationMillis, 171 boolean suppressLeadingZeroElements, 172 boolean suppressTrailingZeroElements) { 173 174 String duration = formatDuration(durationMillis, "d' days 'H' hours 'm' minutes 's' seconds'"); 178 if (suppressLeadingZeroElements) { 179 duration = " " + duration; 181 String tmp = StringUtils.replaceOnce(duration, " 0 days", ""); 182 if (tmp.length() != duration.length()) { 183 duration = tmp; 184 tmp = StringUtils.replaceOnce(duration, " 0 hours", ""); 185 if (tmp.length() != duration.length()) { 186 duration = tmp; 187 tmp = StringUtils.replaceOnce(duration, " 0 minutes", ""); 188 duration = tmp; 189 if (tmp.length() != duration.length()) { 190 duration = StringUtils.replaceOnce(tmp, " 0 seconds", ""); 191 } 192 } 193 } 194 if (duration.length() != 0) { 195 duration = duration.substring(1); 197 } 198 } 199 if (suppressTrailingZeroElements) { 200 String tmp = StringUtils.replaceOnce(duration, " 0 seconds", ""); 201 if (tmp.length() != duration.length()) { 202 duration = tmp; 203 tmp = StringUtils.replaceOnce(duration, " 0 minutes", ""); 204 if (tmp.length() != duration.length()) { 205 duration = tmp; 206 tmp = StringUtils.replaceOnce(duration, " 0 hours", ""); 207 if (tmp.length() != duration.length()) { 208 duration = StringUtils.replaceOnce(tmp, " 0 days", ""); 209 } 210 } 211 } 212 } 213 duration = StringUtils.replaceOnce(duration, "1 seconds", "1 second"); 215 duration = StringUtils.replaceOnce(duration, "1 minutes", "1 minute"); 216 duration = StringUtils.replaceOnce(duration, "1 hours", "1 hour"); 217 duration = StringUtils.replaceOnce(duration, "1 days", "1 day"); 218 return duration; 219 } 220 221 231 public static String formatPeriodISO(long startMillis, long endMillis) { 232 return formatPeriod(startMillis, endMillis, ISO_EXTENDED_FORMAT_PATTERN, false, TimeZone.getDefault()); 233 } 234 235 244 public static String formatPeriod(long startMillis, long endMillis, String format) { 245 return formatPeriod(startMillis, endMillis, format, true, TimeZone.getDefault()); 246 } 247 248 260 public static String formatPeriod(long startMillis, long endMillis, String format, boolean padWithZeros, 261 TimeZone timezone) { 262 263 long millis = endMillis - startMillis; 264 if (millis < 28 * DateUtils.MILLIS_PER_DAY) { 265 return formatDuration(millis, format, padWithZeros); 266 } 267 268 Token[] tokens = lexx(format); 269 270 Calendar start = Calendar.getInstance(timezone); 273 start.setTime(new Date (startMillis)); 274 Calendar end = Calendar.getInstance(timezone); 275 end.setTime(new Date (endMillis)); 276 277 int years = end.get(Calendar.YEAR) - start.get(Calendar.YEAR); 279 int months = end.get(Calendar.MONTH) - start.get(Calendar.MONTH); 280 while (months < 0) { 282 months += 12; 283 years -= 1; 284 } 285 int days = end.get(Calendar.DAY_OF_MONTH) - start.get(Calendar.DAY_OF_MONTH); 286 while (days < 0) { 287 days += 31; months -= 1; 289 } 290 int hours = end.get(Calendar.HOUR_OF_DAY) - start.get(Calendar.HOUR_OF_DAY); 291 while (hours < 0) { 292 hours += 24; 293 days -= 1; 294 } 295 int minutes = end.get(Calendar.MINUTE) - start.get(Calendar.MINUTE); 296 while (minutes < 0) { 297 minutes += 60; 298 hours -= 1; 299 } 300 int seconds = end.get(Calendar.SECOND) - start.get(Calendar.SECOND); 301 while (seconds < 0) { 302 seconds += 60; 303 minutes -= 1; 304 } 305 int milliseconds = end.get(Calendar.MILLISECOND) - start.get(Calendar.MILLISECOND); 306 while (milliseconds < 0) { 307 milliseconds += 1000; 308 seconds -= 1; 309 } 310 311 milliseconds -= reduceAndCorrect(start, end, Calendar.MILLISECOND, milliseconds); 313 seconds -= reduceAndCorrect(start, end, Calendar.SECOND, seconds); 314 minutes -= reduceAndCorrect(start, end, Calendar.MINUTE, minutes); 315 hours -= reduceAndCorrect(start, end, Calendar.HOUR_OF_DAY, hours); 316 days -= reduceAndCorrect(start, end, Calendar.DAY_OF_MONTH, days); 317 months -= reduceAndCorrect(start, end, Calendar.MONTH, months); 318 years -= reduceAndCorrect(start, end, Calendar.YEAR, years); 319 320 if (!Token.containsTokenWithValue(tokens, y)) { 324 if (Token.containsTokenWithValue(tokens, M)) { 325 months += 12 * years; 326 years = 0; 327 } else { 328 days += 365 * years; 330 years = 0; 331 } 332 } 333 if (!Token.containsTokenWithValue(tokens, M)) { 334 days += end.get(Calendar.DAY_OF_YEAR) - start.get(Calendar.DAY_OF_YEAR); 335 months = 0; 336 } 337 if (!Token.containsTokenWithValue(tokens, d)) { 338 hours += 24 * days; 339 days = 0; 340 } 341 if (!Token.containsTokenWithValue(tokens, H)) { 342 minutes += 60 * hours; 343 hours = 0; 344 } 345 if (!Token.containsTokenWithValue(tokens, m)) { 346 seconds += 60 * minutes; 347 minutes = 0; 348 } 349 if (!Token.containsTokenWithValue(tokens, s)) { 350 milliseconds += 1000 * seconds; 351 seconds = 0; 352 } 353 354 return format(tokens, years, months, days, hours, minutes, seconds, milliseconds, padWithZeros); 355 } 356 357 372 static String format(Token[] tokens, int years, int months, int days, int hours, int minutes, int seconds, 373 int milliseconds, boolean padWithZeros) { 374 StringBuffer buffer = new StringBuffer (); 375 boolean lastOutputSeconds = false; 376 int sz = tokens.length; 377 for (int i = 0; i < sz; i++) { 378 Token token = tokens[i]; 379 Object value = token.getValue(); 380 int count = token.getCount(); 381 if (value instanceof StringBuffer ) { 382 buffer.append(value.toString()); 383 } else { 384 if (value == y) { 385 buffer.append(padWithZeros ? StringUtils.leftPad(Integer.toString(years), count, '0') : Integer 386 .toString(years)); 387 lastOutputSeconds = false; 388 } else if (value == M) { 389 buffer.append(padWithZeros ? StringUtils.leftPad(Integer.toString(months), count, '0') : Integer 390 .toString(months)); 391 lastOutputSeconds = false; 392 } else if (value == d) { 393 buffer.append(padWithZeros ? StringUtils.leftPad(Integer.toString(days), count, '0') : Integer 394 .toString(days)); 395 lastOutputSeconds = false; 396 } else if (value == H) { 397 buffer.append(padWithZeros ? StringUtils.leftPad(Integer.toString(hours), count, '0') : Integer 398 .toString(hours)); 399 lastOutputSeconds = false; 400 } else if (value == m) { 401 buffer.append(padWithZeros ? StringUtils.leftPad(Integer.toString(minutes), count, '0') : Integer 402 .toString(minutes)); 403 lastOutputSeconds = false; 404 } else if (value == s) { 405 buffer.append(padWithZeros ? StringUtils.leftPad(Integer.toString(seconds), count, '0') : Integer 406 .toString(seconds)); 407 lastOutputSeconds = true; 408 } else if (value == S) { 409 if (lastOutputSeconds) { 410 milliseconds += 1000; 411 String str = padWithZeros 412 ? StringUtils.leftPad(Integer.toString(milliseconds), count, '0') 413 : Integer.toString(milliseconds); 414 buffer.append(str.substring(1)); 415 } else { 416 buffer.append(padWithZeros 417 ? StringUtils.leftPad(Integer.toString(milliseconds), count, '0') 418 : Integer.toString(milliseconds)); 419 } 420 lastOutputSeconds = false; 421 } 422 } 423 } 424 return buffer.toString(); 425 } 426 427 437 static int reduceAndCorrect(Calendar start, Calendar end, int field, int difference) { 438 end.add( field, -1 * difference ); 439 int endValue = end.get(field); 440 int startValue = start.get(field); 441 if (endValue < startValue) { 442 int newdiff = startValue - endValue; 443 end.add( field, newdiff ); 444 return newdiff; 445 } else { 446 return 0; 447 } 448 } 449 450 static final Object y = "y"; 451 static final Object M = "M"; 452 static final Object d = "d"; 453 static final Object H = "H"; 454 static final Object m = "m"; 455 static final Object s = "s"; 456 static final Object S = "S"; 457 458 464 static Token[] lexx(String format) { 465 char[] array = format.toCharArray(); 466 java.util.ArrayList list = new java.util.ArrayList (array.length); 467 468 boolean inLiteral = false; 469 StringBuffer buffer = null; 470 Token previous = null; 471 int sz = array.length; 472 for(int i=0; i<sz; i++) { 473 char ch = array[i]; 474 if(inLiteral && ch != '\'') { 475 buffer.append(ch); 476 continue; 477 } 478 Object value = null; 479 switch(ch) { 480 case '\'' : 482 if(inLiteral) { 483 buffer = null; 484 inLiteral = false; 485 } else { 486 buffer = new StringBuffer (); 487 list.add(new Token(buffer)); 488 inLiteral = true; 489 } 490 break; 491 case 'y' : value = y; break; 492 case 'M' : value = M; break; 493 case 'd' : value = d; break; 494 case 'H' : value = H; break; 495 case 'm' : value = m; break; 496 case 's' : value = s; break; 497 case 'S' : value = S; break; 498 default : 499 if(buffer == null) { 500 buffer = new StringBuffer (); 501 list.add(new Token(buffer)); 502 } 503 buffer.append(ch); 504 } 505 506 if(value != null) { 507 if(previous != null && previous.getValue() == value) { 508 previous.increment(); 509 } else { 510 Token token = new Token(value); 511 list.add(token); 512 previous = token; 513 } 514 buffer = null; 515 } 516 } 517 return (Token[]) list.toArray( new Token[0] ); 518 } 519 520 523 static class Token { 524 525 532 static boolean containsTokenWithValue(Token[] tokens, Object value) { 533 int sz = tokens.length; 534 for (int i = 0; i < sz; i++) { 535 if (tokens[i].getValue() == value) { 536 return true; 537 } 538 } 539 return false; 540 } 541 542 private Object value; 543 private int count; 544 545 550 Token(Object value) { 551 this.value = value; 552 this.count = 1; 553 } 554 555 562 Token(Object value, int count) { 563 this.value = value; 564 this.count = count; 565 } 566 567 570 void increment() { 571 count++; 572 } 573 574 579 int getCount() { 580 return count; 581 } 582 583 588 Object getValue() { 589 return value; 590 } 591 592 598 public boolean equals(Object obj2) { 599 if (obj2 instanceof Token) { 600 Token tok2 = (Token) obj2; 601 if (this.value.getClass() != tok2.value.getClass()) { 602 return false; 603 } 604 if (this.count != tok2.count) { 605 return false; 606 } 607 if (this.value instanceof StringBuffer ) { 608 return this.value.toString().equals(tok2.value.toString()); 609 } else if (this.value instanceof Number ) { 610 return this.value.equals(tok2.value); 611 } else { 612 return this.value == tok2.value; 613 } 614 } else { 615 return false; 616 } 617 } 618 619 624 public String toString() { 625 return StringUtils.repeat(this.value.toString(), this.count); 626 } 627 } 628 629 } 630 | Popular Tags |