Format liczb waluty Java

89

Czy istnieje sposób na sformatowanie ułamka dziesiętnego w następujący sposób:

100   -> "100"  
100.1 -> "100.10"

Jeśli jest to liczba okrągła, pomiń część dziesiętną. W przeciwnym razie format z dwoma miejscami po przecinku.

DD.
źródło

Odpowiedzi:

48

Wątpię. Problem polega na tym, że 100 nigdy nie jest 100, jeśli jest to liczba zmiennoprzecinkowa, zwykle jest to 99,99999999999 lub 100,0000001 lub coś w tym rodzaju.

Jeśli chcesz sformatować to w ten sposób, musisz zdefiniować epsilon, czyli maksymalną odległość od liczby całkowitej i użyć formatowania liczb całkowitych, jeśli różnica jest mniejsza, i zmiennoprzecinkowej w przeciwnym razie.

Coś takiego załatwiłoby sprawę:

public String formatDecimal(float number) {
  float epsilon = 0.004f; // 4 tenths of a cent
  if (Math.abs(Math.round(number) - number) < epsilon) {
     return String.format("%10.0f", number); // sdb
  } else {
     return String.format("%10.2f", number); // dj_segfault
  }
}
extraneon
źródło
8
Drobny chwytak: liczba zmiennoprzecinkowa może mieć dokładnie 100, z wzorem bitowym 0x42c80000.
Karol S
2
Tak, jak stwierdził Karol S, wiele liczb MOŻE być dokładnie dopasowanych przez liczby zmiennoprzecinkowe. Po prostu nie WSZYSTKIE liczby. 100 to jedna liczba, którą można przedstawić, należy wziąć pod uwagę liczby, których nie można przedstawić.
csga5000
160

Polecam użycie pakietu java.text:

double money = 100.1;
NumberFormat formatter = NumberFormat.getCurrencyInstance();
String moneyString = formatter.format(money);
System.out.println(moneyString);

Ma to tę dodatkową zaletę, że jest specyficzna dla lokalizacji.

Ale jeśli musisz, skróć ciąg, który otrzymujesz, jeśli jest to cały dolar:

if (moneyString.endsWith(".00")) {
    int centsIndex = moneyString.lastIndexOf(".00");
    if (centsIndex != -1) {
        moneyString = moneyString.substring(1, centsIndex);
    }
}
duffymo
źródło
17
Nigdy nie powinieneś używać podwójnego do reprezentowania walut. Konwertuj na długie i zarządzaj separatorem dziesiętnym samodzielnie lub użyj BigDecimalprogramu formatującego. Biblioteka joda-money.sourceforge.net powinna być przyjemną biblioteką do użytku po jej zakończeniu .
gpampara
5
Zgadzam się, re: double! = Pieniądze, ale nie tak postawiono pytanie.
duffymo
3
Co masz na myśli, mówiąc, że tak działają waluty? Mogę powiedzieć, że coś kosztuje 1 dolara, a nie 1 dolara .... istnieje inny sposób wyświetlania walut (inny niż domyślny) i to pytanie dotyczy sposobu pominięcia części dziesiętnej, jeśli jest to liczba całkowita.
DD.
1
To problem z renderowaniem. Umieść logikę w swoim interfejsie użytkownika, aby zaakceptować walutę jako ciąg znaków i skrócić liczbę dziesiętną i centy, jeśli jest to dokładny dolar.
duffymo,
2
Zgoda - dlatego zaleciłem używanie Locale, pisząc to 5,5 roku temu. „Ale jeśli musisz…” to kluczowe zdanie.
duffymo
124
double amount =200.0;
Locale locale = new Locale("en", "US");      
NumberFormat currencyFormatter = NumberFormat.getCurrencyInstance(locale);
System.out.println(currencyFormatter.format(amount));

lub

double amount =200.0;
System.out.println(NumberFormat.getCurrencyInstance(new Locale("en", "US"))
        .format(amount));

Najlepszy sposób na wyświetlanie waluty

Wynik

200,00 $

Jeśli nie chcesz używać znaku, użyj tej metody

double amount = 200;
DecimalFormat twoPlaces = new DecimalFormat("0.00");
System.out.println(twoPlaces.format(amount));

200,00

Można tego również użyć (z separatorem tysięcy)

double amount = 2000000;    
System.out.println(String.format("%,.2f", amount));          

2 000 000,00

Thilina Dharmasena
źródło
Nie wygląda na to, że odwołuje się do „waluty” lub jest używana po jej zadeklarowaniu. Czy z jakiegoś powodu to włączyłeś?
Damian
Przeczytaj więcej o [Class Locale] [1] [1]: docs.oracle.com/javase/7/docs/api/java/util/…
Thilina Dharmasena
18

