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 } |
