2 *******************************************************************************
3 * Copyright (C) 2007-2011, International Business Machines
4 * Corporation and others. All Rights Reserved.
5 *******************************************************************************
7 package com.ibm.icu.impl;
9 import java.io.IOException;
10 import java.io.ObjectInputStream;
11 import java.math.BigInteger;
12 import java.text.FieldPosition;
13 import java.text.ParsePosition;
14 import java.util.Arrays;
15 import java.util.MissingResourceException;
17 import com.ibm.icu.lang.UCharacter;
18 import com.ibm.icu.math.BigDecimal;
19 import com.ibm.icu.text.NumberFormat;
20 import com.ibm.icu.util.ULocale;
21 import com.ibm.icu.util.UResourceBundle;
24 * NumberFormat implementation dedicated/optimized for DateFormat,
25 * used by SimpleDateFormat implementation.
27 public final class DateNumberFormat extends NumberFormat {
29 private static final long serialVersionUID = -6315692826916346953L;
31 private char[] digits;
32 private char zeroDigit; // For backwards compatibility
33 private char minusSign;
34 private boolean positiveOnly = false;
36 private transient char[] decimalBuf = new char[20]; // 20 digits is good enough to store Long.MAX_VALUE
38 private static SimpleCache<ULocale, char[]> CACHE = new SimpleCache<ULocale, char[]>();
40 private int maxIntDigits;
41 private int minIntDigits;
43 public DateNumberFormat(ULocale loc, String digitString, String nsName) {
44 initialize(loc,digitString,nsName);
47 public DateNumberFormat(ULocale loc, char zeroDigit, String nsName) {
48 StringBuffer buf = new StringBuffer();
49 for ( int i = 0 ; i < 10 ; i++ ) {
50 buf.append((char)(zeroDigit+i));
52 initialize(loc,buf.toString(),nsName);
55 private void initialize(ULocale loc,String digitString,String nsName) {
56 char[] elems = CACHE.get(loc);
60 ICUResourceBundle rb = (ICUResourceBundle)UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, loc);
62 minusString = rb.getStringWithFallback("NumberElements/"+nsName+"/symbols/minusSign");
63 } catch (MissingResourceException ex) {
64 if ( !nsName.equals("latn") ) {
66 minusString = rb.getStringWithFallback("NumberElements/latn/symbols/minusSign");
67 } catch (MissingResourceException ex1) {
75 for ( int i = 0 ; i < 10 ; i++ ) {
76 elems[i] = digitString.charAt(i);
78 elems[10] = minusString.charAt(0);
79 CACHE.put(loc, elems);
82 digits = new char[10];
83 System.arraycopy(elems, 0, digits, 0, 10);
84 zeroDigit = digits[0];
86 minusSign = elems[10];
89 public void setMaximumIntegerDigits(int newValue) {
90 maxIntDigits = newValue;
93 public int getMaximumIntegerDigits() {
97 public void setMinimumIntegerDigits(int newValue) {
98 minIntDigits = newValue;
101 public int getMinimumIntegerDigits() {
105 /* For supporting SimpleDateFormat.parseInt */
106 public void setParsePositiveOnly(boolean isPositiveOnly) {
107 positiveOnly = isPositiveOnly;
110 public char getZeroDigit() {
114 public void setZeroDigit(char zero) {
116 if (digits == null) {
117 digits = new char[10];
120 for ( int i = 1 ; i < 10 ; i++ ) {
121 digits[i] = (char)(zero+i);
125 public char[] getDigits() {
129 public StringBuffer format(double number, StringBuffer toAppendTo,
131 throw new UnsupportedOperationException("StringBuffer format(double, StringBuffer, FieldPostion) is not implemented");
134 public StringBuffer format(long numberL, StringBuffer toAppendTo,
139 toAppendTo.append(minusSign);
143 // Note: NumberFormat used by DateFormat only uses int numbers.
144 // Remainder operation on 32bit platform using long is significantly slower
145 // than int. So, this method casts long number into int.
146 int number = (int)numberL;
148 int limit = decimalBuf.length < maxIntDigits ? decimalBuf.length : maxIntDigits;
149 int index = limit - 1;
151 decimalBuf[index] = digits[(number % 10)];
153 if (index == 0 || number == 0) {
158 int padding = minIntDigits - (limit - index);
159 for (; padding > 0; padding--) {
160 decimalBuf[--index] = digits[0];
162 int length = limit - index;
163 toAppendTo.append(decimalBuf, index, length);
164 pos.setBeginIndex(0);
165 if (pos.getField() == NumberFormat.INTEGER_FIELD) {
166 pos.setEndIndex(length);
173 public StringBuffer format(BigInteger number, StringBuffer toAppendTo,
175 throw new UnsupportedOperationException("StringBuffer format(BigInteger, StringBuffer, FieldPostion) is not implemented");
178 public StringBuffer format(java.math.BigDecimal number, StringBuffer toAppendTo,
180 throw new UnsupportedOperationException("StringBuffer format(BigDecimal, StringBuffer, FieldPostion) is not implemented");
183 public StringBuffer format(BigDecimal number,
184 StringBuffer toAppendTo, FieldPosition pos) {
185 throw new UnsupportedOperationException("StringBuffer format(BigDecimal, StringBuffer, FieldPostion) is not implemented");
189 * Note: This method only parse integer numbers which can be represented by long
191 private static final long PARSE_THRESHOLD = 922337203685477579L; // (Long.MAX_VALUE / 10) - 1
193 public Number parse(String text, ParsePosition parsePosition) {
195 boolean sawNumber = false;
196 boolean negative = false;
197 int base = parsePosition.getIndex();
199 for (; base + offset < text.length(); offset++) {
200 char ch = text.charAt(base + offset);
201 if (offset == 0 && ch == minusSign) {
207 int digit = ch - digits[0];
208 if (digit < 0 || 9 < digit) {
209 digit = UCharacter.digit(ch);
211 if (digit < 0 || 9 < digit) {
212 for ( digit = 0 ; digit < 10 ; digit++ ) {
213 if ( ch == digits[digit]) {
218 if (0 <= digit && digit <= 9 && num < PARSE_THRESHOLD) {
220 num = num * 10 + digit;
226 Number result = null;
228 num = negative ? num * (-1) : num;
229 result = new Long(num);
230 parsePosition.setIndex(base + offset);
235 public boolean equals(Object obj) {
236 if (obj == null || !super.equals(obj) || !(obj instanceof DateNumberFormat)) {
239 DateNumberFormat other = (DateNumberFormat)obj;
240 return (this.maxIntDigits == other.maxIntDigits
241 && this.minIntDigits == other.minIntDigits
242 && this.minusSign == other.minusSign
243 && this.positiveOnly == other.positiveOnly
244 && Arrays.equals(this.digits, other.digits));
247 private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
248 stream.defaultReadObject();
249 if (digits == null) {
250 setZeroDigit(zeroDigit);
252 // re-allocate the work buffer
253 decimalBuf = new char[20];