Nie znalazłem żadnego dobrego rozwiązania po wyszukiwaniu w Google, po prostu opublikuj moje rozwiązanie, aby inni mogli się z nimi zapoznać. użyj priceToString do formatowania pieniędzy.

public static String priceWithDecimal (Double price) {
    DecimalFormat formatter = new DecimalFormat("###,###,###.00");
    return formatter.format(price);
}

public static String priceWithoutDecimal (Double price) {
    DecimalFormat formatter = new DecimalFormat("###,###,###.##");
    return formatter.format(price);
}

public static String priceToString(Double price) {
    String toShow = priceWithoutDecimal(price);
    if (toShow.indexOf(".") > 0) {
        return priceWithDecimal(price);
    } else {
        return priceWithoutDecimal(price);
    }
}
wu liang
źródło
Nigdy nie powiedział, że to lepsze. ON właśnie opublikował swoje rozwiązanie, aby inni mogli z niego korzystać. Można przynajmniej powiedzieć, że dziękuję.
Umang Desai,
A jeśli chcę wyświetlić cenę w formacie indyjskim. Bez miejsc po przecinku. Format -> ##, ##, ###
Bhuvan
W metodzie priceWithDecimal (Double) spróbuj zmienić maskę "###,###,###.00"na "###,###,##0.00"„0,00”, gdy wartość wynosi „0”
dellasavia
1
co odwrotnie, aby ponownie przekonwertować sformatowaną walutę na Double
Vivek Shankar
6

Tak. Możesz użyć java.util.formatter . Możesz użyć ciągu formatującego, takiego jak „% 10.2f”

dj_segfault
źródło
String.format()jest do tego ładnym statycznym opakowaniem. Nie jestem jednak pewien, dlaczego używasz „10”.
Xr.
Nie mając wskazówek co do wielkości tej liczby, wybrałem 10 Ex Recto. Nie wiemy, czy taka jest cena batonika czy samochodu. Uważam, że możesz też po prostu zrobić "% .2f", aby pozostawić nieograniczony rozmiar całkowity.
dj_segfault
DD chciał pominąć część dziesiętną, jeśli kwota jest zaokrągloną liczbą jednostek walutowych.
jarnbjo
6

Używam tego (używam StringUtils z commons-lang):

Double qty = 1.01;
String res = String.format(Locale.GERMANY, "%.2f", qty);
String fmt = StringUtils.removeEnd(res, ",00");

Musisz tylko zadbać o lokalizację i odpowiedni ciąg do cięcia.

Dirk Lachowski
źródło
5

Myślę, że jest to proste i jasne w przypadku drukowania waluty:

DecimalFormat df = new DecimalFormat("$###,###.##"); // or pattern "###,###.##$"
System.out.println(df.format(12345.678));

wyjście: 12 345,68 $

I jedno z możliwych rozwiązań na pytanie:

public static void twoDecimalsOrOmit(double d) {
    System.out.println(new DecimalFormat(d%1 == 0 ? "###.##" : "###.00").format(d));
}

twoDecimalsOrOmit((double) 100);
twoDecimalsOrOmit(100.1);

Wynik:

100

100.10

Andrzej
źródło
Przegapiłeś sens postu. Jeśli liczba jest liczbą całkowitą, nie chcę wyświetlać żadnych miejsc po przecinku.
DD.
DD. Przepraszam i poprawiłem odpowiedź zgodnie z pytaniem.
Andrew
5

Zwykle będziemy musieli zrobić odwrotność, jeśli twoje pole pieniężne json jest zmiennoprzecinkowe, może mieć wartość 3,1, 3,15 lub tylko 3.

W takim przypadku może być konieczne zaokrąglenie go, aby poprawnie wyświetlić (i móc później użyć maski w polu wprowadzania):

floatvalue = 200.0; // it may be 200, 200.3 or 200.37, BigDecimal will take care
Locale locale = new Locale("en", "US");      
NumberFormat currencyFormatter = NumberFormat.getCurrencyInstance(locale);

BigDecimal valueAsBD = BigDecimal.valueOf(value);
    valueAsBD.setScale(2, BigDecimal.ROUND_HALF_UP); // add digits to match .00 pattern

System.out.println(currencyFormatter.format(amount));
zwisy
źródło
5

w ten najlepszy sposób.

    public static String formatCurrency(String amount) {
        DecimalFormat formatter = new DecimalFormat("###,###,##0.00");
        return formatter.format(Double.parseDouble(amount));
    }

