onepub-dev/money.dart

BitCoin parsing is wrong.

Closed this issue · 5 comments

code

    money = Money.parse('₿1.99', CommonCurrencies().btc);
    expect(money.format('#.###'), '1.990');

result

Expected: '1.990'
  Actual: '1.000'

The parsing is actually correct (at as money defines it currently).

Money.parse uses the currencies format to parse the amount.

As the default format for BTC is S0 it will only parse out the integer component of the passed amount.

So to correctly parse the amount you passed use:

final money = Money.parse('₿1.99', CommonCurrencies().btc, format: 'S0.00');

There is a question here about how money parses amounts.
Should it parse in minor units that exceed the passed format?

@ttyniwa I've had a harder look at this problem and I've made some changes to the api to better handle this type of situations.

From the 2.3.0 release notes (which I've just published):

  • In response to issue #53 we have modified how excess minorUnits (decimals) are parsed. Even if the parse pattern doesn't contain decimal places we will still parse decimal places in the Monetary Value. This ensures that we always retain the original parsed values precisions. However the api is currently quiet on how precision is treated when parsing decimals. We have now documented the api to state that we will parse upto the Currencies defined precisions.
    • This means:
      if you pass a monetary value with decimal digits in excess of the Currencies precision they will be ignored.
      If you pass a monetary value with decimal digits in excess of the passed pattern then they will be parsed upto the precision of the Currency.
  • Fixed a bug where parsing a no. of the form '.99' (i.e. no leading major digit) would thrown an exception.

The result of these changes is that your example will now work as you expected.

I'm closing this issue but If you find further issues feel free to re-open it.

@ttyniwa I do have question.

I'm wondering if the default pattern for bitcoin is correct.
Currently it is S0 with a precision of 8.
For most currencies the no. of decimals in the default pattern matches the precision.

Should this be changed?

/// current
final Currency btc = Currency.create('BTC', 8, symbol: '₿', pattern: 'S0');
/// proposed
final Currency btc = Currency.create('BTC', 8, symbol: '₿', pattern: 'S0.00000000');

Thank you for your prompt response.
This is the behavior I was hoping for.

Currently it is S0 with a precision of 8.
For most currencies the no. of decimals in the default pattern matches the precision.

Should this be changed?

In my opinion, BTC pattern should be 'S0.########'.
# A single digit, omitted if the value is zero

The new BTC pattern is:
final Currency btc = Currency.create('BTC', 8, symbol: '₿', pattern: 'S0.00000000');

This is to make it consistent with other currencies.

You can still get the output you desired by using your proposed pattern be either

registering your own version of BTC via Currencies.register(btc);

or supplying your own pattern when calling Money.format()