Mercurial Hosting > nabble
comparison src/fschmidt/util/java/Money.java @ 68:00520880ad02
add fschmidt source
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Sun, 05 Oct 2025 17:24:15 -0600 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
67:9d0fefce6985 | 68:00520880ad02 |
---|---|
1 /* | |
2 Copyright (c) 2008 Franklin Schmidt <fschmidt@gmail.com> | |
3 | |
4 Permission is hereby granted, free of charge, to any person obtaining a copy | |
5 of this software and associated documentation files (the "Software"), to deal | |
6 in the Software without restriction, including without limitation the rights | |
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
8 copies of the Software, and to permit persons to whom the Software is | |
9 furnished to do so, subject to the following conditions: | |
10 | |
11 The above copyright notice and this permission notice shall be included in | |
12 all copies or substantial portions of the Software. | |
13 | |
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
20 THE SOFTWARE. | |
21 */ | |
22 | |
23 package fschmidt.util.java; | |
24 | |
25 import java.io.Externalizable; | |
26 import java.io.ObjectInput; | |
27 import java.io.IOException; | |
28 import java.io.ObjectOutput; | |
29 import java.io.ObjectInputStream; | |
30 import java.sql.PreparedStatement; | |
31 import java.sql.SQLException; | |
32 import java.sql.ResultSet; | |
33 import java.math.BigDecimal; | |
34 import java.util.regex.Pattern; | |
35 import java.util.regex.Matcher; | |
36 import fschmidt.db.DbStorable; | |
37 | |
38 | |
39 public final class Money implements Comparable, Externalizable, DbStorable { | |
40 private static final int currentVersion = 0; | |
41 private static final long serialVersionUID = 0L; | |
42 | |
43 private /*final*/ long cents; | |
44 | |
45 public static Money read(ObjectInput in) | |
46 throws IOException | |
47 { | |
48 if( !in.readBoolean() ) | |
49 return null; | |
50 return new Money(in.readLong()); | |
51 } | |
52 | |
53 public static void write(ObjectOutput out,Money m) | |
54 throws IOException | |
55 { | |
56 if( m==null ) { | |
57 out.writeBoolean(false); | |
58 return; | |
59 } | |
60 out.writeBoolean(true); | |
61 out.writeLong(m.cents); | |
62 } | |
63 | |
64 public void writeExternal(ObjectOutput out) | |
65 throws IOException | |
66 { | |
67 out.writeInt(currentVersion); | |
68 out.writeLong(cents); | |
69 } | |
70 | |
71 public void readExternal(ObjectInput in) | |
72 throws IOException, ClassNotFoundException | |
73 { | |
74 int ver = in.readInt(); | |
75 switch(ver) { | |
76 case 0: | |
77 cents = in.readLong(); | |
78 break; | |
79 default: | |
80 throw new RuntimeException(); | |
81 } | |
82 } | |
83 | |
84 public Money() {} // for Externalizable | |
85 | |
86 public Money(ObjectInput in) | |
87 throws IOException, ClassNotFoundException | |
88 { | |
89 cents = in.readInt(); | |
90 } | |
91 | |
92 public Money(long cents) { | |
93 this.cents = cents; | |
94 } | |
95 | |
96 private static final Pattern p = Pattern.compile(" *-?\\$? *[0-9,.]+ *"); | |
97 private static final Pattern pSub = Pattern.compile("[ \\$,]"); | |
98 | |
99 public Money(String val) | |
100 throws NumberFormatException | |
101 { | |
102 if( !p.matcher(val).matches() ) | |
103 throw new NumberFormatException("invalid format for money: '"+val+"'"); | |
104 Matcher mSub = pSub.matcher(val); | |
105 val = pSub.matcher(val).replaceAll(""); | |
106 cents = Math.round(Float.parseFloat(val)*100); | |
107 } | |
108 | |
109 public Money(double d) { | |
110 cents = (long)Math.round( (d *1000) / 10); | |
111 } | |
112 | |
113 public void setField(PreparedStatement stmt,int idx) | |
114 throws SQLException | |
115 { | |
116 stmt.setBigDecimal(idx,toBigDecimal()); | |
117 } | |
118 | |
119 public static void setMoneyNull(PreparedStatement stmt,int idx) | |
120 throws SQLException | |
121 { | |
122 stmt.setNull(idx,java.sql.Types.DECIMAL); | |
123 } | |
124 | |
125 public static void setMoney(PreparedStatement stmt,int idx,Money m) | |
126 throws SQLException | |
127 { | |
128 if( m==null ) { | |
129 setMoneyNull(stmt,idx); | |
130 } else { | |
131 m.setField(stmt,idx); | |
132 } | |
133 } | |
134 | |
135 public static Money getMoney(ResultSet rs,String columnName) | |
136 throws SQLException | |
137 { | |
138 Money m = new Money(rs,columnName); | |
139 return rs.wasNull() ? null : m; | |
140 } | |
141 | |
142 private Money(ResultSet rs,String columnName) | |
143 throws SQLException | |
144 { | |
145 cents = Math.round(rs.getFloat(columnName)*100); | |
146 } | |
147 | |
148 public boolean equals(Object obj) { | |
149 if( obj==null || !(obj instanceof Money) ) | |
150 return false; | |
151 Money m = (Money)obj; | |
152 return cents==m.cents; | |
153 } | |
154 | |
155 public int compareTo(Money val) { | |
156 return val != null ? | |
157 (cents < val.cents ? -1 : cents==val.cents ? 0 : 1) : | |
158 0; | |
159 } | |
160 | |
161 public int compareTo(Object obj) { | |
162 return compareTo( (Money)obj ); | |
163 } | |
164 | |
165 public int hashCode() { | |
166 return (int)cents; | |
167 } | |
168 | |
169 public String toString() { | |
170 return toString("$"); | |
171 } | |
172 | |
173 public String toString(String currency) { | |
174 StringBuilder buf = new StringBuilder(); | |
175 buf.append( cents<0 ? -cents : cents ); | |
176 while( buf.length() < 3 ) | |
177 buf.insert(0,'0'); | |
178 buf.insert(buf.length()-2,'.'); | |
179 int start = buf.charAt(0)=='-' ? 1 : 0; | |
180 for( int i=buf.length()-6; i>start; i-=3 ) | |
181 buf.insert(i,','); | |
182 buf.insert(0,currency); | |
183 if( cents < 0 ) | |
184 buf.insert(0,'-'); | |
185 return buf.toString(); | |
186 } | |
187 | |
188 public String toSimpleString() { | |
189 StringBuilder buf = new StringBuilder(); | |
190 buf.append(cents); | |
191 while( buf.length() < 3 ) | |
192 buf.insert(0,'0'); | |
193 buf.insert(buf.length()-2,'.'); | |
194 | |
195 return buf.toString(); | |
196 } | |
197 | |
198 public boolean isZero() { | |
199 return cents==0; | |
200 } | |
201 | |
202 public Money min(Money val) { | |
203 return cents < val.cents ? this : val; | |
204 } | |
205 | |
206 public Money max(Money val) { | |
207 return cents > val.cents ? this : val; | |
208 } | |
209 | |
210 public Money add(Money val) { | |
211 return new Money(cents+val.cents); | |
212 } | |
213 | |
214 public Money subtract(Money val) { | |
215 return new Money(cents-val.cents); | |
216 } | |
217 | |
218 public Money multiply(int val) { | |
219 return new Money(cents*val); | |
220 } | |
221 | |
222 public Money multiply(float val) { | |
223 return new Money(Math.round(cents*val)); | |
224 } | |
225 | |
226 public Money multiply(double val) { | |
227 return new Money((long)Math.round(cents*val)); | |
228 } | |
229 | |
230 public double divide(Money val) { | |
231 if ((double)val.cents == 0) { | |
232 return Double.NaN; | |
233 } | |
234 return (double)cents/(double)val.cents; | |
235 } | |
236 | |
237 public Money divide(int val) { | |
238 return new Money(cents/val); | |
239 } | |
240 | |
241 public Money divideRoundingUp(int val) { | |
242 return new Money((cents+val-1)/val); | |
243 } | |
244 | |
245 public Money divide(float val) { | |
246 return new Money(Math.round(cents/val)); | |
247 } | |
248 | |
249 public Money divide(double val) { | |
250 return new Money((long)Math.round(cents/val)); | |
251 } | |
252 | |
253 public Money inc() { | |
254 return new Money(cents+1); | |
255 } | |
256 | |
257 public Money dec() { | |
258 return new Money(cents-1); | |
259 } | |
260 | |
261 public Money avg(Money val) { | |
262 return new Money((cents+val.cents)/2); | |
263 } | |
264 | |
265 public double doubleValue() { | |
266 return cents/100.0; | |
267 } | |
268 | |
269 public BigDecimal toBigDecimal() { | |
270 return BigDecimal.valueOf(cents,2); | |
271 } | |
272 | |
273 public long getCents() { | |
274 return cents; | |
275 } | |
276 | |
277 | |
278 public static final Money ZERO = new Money(0); | |
279 public static final Money MAX_VALUE = new Money(Integer.MAX_VALUE); | |
280 public static final Money MIN_VALUE = new Money(Integer.MIN_VALUE); | |
281 | |
282 private void readObject(ObjectInputStream stream) | |
283 throws IOException, ClassNotFoundException | |
284 { | |
285 stream.defaultReadObject(); | |
286 } | |
287 | |
288 public static void main(String[] args) { | |
289 System.out.println(new Money("z$1,234.56 ")); | |
290 } | |
291 | |
292 } |