100 -> „100,00”
100,1 -> „100,10”

Samet ÖZTOPRAK
źródło
5
NumberFormat currency = NumberFormat.getCurrencyInstance();
String myCurrency = currency.format(123.5);
System.out.println(myCurrency);

wynik:

$123.50

Jeśli chcesz zmienić walutę,

NumberFormat currency = NumberFormat.getCurrencyInstance(Locale.CHINA);
String myCurrency = currency.format(123.5);
System.out.println(myCurrency);

wynik:

123.50
Subhashi
źródło
4

powinieneś zrobić coś takiego:

public static void main(String[] args) {
    double d1 = 100d;
    double d2 = 100.1d;
    print(d1);
    print(d2);
}

private static void print(double d) {
    String s = null;
    if (Math.round(d) != d) {
        s = String.format("%.2f", d);
    } else {
        s = String.format("%.0f", d);
    }
    System.out.println(s);
}

który drukuje:

100

100,10

Stefan De Boey
źródło
Czy Math.round (d)! = D zadziała? Z pływakami to często! = Nawet jeśli myślisz, że tak.
extraneon
1
z drugiej strony, gdyby d było 100,000000000000001, to nadal byłoby wydrukowane jako 100
Stefan De Boey
4

Wiem, że to stare pytanie, ale ...

import java.text.*;

public class FormatCurrency
{
    public static void main(String[] args)
    {
        double price = 123.4567;
        DecimalFormat df = new DecimalFormat("#.##");
        System.out.print(df.format(price));
    }
}
Aezur
źródło
3
To nie działa, działa na przykład 100.1 -> "100.1" - zobacz stackoverflow.com/questions/5033404/…
davnicwil
4

Możesz po prostu zrobić coś takiego i podać całą liczbę, a następnie centy.

String.format("$%,d.%02d",wholeNum,change);
user2645904
źródło
4

Zgadzam się z @duffymo, że musisz używać java.text.NumberFormatmetod do tego typu rzeczy. W rzeczywistości możesz wykonać całe formatowanie w nim natywnie bez wykonywania jakichkolwiek porównań typu String:

private String formatPrice(final double priceAsDouble) 
{
    NumberFormat formatter = NumberFormat.getCurrencyInstance();
    if (Math.round(priceAsDouble * 100) % 100 == 0) {
        formatter.setMaximumFractionDigits(0);
    }
    return formatter.format(priceAsDouble);
}

Kilka bitów, na które warto zwrócić uwagę:

  • Całość Math.round(priceAsDouble * 100) % 100po prostu omija niedokładności podwójnych / floatów. Po prostu sprawdzając, czy zaokrąglijmy do setek (może to nastawienie amerykańskie), czy są jeszcze centy.
  • Sztuczka setMaximumFractionDigits()polegająca na usunięciu liczb dziesiętnych polega na metodzie

Bez względu na logikę określania, czy ułamki dziesiętne powinny zostać obcięte, czy też nie, setMaximumFractionDigits()powinna zostać wykorzystana.

xbakesx
źródło
1
Jeśli chodzi o punkt widzenia *100i %100bycie nastawionym na US, możesz użyć Math.pow(10, formatter.getMaximumFractionDigits())zamiast zakodowanego 100na
stałe
3

Jeśli chcesz pracować na walutach, musisz użyć klasy BigDecimal. Problem polega na tym, że nie ma sposobu na przechowywanie w pamięci niektórych liczb zmiennoprzecinkowych (np. Można zapisać 5,3456, ale nie 5,3455), co może mieć wpływ na złe obliczenia.

Jest fajny artykuł, jak współpracować z BigDecimal i walutami:

http://www.javaworld.com/javaworld/jw-06-2001/jw-0601-cents.html

Adrian Adamczyk
źródło
2
Nie ma to żadnego związku z pytaniem, które zadałem.
DD.
3

Format od 1000000,2 do 1000000,20

private static final DecimalFormat DF = new DecimalFormat();

public static String toCurrency(Double d) {
    if (d == null || "".equals(d) || "NaN".equals(d)) {
        return " - ";
    }
    BigDecimal bd = new BigDecimal(d);
    bd = bd.setScale(2, BigDecimal.ROUND_HALF_UP);
    DecimalFormatSymbols symbols = DF.getDecimalFormatSymbols();
    symbols.setGroupingSeparator(' ');
    String ret = DF.format(bd) + "";
    if (ret.indexOf(",") == -1) {
        ret += ",00";
    }
    if (ret.split(",")[1].length() != 2) {
        ret += "0";
    }
    return ret;
}
Lukas
źródło
2

