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 }