-
Notifications
You must be signed in to change notification settings - Fork 38
/
Copy pathcurrency.html
162 lines (126 loc) · 5.24 KB
/
currency.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>Currency</title>
</head>
<body>
<h1>Currency</h1>
<h2>Draft 2001-08-28</h2>
<p>We had some discussions connected with the Euro conversion. Especially for
the transition period, it is important to help people avoid bugs with currency
formatting and display. Currently, the burden is on the programmer to make sure
that the correct number is used with the correct format: you need to know
whether it is dollars or francs, plus call the right formatter.</p>
<p>The proposal is to add a Currency object (in C this will be a struct, but for
simplicity we'll use Java syntax here).</p>
<pre>/*
The Currency class encapsulates both a BigDecimal and a currency (ISO 4217 3-letter code).
It has three purposes:
- avoid type errors when formatting currencies where the wrong value is displayed.
- allow non-locale currencies to be displayed, e.g. Yen as displayed in the US.
- allow for conversion in display (but only where it can be done rigorously (i.e. EURO)!)
The change in behavior for formatting in NumberFormat should be:
1. if the currency is native to the locale, format it normally.
2. if the currency can be rigorously converted, e.g EUR to FRF or back
convert it, and format normally
Otherwise, get the number of decimal places from the representative locale, then
3. if the locale has a currency symbol for that currency, use it.
4. otherwise use the ISO currency symbol
To support this, we need to add a new element to the DecimalFormatSymbols
and the resource bundle. Here is an example:
foreignCurrencies: {{"JPY", "¥"}, {"CHF", "sFr"}, {"GBP", "£"}};
We will also have a global mapping from currency codes to representative locales.
Usually there is only one (USD -> en_US), but sometimes there are several
possibilities so we pick one (EUR -> de_DE).
[Note: this could be generated at build time.]
Examples:
NumberFormat nf = NumberFormat.getCurrencyInstance( );
Currency a = new Currency(1234.56,"EUR");
Currency a = new Currency(1234.56,"JPY");
1. fr_FR_EURO: nf.format(a) = "€ 1 234,56"
2. fr_FR_NOEURO: nf.format(a) = "Fr 8 665,00"
3. en_US: nf.format(a) = "€1,234.56", nf.format(b) = "¥1,235"
4. fr_FR: nf.format(b) = "JPY 1 235"
These examples are for the situation where:
#3, the en_US locale has the extra ForeignCurrencies resources for those currencies,
#4, the fr_FR lacks them, and so defaults to the currency symbol.
Note that before January 1, 2002, the default for fr_FR will be #2;
after it will be #1.
ISSUE: Possibly make this a subclass of BigDecimal.
Makes it easier to use, but might be considered to violate the
semantics since part of the point of the class is to disallow
combining mismatched currencies.
*/
public final class Currency {
BigDecimal amount;
int ISOcode;
// note: we compress the ISO 4217 code to fit into 16 bits,
// It is always 3 uppercase ASCII digits
// this isn't really necessary in Java, but might be useful
// in the C version.
public Currency(BigDecimal amount, String ISOcode) {
this.amount = amount;
this.ISOcode = compress(ISOcode);
}
public Currency(double amount, String ISOcode) {
this.amount = new BigDecimal(amount);
this.ISOcode = compress(ISOcode);
}
public BigDecimal getAmount() {
return amount;
}
public String getISOcode() {
return restore(ISOcode);
}
// have a few convenience functions.
// for anything else, extract the amount and use BigDecimal functions
public Currency add(Currency other) {
if (ISOcode != other.ISOcode) throw new NumberFormatException("Mismatched Currency Types");
return new Currency(amount.add(other.amount), ISOcode);
}
public Currency negate() {
return new Currency(amount.negate(), ISOcode);
}
public Currency convertTo(String ISOcode) {
// TODO: add EURO
// returns null if the code can't be rigorously converted.
return null;
}
// ==================
private Currency(BigDecimal amount, int ISOcode) {
this.amount = amount;
this.ISOcode = ISOcode;
}
private int compress(String code) {
int result = 0;
main:
if (code.length() == 3) {
for (int i = 0; i < 3; ++i) {
int c = code.charAt(i);
if (c < 'A' || c > 'z') break main;
c &= 0x1F;
if (c > 25) break main;
result <<= 5;
result += c;
}
return result;
}
throw new IllegalArgumentException("Illegal ISO Code");
}
private String restore (int i) {
char[] temp = new char[3];
temp[2] = (char)((i & 0x1F) + 0x40);
temp[1] = (char)(((i >>= 5) & 0x1F) + 0x40);
temp[0] = (char)((i >> 5) + 0x40);
return new String(temp);
}
public String toString() {
// for debugging only, should use NumberFormat for formatting
return "[" + getAmount() + ", " + getISOcode() + "]";
}
}
</pre>
</body>
</html>