1 16 package org.apache.commons.lang.time; 17 18 import java.text.DateFormat ; 19 import java.text.DateFormatSymbols ; 20 import java.text.FieldPosition ; 21 import java.text.Format ; 22 import java.text.ParsePosition ; 23 import java.text.SimpleDateFormat ; 24 import java.util.ArrayList ; 25 import java.util.Calendar ; 26 import java.util.Date ; 27 import java.util.GregorianCalendar ; 28 import java.util.HashMap ; 29 import java.util.List ; 30 import java.util.Locale ; 31 import java.util.Map ; 32 import java.util.TimeZone ; 33 34 66 public class FastDateFormat extends Format { 67 79 82 public static final int FULL = DateFormat.FULL; 83 86 public static final int LONG = DateFormat.LONG; 87 90 public static final int MEDIUM = DateFormat.MEDIUM; 91 94 public static final int SHORT = DateFormat.SHORT; 95 96 static final double LOG_10 = Math.log(10); 98 99 private static String cDefaultPattern; 100 101 private static Map cInstanceCache = new HashMap (7); 102 private static Map cDateInstanceCache = new HashMap (7); 103 private static Map cTimeInstanceCache = new HashMap (7); 104 private static Map cDateTimeInstanceCache = new HashMap (7); 105 private static Map cTimeZoneDisplayCache = new HashMap (7); 106 107 110 private final String mPattern; 111 114 private final TimeZone mTimeZone; 115 118 private final boolean mTimeZoneForced; 119 122 private final Locale mLocale; 123 126 private final boolean mLocaleForced; 127 130 private Rule[] mRules; 131 134 private int mMaxLengthEstimate; 135 136 143 public static FastDateFormat getInstance() { 144 return getInstance(getDefaultPattern(), null, null); 145 } 146 147 156 public static FastDateFormat getInstance(String pattern) { 157 return getInstance(pattern, null, null); 158 } 159 160 171 public static FastDateFormat getInstance(String pattern, TimeZone timeZone) { 172 return getInstance(pattern, timeZone, null); 173 } 174 175 185 public static FastDateFormat getInstance(String pattern, Locale locale) { 186 return getInstance(pattern, null, locale); 187 } 188 189 202 public static synchronized FastDateFormat getInstance(String pattern, TimeZone timeZone, Locale locale) { 203 FastDateFormat emptyFormat = new FastDateFormat(pattern, timeZone, locale); 204 FastDateFormat format = (FastDateFormat) cInstanceCache.get(emptyFormat); 205 if (format == null) { 206 format = emptyFormat; 207 format.init(); cInstanceCache.put(format, format); } 210 return format; 211 } 212 213 224 public static FastDateFormat getDateInstance(int style) { 225 return getDateInstance(style, null, null); 226 } 227 228 239 public static FastDateFormat getDateInstance(int style, Locale locale) { 240 return getDateInstance(style, null, locale); 241 } 242 243 255 public static FastDateFormat getDateInstance(int style, TimeZone timeZone) { 256 return getDateInstance(style, timeZone, null); 257 } 258 270 public static synchronized FastDateFormat getDateInstance(int style, TimeZone timeZone, Locale locale) { 271 Object key = new Integer (style); 272 if (timeZone != null) { 273 key = new Pair(key, timeZone); 274 } 275 if (locale != null) { 276 key = new Pair(key, locale); 277 } 278 279 FastDateFormat format = (FastDateFormat) cDateInstanceCache.get(key); 280 if (format == null) { 281 if (locale == null) { 282 locale = Locale.getDefault(); 283 } 284 285 try { 286 SimpleDateFormat formatter = (SimpleDateFormat ) DateFormat.getDateInstance(style, locale); 287 String pattern = formatter.toPattern(); 288 format = getInstance(pattern, timeZone, locale); 289 cDateInstanceCache.put(key, format); 290 291 } catch (ClassCastException ex) { 292 throw new IllegalArgumentException ("No date pattern for locale: " + locale); 293 } 294 } 295 return format; 296 } 297 298 309 public static FastDateFormat getTimeInstance(int style) { 310 return getTimeInstance(style, null, null); 311 } 312 313 324 public static FastDateFormat getTimeInstance(int style, Locale locale) { 325 return getTimeInstance(style, null, locale); 326 } 327 328 340 public static FastDateFormat getTimeInstance(int style, TimeZone timeZone) { 341 return getTimeInstance(style, timeZone, null); 342 } 343 344 356 public static synchronized FastDateFormat getTimeInstance(int style, TimeZone timeZone, Locale locale) { 357 Object key = new Integer (style); 358 if (timeZone != null) { 359 key = new Pair(key, timeZone); 360 } 361 if (locale != null) { 362 key = new Pair(key, locale); 363 } 364 365 FastDateFormat format = (FastDateFormat) cTimeInstanceCache.get(key); 366 if (format == null) { 367 if (locale == null) { 368 locale = Locale.getDefault(); 369 } 370 371 try { 372 SimpleDateFormat formatter = (SimpleDateFormat ) DateFormat.getTimeInstance(style, locale); 373 String pattern = formatter.toPattern(); 374 format = getInstance(pattern, timeZone, locale); 375 cTimeInstanceCache.put(key, format); 376 377 } catch (ClassCastException ex) { 378 throw new IllegalArgumentException ("No date pattern for locale: " + locale); 379 } 380 } 381 return format; 382 } 383 384 396 public static FastDateFormat getDateTimeInstance( 397 int dateStyle, int timeStyle) { 398 return getDateTimeInstance(dateStyle, timeStyle, null, null); 399 } 400 401 413 public static FastDateFormat getDateTimeInstance( 414 int dateStyle, int timeStyle, Locale locale) { 415 return getDateTimeInstance(dateStyle, timeStyle, null, locale); 416 } 417 418 431 public static FastDateFormat getDateTimeInstance( 432 int dateStyle, int timeStyle, TimeZone timeZone) { 433 return getDateTimeInstance(dateStyle, timeStyle, timeZone, null); 434 } 435 448 public static synchronized FastDateFormat getDateTimeInstance(int dateStyle, int timeStyle, TimeZone timeZone, 449 Locale locale) { 450 451 Object key = new Pair(new Integer (dateStyle), new Integer (timeStyle)); 452 if (timeZone != null) { 453 key = new Pair(key, timeZone); 454 } 455 if (locale != null) { 456 key = new Pair(key, locale); 457 } 458 459 FastDateFormat format = (FastDateFormat) cDateTimeInstanceCache.get(key); 460 if (format == null) { 461 if (locale == null) { 462 locale = Locale.getDefault(); 463 } 464 465 try { 466 SimpleDateFormat formatter = (SimpleDateFormat ) DateFormat.getDateTimeInstance(dateStyle, timeStyle, 467 locale); 468 String pattern = formatter.toPattern(); 469 format = getInstance(pattern, timeZone, locale); 470 cDateTimeInstanceCache.put(key, format); 471 472 } catch (ClassCastException ex) { 473 throw new IllegalArgumentException ("No date time pattern for locale: " + locale); 474 } 475 } 476 return format; 477 } 478 479 490 static synchronized String getTimeZoneDisplay(TimeZone tz, boolean daylight, int style, Locale locale) { 491 Object key = new TimeZoneDisplayKey(tz, daylight, style, locale); 492 String value = (String ) cTimeZoneDisplayCache.get(key); 493 if (value == null) { 494 value = tz.getDisplayName(daylight, style, locale); 496 cTimeZoneDisplayCache.put(key, value); 497 } 498 return value; 499 } 500 501 506 private static synchronized String getDefaultPattern() { 507 if (cDefaultPattern == null) { 508 cDefaultPattern = new SimpleDateFormat ().toPattern(); 509 } 510 return cDefaultPattern; 511 } 512 513 528 protected FastDateFormat(String pattern, TimeZone timeZone, Locale locale) { 529 super(); 530 if (pattern == null) { 531 throw new IllegalArgumentException ("The pattern must not be null"); 532 } 533 mPattern = pattern; 534 535 mTimeZoneForced = (timeZone != null); 536 if (timeZone == null) { 537 timeZone = TimeZone.getDefault(); 538 } 539 mTimeZone = timeZone; 540 541 mLocaleForced = (locale != null); 542 if (locale == null) { 543 locale = Locale.getDefault(); 544 } 545 mLocale = locale; 546 } 547 548 551 protected void init() { 552 List rulesList = parsePattern(); 553 mRules = (Rule[]) rulesList.toArray(new Rule[rulesList.size()]); 554 555 int len = 0; 556 for (int i=mRules.length; --i >= 0; ) { 557 len += mRules[i].estimateLength(); 558 } 559 560 mMaxLengthEstimate = len; 561 } 562 563 571 protected List parsePattern() { 572 DateFormatSymbols symbols = new DateFormatSymbols (mLocale); 573 List rules = new ArrayList (); 574 575 String [] ERAs = symbols.getEras(); 576 String [] months = symbols.getMonths(); 577 String [] shortMonths = symbols.getShortMonths(); 578 String [] weekdays = symbols.getWeekdays(); 579 String [] shortWeekdays = symbols.getShortWeekdays(); 580 String [] AmPmStrings = symbols.getAmPmStrings(); 581 582 int length = mPattern.length(); 583 int[] indexRef = new int[1]; 584 585 for (int i = 0; i < length; i++) { 586 indexRef[0] = i; 587 String token = parseToken(mPattern, indexRef); 588 i = indexRef[0]; 589 590 int tokenLen = token.length(); 591 if (tokenLen == 0) { 592 break; 593 } 594 595 Rule rule; 596 char c = token.charAt(0); 597 598 switch (c) { 599 case 'G': rule = new TextField(Calendar.ERA, ERAs); 601 break; 602 case 'y': if (tokenLen >= 4) { 604 rule = selectNumberRule(Calendar.YEAR, tokenLen); 605 } else { 606 rule = TwoDigitYearField.INSTANCE; 607 } 608 break; 609 case 'M': if (tokenLen >= 4) { 611 rule = new TextField(Calendar.MONTH, months); 612 } else if (tokenLen == 3) { 613 rule = new TextField(Calendar.MONTH, shortMonths); 614 } else if (tokenLen == 2) { 615 rule = TwoDigitMonthField.INSTANCE; 616 } else { 617 rule = UnpaddedMonthField.INSTANCE; 618 } 619 break; 620 case 'd': rule = selectNumberRule(Calendar.DAY_OF_MONTH, tokenLen); 622 break; 623 case 'h': rule = new TwelveHourField(selectNumberRule(Calendar.HOUR, tokenLen)); 625 break; 626 case 'H': rule = selectNumberRule(Calendar.HOUR_OF_DAY, tokenLen); 628 break; 629 case 'm': rule = selectNumberRule(Calendar.MINUTE, tokenLen); 631 break; 632 case 's': rule = selectNumberRule(Calendar.SECOND, tokenLen); 634 break; 635 case 'S': rule = selectNumberRule(Calendar.MILLISECOND, tokenLen); 637 break; 638 case 'E': rule = new TextField(Calendar.DAY_OF_WEEK, tokenLen < 4 ? shortWeekdays : weekdays); 640 break; 641 case 'D': rule = selectNumberRule(Calendar.DAY_OF_YEAR, tokenLen); 643 break; 644 case 'F': rule = selectNumberRule(Calendar.DAY_OF_WEEK_IN_MONTH, tokenLen); 646 break; 647 case 'w': rule = selectNumberRule(Calendar.WEEK_OF_YEAR, tokenLen); 649 break; 650 case 'W': rule = selectNumberRule(Calendar.WEEK_OF_MONTH, tokenLen); 652 break; 653 case 'a': rule = new TextField(Calendar.AM_PM, AmPmStrings); 655 break; 656 case 'k': rule = new TwentyFourHourField(selectNumberRule(Calendar.HOUR_OF_DAY, tokenLen)); 658 break; 659 case 'K': rule = selectNumberRule(Calendar.HOUR, tokenLen); 661 break; 662 case 'z': if (tokenLen >= 4) { 664 rule = new TimeZoneNameRule(mTimeZone, mTimeZoneForced, mLocale, TimeZone.LONG); 665 } else { 666 rule = new TimeZoneNameRule(mTimeZone, mTimeZoneForced, mLocale, TimeZone.SHORT); 667 } 668 break; 669 case 'Z': if (tokenLen == 1) { 671 rule = TimeZoneNumberRule.INSTANCE_NO_COLON; 672 } else { 673 rule = TimeZoneNumberRule.INSTANCE_COLON; 674 } 675 break; 676 case '\'': String sub = token.substring(1); 678 if (sub.length() == 1) { 679 rule = new CharacterLiteral(sub.charAt(0)); 680 } else { 681 rule = new StringLiteral(sub); 682 } 683 break; 684 default: 685 throw new IllegalArgumentException ("Illegal pattern component: " + token); 686 } 687 688 rules.add(rule); 689 } 690 691 return rules; 692 } 693 694 701 protected String parseToken(String pattern, int[] indexRef) { 702 StringBuffer buf = new StringBuffer (); 703 704 int i = indexRef[0]; 705 int length = pattern.length(); 706 707 char c = pattern.charAt(i); 708 if (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z') { 709 buf.append(c); 712 713 while (i + 1 < length) { 714 char peek = pattern.charAt(i + 1); 715 if (peek == c) { 716 buf.append(c); 717 i++; 718 } else { 719 break; 720 } 721 } 722 } else { 723 buf.append('\''); 725 726 boolean inLiteral = false; 727 728 for (; i < length; i++) { 729 c = pattern.charAt(i); 730 731 if (c == '\'') { 732 if (i + 1 < length && pattern.charAt(i + 1) == '\'') { 733 i++; 735 buf.append(c); 736 } else { 737 inLiteral = !inLiteral; 738 } 739 } else if (!inLiteral && 740 (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z')) { 741 i--; 742 break; 743 } else { 744 buf.append(c); 745 } 746 } 747 } 748 749 indexRef[0] = i; 750 return buf.toString(); 751 } 752 753 760 protected NumberRule selectNumberRule(int field, int padding) { 761 switch (padding) { 762 case 1: 763 return new UnpaddedNumberField(field); 764 case 2: 765 return new TwoDigitNumberField(field); 766 default: 767 return new PaddedNumberField(field, padding); 768 } 769 } 770 771 782 public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) { 783 if (obj instanceof Date ) { 784 return format((Date ) obj, toAppendTo); 785 } else if (obj instanceof Calendar ) { 786 return format((Calendar ) obj, toAppendTo); 787 } else if (obj instanceof Long ) { 788 return format(((Long ) obj).longValue(), toAppendTo); 789 } else { 790 throw new IllegalArgumentException ("Unknown class: " + 791 (obj == null ? "<null>" : obj.getClass().getName())); 792 } 793 } 794 795 802 public String format(long millis) { 803 return format(new Date (millis)); 804 } 805 806 812 public String format(Date date) { 813 Calendar c = new GregorianCalendar (mTimeZone); 814 c.setTime(date); 815 return applyRules(c, new StringBuffer (mMaxLengthEstimate)).toString(); 816 } 817 818 824 public String format(Calendar calendar) { 825 return format(calendar, new StringBuffer (mMaxLengthEstimate)).toString(); 826 } 827 828 837 public StringBuffer format(long millis, StringBuffer buf) { 838 return format(new Date (millis), buf); 839 } 840 841 849 public StringBuffer format(Date date, StringBuffer buf) { 850 Calendar c = new GregorianCalendar (mTimeZone); 851 c.setTime(date); 852 return applyRules(c, buf); 853 } 854 855 863 public StringBuffer format(Calendar calendar, StringBuffer buf) { 864 if (mTimeZoneForced) { 865 calendar = (Calendar ) calendar.clone(); 866 calendar.setTimeZone(mTimeZone); 867 } 868 return applyRules(calendar, buf); 869 } 870 871 879 protected StringBuffer applyRules(Calendar calendar, StringBuffer buf) { 880 Rule[] rules = mRules; 881 int len = mRules.length; 882 for (int i = 0; i < len; i++) { 883 rules[i].appendTo(buf, calendar); 884 } 885 return buf; 886 } 887 888 897 public Object parseObject(String source, ParsePosition pos) { 898 pos.setIndex(0); 899 pos.setErrorIndex(0); 900 return null; 901 } 902 903 910 public String getPattern() { 911 return mPattern; 912 } 913 914 924 public TimeZone getTimeZone() { 925 return mTimeZone; 926 } 927 928 935 public boolean getTimeZoneOverridesCalendar() { 936 return mTimeZoneForced; 937 } 938 939 944 public Locale getLocale() { 945 return mLocale; 946 } 947 948 957 public int getMaxLengthEstimate() { 958 return mMaxLengthEstimate; 959 } 960 961 969 public boolean equals(Object obj) { 970 if (obj instanceof FastDateFormat == false) { 971 return false; 972 } 973 FastDateFormat other = (FastDateFormat) obj; 974 if ( 975 (mPattern == other.mPattern || mPattern.equals(other.mPattern)) && 976 (mTimeZone == other.mTimeZone || mTimeZone.equals(other.mTimeZone)) && 977 (mLocale == other.mLocale || mLocale.equals(other.mLocale)) && 978 (mTimeZoneForced == other.mTimeZoneForced) && 979 (mLocaleForced == other.mLocaleForced) 980 ) { 981 return true; 982 } 983 return false; 984 } 985 986 991 public int hashCode() { 992 int total = 0; 993 total += mPattern.hashCode(); 994 total += mTimeZone.hashCode(); 995 total += (mTimeZoneForced ? 1 : 0); 996 total += mLocale.hashCode(); 997 total += (mLocaleForced ? 1 : 0); 998 return total; 999 } 1000 1001 1006 public String toString() { 1007 return "FastDateFormat[" + mPattern + "]"; 1008 } 1009 1010 1015 private interface Rule { 1016 int estimateLength(); 1017 void appendTo(StringBuffer buffer, Calendar calendar); 1018 } 1019 1020 1023 private interface NumberRule extends Rule { 1024 void appendTo(StringBuffer buffer, int value); 1025 } 1026 1027 1030 private static class CharacterLiteral implements Rule { 1031 private final char mValue; 1032 1033 CharacterLiteral(char value) { 1034 mValue = value; 1035 } 1036 1037 public int estimateLength() { 1038 return 1; 1039 } 1040 1041 public void appendTo(StringBuffer buffer, Calendar calendar) { 1042 buffer.append(mValue); 1043 } 1044 } 1045 1046 1049 private static class StringLiteral implements Rule { 1050 private final String mValue; 1051 1052 StringLiteral(String value) { 1053 mValue = value; 1054 } 1055 1056 public int estimateLength() { 1057 return mValue.length(); 1058 } 1059 1060 public void appendTo(StringBuffer buffer, Calendar calendar) { 1061 buffer.append(mValue); 1062 } 1063 } 1064 1065 1068 private static class TextField implements Rule { 1069 private final int mField; 1070 private final String [] mValues; 1071 1072 TextField(int field, String [] values) { 1073 mField = field; 1074 mValues = values; 1075 } 1076 1077 public int estimateLength() { 1078 int max = 0; 1079 for (int i=mValues.length; --i >= 0; ) { 1080 int len = mValues[i].length(); 1081 if (len > max) { 1082 max = len; 1083 } 1084 } 1085 return max; 1086 } 1087 1088 public void appendTo(StringBuffer buffer, Calendar calendar) { 1089 buffer.append(mValues[calendar.get(mField)]); 1090 } 1091 } 1092 1093 1096 private static class UnpaddedNumberField implements NumberRule { 1097 static final UnpaddedNumberField INSTANCE_YEAR = new UnpaddedNumberField(Calendar.YEAR); 1098 1099 private final int mField; 1100 1101 UnpaddedNumberField(int field) { 1102 mField = field; 1103 } 1104 1105 public int estimateLength() { 1106 return 4; 1107 } 1108 1109 public void appendTo(StringBuffer buffer, Calendar calendar) { 1110 appendTo(buffer, calendar.get(mField)); 1111 } 1112 1113 public final void appendTo(StringBuffer buffer, int value) { 1114 if (value < 10) { 1115 buffer.append((char)(value + '0')); 1116 } else if (value < 100) { 1117 buffer.append((char)(value / 10 + '0')); 1118 buffer.append((char)(value % 10 + '0')); 1119 } else { 1120 buffer.append(Integer.toString(value)); 1121 } 1122 } 1123 } 1124 1125 1128 private static class UnpaddedMonthField implements NumberRule { 1129 static final UnpaddedMonthField INSTANCE = new UnpaddedMonthField(); 1130 1131 UnpaddedMonthField() { 1132 } 1133 1134 public int estimateLength() { 1135 return 2; 1136 } 1137 1138 public void appendTo(StringBuffer buffer, Calendar calendar) { 1139 appendTo(buffer, calendar.get(Calendar.MONTH) + 1); 1140 } 1141 1142 public final void appendTo(StringBuffer buffer, int value) { 1143 if (value < 10) { 1144 buffer.append((char)(value + '0')); 1145 } else { 1146 buffer.append((char)(value / 10 + '0')); 1147 buffer.append((char)(value % 10 + '0')); 1148 } 1149 } 1150 } 1151 1152 1155 private static class PaddedNumberField implements NumberRule { 1156 private final int mField; 1157 private final int mSize; 1158 1159 PaddedNumberField(int field, int size) { 1160 if (size < 3) { 1161 throw new IllegalArgumentException (); 1163 } 1164 mField = field; 1165 mSize = size; 1166 } 1167 1168 public int estimateLength() { 1169 return 4; 1170 } 1171 1172 public void appendTo(StringBuffer buffer, Calendar calendar) { 1173 appendTo(buffer, calendar.get(mField)); 1174 } 1175 1176 public final void appendTo(StringBuffer buffer, int value) { 1177 if (value < 100) { 1178 for (int i = mSize; --i >= 2; ) { 1179 buffer.append('0'); 1180 } 1181 buffer.append((char)(value / 10 + '0')); 1182 buffer.append((char)(value % 10 + '0')); 1183 } else { 1184 int digits; 1185 if (value < 1000) { 1186 digits = 3; 1187 } else { 1188 digits = (int)(Math.log(value) / LOG_10) + 1; 1189 } 1190 for (int i = mSize; --i >= digits; ) { 1191 buffer.append('0'); 1192 } 1193 buffer.append(Integer.toString(value)); 1194 } 1195 } 1196 } 1197 1198 1201 private static class TwoDigitNumberField implements NumberRule { 1202 private final int mField; 1203 1204 TwoDigitNumberField(int field) { 1205 mField = field; 1206 } 1207 1208 public int estimateLength() { 1209 return 2; 1210 } 1211 1212 public void appendTo(StringBuffer buffer, Calendar calendar) { 1213 appendTo(buffer, calendar.get(mField)); 1214 } 1215 1216 public final void appendTo(StringBuffer buffer, int value) { 1217 if (value < 100) { 1218 buffer.append((char)(value / 10 + '0')); 1219 buffer.append((char)(value % 10 + '0')); 1220 } else { 1221 buffer.append(Integer.toString(value)); 1222 } 1223 } 1224 } 1225 1226 1229 private static class TwoDigitYearField implements NumberRule { 1230 static final TwoDigitYearField INSTANCE = new TwoDigitYearField(); 1231 1232 TwoDigitYearField() { 1233 } 1234 1235 public int estimateLength() { 1236 return 2; 1237 } 1238 1239 public void appendTo(StringBuffer buffer, Calendar calendar) { 1240 appendTo(buffer, calendar.get(Calendar.YEAR) % 100); 1241 } 1242 1243 public final void appendTo(StringBuffer buffer, int value) { 1244 buffer.append((char)(value / 10 + '0')); 1245 buffer.append((char)(value % 10 + '0')); 1246 } 1247 } 1248 1249 1252 private static class TwoDigitMonthField implements NumberRule { 1253 static final TwoDigitMonthField INSTANCE = new TwoDigitMonthField(); 1254 1255 TwoDigitMonthField() { 1256 } 1257 1258 public int estimateLength() { 1259 return 2; 1260 } 1261 1262 public void appendTo(StringBuffer buffer, Calendar calendar) { 1263 appendTo(buffer, calendar.get(Calendar.MONTH) + 1); 1264 } 1265 1266 public final void appendTo(StringBuffer buffer, int value) { 1267 buffer.append((char)(value / 10 + '0')); 1268 buffer.append((char)(value % 10 + '0')); 1269 } 1270 } 1271 1272 1275 private static class TwelveHourField implements NumberRule { 1276 private final NumberRule mRule; 1277 1278 TwelveHourField(NumberRule rule) { 1279 mRule = rule; 1280 } 1281 1282 public int estimateLength() { 1283 return mRule.estimateLength(); 1284 } 1285 1286 public void appendTo(StringBuffer buffer, Calendar calendar) { 1287 int value = calendar.get(Calendar.HOUR); 1288 if (value == 0) { 1289 value = calendar.getLeastMaximum(Calendar.HOUR) + 1; 1290 } 1291 mRule.appendTo(buffer, value); 1292 } 1293 1294 public void appendTo(StringBuffer buffer, int value) { 1295 mRule.appendTo(buffer, value); 1296 } 1297 } 1298 1299 1302 private static class TwentyFourHourField implements NumberRule { 1303 private final NumberRule mRule; 1304 1305 TwentyFourHourField(NumberRule rule) { 1306 mRule = rule; 1307 } 1308 1309 public int estimateLength() { 1310 return mRule.estimateLength(); 1311 } 1312 1313 public void appendTo(StringBuffer buffer, Calendar calendar) { 1314 int value = calendar.get(Calendar.HOUR_OF_DAY); 1315 if (value == 0) { 1316 value = calendar.getMaximum(Calendar.HOUR_OF_DAY) + 1; 1317 } 1318 mRule.appendTo(buffer, value); 1319 } 1320 1321 public void appendTo(StringBuffer buffer, int value) { 1322 mRule.appendTo(buffer, value); 1323 } 1324 } 1325 1326 1329 private static class TimeZoneNameRule implements Rule { 1330 private final TimeZone mTimeZone; 1331 private final boolean mTimeZoneForced; 1332 private final Locale mLocale; 1333 private final int mStyle; 1334 private final String mStandard; 1335 private final String mDaylight; 1336 1337 TimeZoneNameRule(TimeZone timeZone, boolean timeZoneForced, Locale locale, int style) { 1338 mTimeZone = timeZone; 1339 mTimeZoneForced = timeZoneForced; 1340 mLocale = locale; 1341 mStyle = style; 1342 1343 if (timeZoneForced) { 1344 mStandard = getTimeZoneDisplay(timeZone, false, style, locale); 1345 mDaylight = getTimeZoneDisplay(timeZone, true, style, locale); 1346 } else { 1347 mStandard = null; 1348 mDaylight = null; 1349 } 1350 } 1351 1352 public int estimateLength() { 1353 if (mTimeZoneForced) { 1354 return Math.max(mStandard.length(), mDaylight.length()); 1355 } else if (mStyle == TimeZone.SHORT) { 1356 return 4; 1357 } else { 1358 return 40; 1359 } 1360 } 1361 1362 public void appendTo(StringBuffer buffer, Calendar calendar) { 1363 if (mTimeZoneForced) { 1364 if (mTimeZone.useDaylightTime() && calendar.get(Calendar.DST_OFFSET) != 0) { 1365 buffer.append(mDaylight); 1366 } else { 1367 buffer.append(mStandard); 1368 } 1369 } else { 1370 TimeZone timeZone = calendar.getTimeZone(); 1371 if (timeZone.useDaylightTime() && calendar.get(Calendar.DST_OFFSET) != 0) { 1372 buffer.append(getTimeZoneDisplay(timeZone, true, mStyle, mLocale)); 1373 } else { 1374 buffer.append(getTimeZoneDisplay(timeZone, false, mStyle, mLocale)); 1375 } 1376 } 1377 } 1378 } 1379 1380 1384 private static class TimeZoneNumberRule implements Rule { 1385 static final TimeZoneNumberRule INSTANCE_COLON = new TimeZoneNumberRule(true); 1386 static final TimeZoneNumberRule INSTANCE_NO_COLON = new TimeZoneNumberRule(false); 1387 1388 final boolean mColon; 1389 1390 TimeZoneNumberRule(boolean colon) { 1391 mColon = colon; 1392 } 1393 1394 public int estimateLength() { 1395 return 5; 1396 } 1397 1398 public void appendTo(StringBuffer buffer, Calendar calendar) { 1399 int offset = calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET); 1400 1401 if (offset < 0) { 1402 buffer.append('-'); 1403 offset = -offset; 1404 } else { 1405 buffer.append('+'); 1406 } 1407 1408 int hours = offset / (60 * 60 * 1000); 1409 buffer.append((char)(hours / 10 + '0')); 1410 buffer.append((char)(hours % 10 + '0')); 1411 1412 if (mColon) { 1413 buffer.append(':'); 1414 } 1415 1416 int minutes = offset / (60 * 1000) - 60 * hours; 1417 buffer.append((char)(minutes / 10 + '0')); 1418 buffer.append((char)(minutes % 10 + '0')); 1419 } 1420 } 1421 1422 1426 private static class TimeZoneDisplayKey { 1427 private final TimeZone mTimeZone; 1428 private final int mStyle; 1429 private final Locale mLocale; 1430 1431 TimeZoneDisplayKey(TimeZone timeZone, 1432 boolean daylight, int style, Locale locale) { 1433 mTimeZone = timeZone; 1434 if (daylight) { 1435 style |= 0x80000000; 1436 } 1437 mStyle = style; 1438 mLocale = locale; 1439 } 1440 1441 public int hashCode() { 1442 return mStyle * 31 + mLocale.hashCode(); 1443 } 1444 1445 public boolean equals(Object obj) { 1446 if (this == obj) { 1447 return true; 1448 } 1449 if (obj instanceof TimeZoneDisplayKey) { 1450 TimeZoneDisplayKey other = (TimeZoneDisplayKey)obj; 1451 return 1452 mTimeZone.equals(other.mTimeZone) && 1453 mStyle == other.mStyle && 1454 mLocale.equals(other.mLocale); 1455 } 1456 return false; 1457 } 1458 } 1459 1460 1467 private static class Pair { 1468 private final Object mObj1; 1469 private final Object mObj2; 1470 1471 public Pair(Object obj1, Object obj2) { 1472 mObj1 = obj1; 1473 mObj2 = obj2; 1474 } 1475 1476 public boolean equals(Object obj) { 1477 if (this == obj) { 1478 return true; 1479 } 1480 1481 if (!(obj instanceof Pair)) { 1482 return false; 1483 } 1484 1485 Pair key = (Pair)obj; 1486 1487 return 1488 (mObj1 == null ? 1489 key.mObj1 == null : mObj1.equals(key.mObj1)) && 1490 (mObj2 == null ? 1491 key.mObj2 == null : mObj2.equals(key.mObj2)); 1492 } 1493 1494 public int hashCode() { 1495 return 1496 (mObj1 == null ? 0 : mObj1.hashCode()) + 1497 (mObj2 == null ? 0 : mObj2.hashCode()); 1498 } 1499 1500 public String toString() { 1501 return "[" + mObj1 + ':' + mObj2 + ']'; 1502 } 1503 } 1504 1505} 1506 | Popular Tags |