2 *******************************************************************************
3 * Copyright (C) 2009-2013, International Business Machines Corporation and *
4 * others. All Rights Reserved. *
5 *******************************************************************************
7 package com.ibm.icu.text;
9 import java.lang.reflect.Field;
10 import java.util.Collections;
11 import java.util.Date;
12 import java.util.List;
14 import com.ibm.icu.util.Calendar;
15 import com.ibm.icu.util.GregorianCalendar;
16 import com.ibm.icu.util.TimeZone;
19 * Provides information about currencies that is not specific to a locale.
21 * A note about currency dates. The CLDR data provides data to the day,
22 * inclusive. The date information used by CurrencyInfo and CurrencyFilter
23 * is represented by milliseconds, which is overly precise. These times are
24 * in GMT, so queries involving dates should use GMT times, but more generally
25 * you should avoid relying on time of day in queries.
27 * This class is not intended for public subclassing.
31 public class CurrencyMetaInfo {
32 private static final CurrencyMetaInfo impl;
33 private static final boolean hasData;
36 * Returns the unique instance of the currency meta info.
37 * @return the meta info
40 public static CurrencyMetaInfo getInstance() {
45 * Returns the unique instance of the currency meta info, or null if
46 * noSubstitute is true and there is no data to support this API.
47 * @param noSubstitute true if no substitute data should be used
48 * @return the meta info, or null
51 public static CurrencyMetaInfo getInstance(boolean noSubstitute) {
52 return hasData ? impl : null;
56 * Returns true if there is data for the currency meta info.
57 * @return true if there is actual data
59 * @deprecated This API is ICU internal only.
61 public static boolean hasData() {
66 * Subclass constructor.
68 * @deprecated This API is ICU internal only.
70 protected CurrencyMetaInfo() {
74 * A filter used to select which currency info is returned.
77 public static final class CurrencyFilter {
79 * The region to filter on. If null, accepts any region.
82 public final String region;
85 * The currency to filter on. If null, accepts any currency.
88 public final String currency;
91 * The from date to filter on (as milliseconds). Accepts any currency on or after this date.
94 public final long from;
97 * The to date to filter on (as milliseconds). Accepts any currency on or before this date.
100 public final long to;
103 * true if we are filtering only for currencies used as legal tender.
105 * @deprecated This API is ICU internal only.
107 public final boolean tenderOnly;
109 private CurrencyFilter(String region, String currency, long from, long to, boolean tenderOnly) {
110 this.region = region;
111 this.currency = currency;
114 this.tenderOnly = tenderOnly;
118 private static final CurrencyFilter ALL = new CurrencyFilter(
119 null, null, Long.MIN_VALUE, Long.MAX_VALUE, false);
122 * Returns a filter that accepts all currency data.
126 public static CurrencyFilter all() {
131 * Returns a filter that accepts all currencies in use as of the current date.
133 * @see #withDate(Date)
136 public static CurrencyFilter now() {
137 return ALL.withDate(new Date());
141 * Returns a filter that accepts all currencies ever used in the given region.
142 * @param region the region code
144 * @see #withRegion(String)
147 public static CurrencyFilter onRegion(String region) {
148 return ALL.withRegion(region);
152 * Returns a filter that accepts the given currency.
153 * @param currency the currency code
155 * @see #withCurrency(String)
158 public static CurrencyFilter onCurrency(String currency) {
159 return ALL.withCurrency(currency);
163 * Returns a filter that accepts all currencies in use on the given date.
164 * @param date the date
166 * @see #withDate(Date)
169 public static CurrencyFilter onDate(Date date) {
170 return ALL.withDate(date);
174 * Returns a filter that accepts all currencies that were in use at some point between
175 * the given dates, or if dates are equal, currencies in use on that date.
176 * @param from date on or after a currency must have been in use
177 * @param to date on or before which a currency must have been in use,
178 * or if equal to from, the date on which a currency must have been in use
180 * @see #withDateRange(Date, Date)
183 public static CurrencyFilter onDateRange(Date from, Date to) {
184 return ALL.withDateRange(from, to);
188 * Returns a filter that accepts all currencies in use on the given date.
189 * @param date the date as milliseconds after Jan 1, 1970
191 * @provisional This API might change or be removed in a future release.
193 public static CurrencyFilter onDate(long date) {
194 return ALL.withDate(date);
198 * Returns a filter that accepts all currencies that were in use at some
199 * point between the given dates, or if dates are equal, currencies in
201 * @param from The date on or after a currency must have been in use.
202 * Measured in milliseconds since Jan 1, 1970 GMT.
203 * @param to The date on or before which a currency must have been in use.
204 * Measured in milliseconds since Jan 1, 1970 GMT.
206 * @provisional This API might change or be removed in a future release.
208 public static CurrencyFilter onDateRange(long from, long to) {
209 return ALL.withDateRange(from, to);
213 * Returns a CurrencyFilter for finding currencies that were either once used,
214 * are used, or will be used as tender.
216 * @provisional This API might change or be removed in a future release.
218 public static CurrencyFilter onTender() {
219 return ALL.withTender();
223 * Returns a copy of this filter, with the specified region. Region can be null to
224 * indicate no filter on region.
225 * @param region the region code
227 * @see #onRegion(String)
230 public CurrencyFilter withRegion(String region) {
231 return new CurrencyFilter(region, this.currency, this.from, this.to, this.tenderOnly);
235 * Returns a copy of this filter, with the specified currency. Currency can be null to
236 * indicate no filter on currency.
237 * @param currency the currency code
239 * @see #onCurrency(String)
242 public CurrencyFilter withCurrency(String currency) {
243 return new CurrencyFilter(this.region, currency, this.from, this.to, this.tenderOnly);
247 * Returns a copy of this filter, with from and to set to the given date.
248 * @param date the date on which the currency must have been in use
253 public CurrencyFilter withDate(Date date) {
254 return new CurrencyFilter(this.region, this.currency, date.getTime(), date.getTime(), this.tenderOnly);
258 * Returns a copy of this filter, with from and to set to the given dates.
259 * @param from date on or after which the currency must have been in use
260 * @param to date on or before which the currency must have been in use
262 * @see #onDateRange(Date, Date)
265 public CurrencyFilter withDateRange(Date from, Date to) {
266 long fromLong = from == null ? Long.MIN_VALUE : from.getTime();
267 long toLong = to == null ? Long.MAX_VALUE : to.getTime();
268 return new CurrencyFilter(this.region, this.currency, fromLong, toLong, this.tenderOnly);
272 * Returns a copy of this filter that accepts all currencies in use on
274 * @param date the date as milliseconds after Jan 1, 1970
276 * @provisional This API might change or be removed in a future release.
278 public CurrencyFilter withDate(long date) {
279 return new CurrencyFilter(this.region, this.currency, date, date, this.tenderOnly);
283 * Returns a copy of this filter that accepts all currencies that were
284 * in use at some point between the given dates, or if dates are equal,
285 * currencies in use on that date.
286 * @param from The date on or after a currency must have been in use.
287 * Measured in milliseconds since Jan 1, 1970 GMT.
288 * @param to The date on or before which a currency must have been in use.
289 * Measured in milliseconds since Jan 1, 1970 GMT.
291 * @provisional This API might change or be removed in a future release.
293 public CurrencyFilter withDateRange(long from, long to) {
294 return new CurrencyFilter(this.region, this.currency, from, to, this.tenderOnly);
298 * Returns a copy of this filter that filters for currencies that were
299 * either once used, are used, or will be used as tender.
301 * @provisional This API might change or be removed in a future release.
303 public CurrencyFilter withTender() {
304 return new CurrencyFilter(this.region, this.currency, this.from, this.to, true);
312 public boolean equals(Object rhs) {
313 return rhs instanceof CurrencyFilter &&
314 equals((CurrencyFilter) rhs);
318 * Type-safe override of {@link #equals(Object)}.
319 * @param rhs the currency filter to compare to
320 * @return true if the filters are equal
323 public boolean equals(CurrencyFilter rhs) {
324 return this == rhs || (rhs != null &&
325 equals(this.region, rhs.region) &&
326 equals(this.currency, rhs.currency) &&
327 this.from == rhs.from &&
329 this.tenderOnly == rhs.tenderOnly);
337 public int hashCode() {
339 if (region != null) {
340 hc = region.hashCode();
342 if (currency != null) {
343 hc = hc * 31 + currency.hashCode();
345 hc = hc * 31 + (int) from;
346 hc = hc * 31 + (int) (from >>> 32);
347 hc = hc * 31 + (int) to;
348 hc = hc * 31 + (int) (to >>> 32);
349 hc = hc * 31 + (tenderOnly ? 1 : 0);
354 * Returns a string representing the filter, for debugging.
355 * @return A string representing the filter.
359 public String toString() {
360 return debugString(this);
363 private static boolean equals(String lhs, String rhs) {
364 return lhs == rhs || (lhs != null && lhs.equals(rhs));
369 * Represents the raw information about fraction digits and rounding increment.
372 public static final class CurrencyDigits {
374 * Number of fraction digits used to display this currency.
377 public final int fractionDigits;
379 * Rounding increment used when displaying this currency.
382 public final int roundingIncrement;
385 * Constructor for CurrencyDigits.
386 * @param fractionDigits the fraction digits
387 * @param roundingIncrement the rounding increment
390 public CurrencyDigits(int fractionDigits, int roundingIncrement) {
391 this.fractionDigits = fractionDigits;
392 this.roundingIncrement = roundingIncrement;
396 * Returns a string representing the currency digits, for debugging.
397 * @return A string representing the currency digits.
401 public String toString() {
402 return debugString(this);
407 * Represents a complete currency info record listing the region, currency, from and to dates,
409 * Use {@link CurrencyMetaInfo#currencyInfo(CurrencyFilter)}
410 * for a list of info objects matching the filter.
413 public static final class CurrencyInfo {
415 * Region code where currency is used.
418 public final String region;
421 * The three-letter ISO currency code.
424 public final String code;
427 * Date on which the currency was first officially used in the region.
428 * This is midnight at the start of the first day on which the currency was used, GMT.
429 * If there is no date, this is Long.MIN_VALUE;
432 public final long from;
435 * Date at which the currency stopped being officially used in the region.
436 * This is one millisecond before midnight at the end of the last day on which the currency was used, GMT.
437 * If there is no date, this is Long.MAX_VALUE.
441 public final long to;
444 * Preference order of currencies being used at the same time in the region. Lower
445 * values are preferred (generally, this is a transition from an older to a newer
446 * currency). Priorities within a single country are unique.
449 public final int priority;
452 private final boolean tender;
455 * @deprecated ICU 51 Use {@link CurrencyMetaInfo#currencyInfo(CurrencyFilter)} instead.
457 public CurrencyInfo(String region, String code, long from, long to, int priority) {
458 this(region, code, from, to, priority, true);
462 * Constructs a currency info.
465 * @deprecated This API is ICU internal only.
467 public CurrencyInfo(String region, String code, long from, long to, int priority, boolean tender) {
468 this.region = region;
472 this.priority = priority;
473 this.tender = tender;
477 * Returns a string representation of this object, useful for debugging.
478 * @return A string representation of this object.
482 public String toString() {
483 return debugString(this);
487 * Determine whether or not this currency was once used, is used,
488 * or will be used as tender in this region.
490 * @provisional This API might change or be removed in a future release.
492 public boolean isTender() {
499 * Returns the list of CurrencyInfos matching the provided filter. Results
500 * are ordered by country code, then by highest to lowest priority (0 is highest).
501 * The returned list is unmodifiable.
502 * @param filter the filter to control which currency info to return
503 * @return the matching information
506 public List<CurrencyInfo> currencyInfo(CurrencyFilter filter) {
507 return Collections.emptyList();
511 * Returns the list of currency codes matching the provided filter.
512 * Results are ordered as in {@link #currencyInfo(CurrencyFilter)}.
513 * The returned list is unmodifiable.
514 * @param filter the filter to control which currencies to return. If filter is null,
515 * returns all currencies for which information is available.
516 * @return the matching currency codes
519 public List<String> currencies(CurrencyFilter filter) {
520 return Collections.emptyList();
524 * Returns the list of region codes matching the provided filter.
525 * Results are ordered as in {@link #currencyInfo(CurrencyFilter)}.
526 * The returned list is unmodifiable.
527 * @param filter the filter to control which regions to return. If filter is null,
528 * returns all regions for which information is available.
529 * @return the matching region codes
532 public List<String> regions(CurrencyFilter filter) {
533 return Collections.emptyList();
538 * Returns the CurrencyDigits for the currency code.
539 * @param isoCode the currency code
540 * @return the CurrencyDigits
543 public CurrencyDigits currencyDigits(String isoCode) {
544 return defaultDigits;
549 * @deprecated This API is ICU internal only.
551 protected static final CurrencyDigits defaultDigits = new CurrencyDigits(2, 0);
554 CurrencyMetaInfo temp = null;
555 boolean tempHasData = false;
557 Class<?> clzz = Class.forName("com.ibm.icu.impl.ICUCurrencyMetaInfo");
558 temp = (CurrencyMetaInfo) clzz.newInstance();
560 } catch (Throwable t) {
561 temp = new CurrencyMetaInfo();
564 hasData = tempHasData;
567 private static String dateString(long date) {
568 if (date == Long.MAX_VALUE || date == Long.MIN_VALUE) {
571 GregorianCalendar gc = new GregorianCalendar();
572 gc.setTimeZone(TimeZone.getTimeZone("GMT"));
573 gc.setTimeInMillis(date);
574 return "" + gc.get(Calendar.YEAR) + '-' + (gc.get(Calendar.MONTH) + 1) + '-' +
575 gc.get(Calendar.DAY_OF_MONTH);
578 private static String debugString(Object o) {
579 StringBuilder sb = new StringBuilder();
581 for (Field f : o.getClass().getFields()) {
585 if (v instanceof Date) {
586 s = dateString(((Date)v).getTime());
587 } else if (v instanceof Long) {
588 s = dateString(((Long)v).longValue());
590 s = String.valueOf(v);
595 if (sb.length() > 0) {
598 sb.append(f.getName())
604 } catch (Throwable t) {
606 sb.insert(0, o.getClass().getSimpleName() + "(");
608 return sb.toString();