Ten post naprawdę pomógł mi w końcu dostać to, czego chcę. Więc chciałem po prostu dodać tutaj swój kod, aby pomóc innym. Oto mój kod z pewnym wyjaśnieniem.

Poniższy kod:

double moneyWithDecimals = 5.50;
double moneyNoDecimals = 5.00;
System.out.println(jeroensFormat(moneyWithDecimals));
System.out.println(jeroensFormat(moneyNoDecimals));

Wróci:

5,-
€ 5,50

Rzeczywista metoda jeroensFormat ():

public String jeroensFormat(double money)//Wants to receive value of type double
{
        NumberFormat dutchFormat = NumberFormat.getCurrencyInstance();
        money = money;
        String twoDecimals = dutchFormat.format(money); //Format to string
        if(tweeDecimalen.matches(".*[.]...[,]00$")){
            String zeroDecimals = twoDecimals.substring(0, twoDecimals.length() -3);
                return zeroDecimals;
        }
        if(twoDecimals.endsWith(",00")){
            String zeroDecimals = String.format("€ %.0f,-", money);
            return zeroDecimals; //Return with ,00 replaced to ,-
        }
        else{ //If endsWith != ,00 the actual twoDecimals string can be returned
            return twoDecimals;
        }
}

Metoda displayJeroensFormat, która wywołuje metodę jeroensFormat ()

    public void displayJeroensFormat()//@parameter double:
    {
        System.out.println(jeroensFormat(10.5)); //Example for two decimals
        System.out.println(jeroensFormat(10.95)); //Example for two decimals
        System.out.println(jeroensFormat(10.00)); //Example for zero decimals
        System.out.println(jeroensFormat(100.000)); //Example for zero decimals
    }

Będzie miał następujący wynik:

10,5010,9510,-
€ 100.000 (In Holland numbers bigger than € 999,- and wit no decimals don't have ,-)

Ten kod wykorzystuje Twoją aktualną walutę. W moim przypadku jest to Holandia, więc sformatowany ciąg dla mnie będzie inny niż dla kogoś w USA.

  • Holandia: 999,999,99
  • USA: 999 999,99

Po prostu obserwuj ostatnie 3 znaki tych liczb. Mój kod zawiera instrukcję if, która sprawdza, czy ostatnie 3 znaki są równe „, 00”. Aby używać tego w USA, być może trzeba będzie zmienić to na „.00”, jeśli to jeszcze nie działa.

Jeroen
źródło
2

Byłem na tyle szalony, żeby napisać własną funkcję:

Spowoduje to konwersję liczby całkowitej na format walutowy (można go również zmodyfikować w przypadku liczb dziesiętnych):

 String getCurrencyFormat(int v){
        String toReturn = "";
        String s =  String.valueOf(v);
        int length = s.length();
        for(int i = length; i >0 ; --i){
            toReturn += s.charAt(i - 1);
            if((i - length - 1) % 3 == 0 && i != 1) toReturn += ',';
        }
        return "$" + new StringBuilder(toReturn).reverse().toString();
    }
A-Sharabiani
źródło
2
  public static String formatPrice(double value) {
        DecimalFormat formatter;
        if (value<=99999)
          formatter = new DecimalFormat("###,###,##0.00");
        else
            formatter = new DecimalFormat("#,##,##,###.00");

        return formatter.format(value);
    }
PRATEEK BHARDWAJ
źródło
1

Oto, co zrobiłem, używając liczby całkowitej do przedstawienia kwoty w centach:

public static String format(int moneyInCents) {
    String format;
    Number value;
    if (moneyInCents % 100 == 0) {
        format = "%d";
        value = moneyInCents / 100;
    } else {
        format = "%.2f";
        value = moneyInCents / 100.0;
    }
    return String.format(Locale.US, format, value);
}

Problem NumberFormat.getCurrencyInstance()polega na tym, że czasami naprawdę chcesz, aby 20 $ to 20 $, po prostu wygląda lepiej niż 20,00 $.

Jeśli ktoś znajdzie lepszy sposób na zrobienie tego, używając NumberFormat, mam uszy.

Viktor Nordling
źródło
1

Dla osób, które chcą sformatować walutę, ale nie chcą, aby była oparta na lokalnej, możemy to zrobić:

val numberFormat = NumberFormat.getCurrencyInstance() // Default local currency
val currency = Currency.getInstance("USD")            // This make the format not locale specific 
numberFormat.setCurrency(currency)

...use the formator as you want...
Haomin
źródło