Giter Site home page Giter Site logo

automatevalue / nodamoney Goto Github PK

View Code? Open in Web Editor NEW
203.0 17.0 46.0 8 MB

NodaMoney provides a library that treats Money as a first class citizen and handles all the ugly bits like currencies and formatting.

License: Apache License 2.0

C# 97.06% Smalltalk 1.60% PowerShell 0.72% Shell 0.59% Batchfile 0.03%
money currencies exchange-rates domain-driven-design

nodamoney's Introduction

NodaMoney

You can get the latest stable release or prerelease from the official Nuget.org feed or from our github releases page.

If you'd like to work with the bleeding edge, you can use our custom Nuget feed. Packages on this feed are alpha and beta and, while they've passed all our tests, are not yet ready for production.

For support, bugs and new ideas use GitHub issues. Please see our guidelines for contributing to the NodaMoney.

Build status Coverage Status

See http://www.nodamoney.org/ for more information about this project or below.

About

NodaMoney provides a library that treats Money as a first class citizen in .NET and handles all the ugly bits like currencies and formatting.

We have the decimal type in .NET to store an amount of money, which can be used for very basic things. But it's still a numeric value without knowledge about its currency, major and minor units, formatting, etc. The .NET Framework has the System.Globalization namespace that helps with formatting of money in different cultures and regions, but it only captures some info about currencies, but not everything.

There is also some business logic surronding money, like dividing without losing pennies (like in the movie Office Space), conversion, etc. that motivates to have a Money type that contains all the domain logic, like Martin Fowler already descibed in his book Patterns of Enterprise Application Architecture

NodaMoney represents the .NET counterpart of java library JodaMoney, like NodaTime is the .NET counterpart of JodaTime. NodaMoney does not provide, nor is it intended to provide, monetary algorithms beyond the most basic and obvious. This is because the requirements for these algorithms vary widely between domains. This library is intended to act as the base layer, providing classes that should be in the .NET Framework. It complies with the currencies in ISO 4217.

Usage

At the moment there are four classes:

  • Currency: An immutable structure that represents a currency. It can give all ISO 4217 and custom currencies.
  • Money: An immutable structure that represents money in a specified currency.
  • ExchangeRate: A stucture that represents a currency pair that can convert money from one currency to another currency.
  • CurrencyBuilder: Defines a custom currency that is new or based on another currency.

Initalizing money

// define money with explicit currency
var euros = new Money(6.54m, Currency.FromCode("EUR"));
var euros = new Money(6.54m, "EUR");

// define money explicit using helper method for most used currencies in the world
var money = Money.Euro(6.54m);
var money = Money.USDollar(6.54m);
var money = Money.PoundSterling(6.54m);
var money = Money.Yen(6);

// define money implicit using currency of current culture/region
var money = new Money(6.54m);
Money money = 6.54m;
Money money = 6;
Money money = (Money)6.54; // need explict cast from double data type  

// auto-rounding to the minor unit will take place with MidpointRounding.ToEven
// also known as banker's rounding 
var euro = new Money(765.425m, "EUR"); // EUR 765.42
var euro = new Money(765.425m, "EUR", MidpointRounding.AwayFromZero); // EUR 765.43

// deconstruct money
var money = new Money(10m, "EUR");
var (amount, currency) = money;

Money operations

var euro10 = Money.Euro(10);
var euro20 = Money.Euro(20);
var dollar10 = Money.USDollar(10);

// add and substract
var euro30 = euro10 + euro20;
var euro10 = euro20 - euro10;
var m = euro10 + dollar10; // will throw exception!
euro10 += euro20;
euro10 -= euro20;

// compare money
euro10 == euro20; // false
euro10 != euro20; // true;
euro10 == dollar10; // false;
euro20 > euro10; // true;
euro10 <= dollar10; // will throw exception!

// decrement and increment by minor unit
var yen = new Money(765m, "JPY"); // the smallest unit is 1 yen
var euro = new Money(765.43m, "EUR");
++yen; // JPY 766
--yen; // JPY 765
++euro; // EUR 765.44
--euro; // EUR 765.43

Money formatting

var yen = new Money(765m, "JPY");
var euro = new Money(765.43m, "EUR");
var dollar = new Money(765.43m, "USD");
var dinar = new Money(765.432m, "BHD");

// Implicit when current culture is 'en-US'
yen.ToString();    // "¥765"
euro.ToString();   // "€765.43"
dollar.ToString(); // "$765.43"
dinar.ToString();  // "BD765.432"

yen.ToString("C2");    // "¥765.00"
euro.ToString("C2");   // "€765.43"
dollar.ToString("C2"); // "$765.43"
dinar.ToString("C2");  // "BD765.43"

// Implicit when current culture is 'nl-BE'
yen.ToString();    // "¥ 765"
euro.ToString();   // "€ 765,43"
dollar.ToString(); // "$ 765,43"
dinar.ToString();  // "BD 765,432"

// Implicit when current culture is 'fr-BE'
yen.ToString();    // "765 ¥"
euro.ToString();   // "765,43 €"
dollar.ToString(); // "765,43 $"
dinar.ToString();  // "765,432 BD"
}

// Explicit format for culture 'nl-NL'
var ci = new CultureInfo("nl-NL");

yen.ToString(ci);    // "¥ 765"
euro.ToString(ci);   // "€ 765,43"
dollar.ToString(ci); // "$ 765,43"
dinar.ToString(ci);  // "BD 765,432"

Money parsing

// Implicit parsing when current culture is 'nl-BE'
Money euro = Money.Parse("€ 765,43");
Money euro = Money.Parse("-€ 765,43");
Money euro = Money.Parse("€-765,43");
Money euro = Money.Parse("765,43 €");
Money yen = Money.Parse("¥ 765"); // throw FormatException, because ¥ symbol is used for Japanese yen and Chinese yuan
Money dollar = Money.Parse("$ 765,43"); // throw FormatException, because $ symbol is used for multiple currencies

// Implicit parsing when current culture is 'ja-JP'
Money yen = Money.Parse("¥ 765");

// Implicit parsing when current culture is 'zh-CN'
Money yuan = Money.Parse("¥ 765");

// Implicit parsing when current culture is 'en-US'
Money dollar = Money.Parse("$765.43");
Money dollar = Money.Parse("($765.43)"); // -$765.43

// Implicit parsing when current culture is 'es-AR'
Money peso = Money.Parse("$765.43");

// Explicit parsing when current culture is 'nl-BE'
Money euro = Money.Parse("€ 765,43", Currency.FromCode("EUR"));
Money euro = Money.Parse("765,43 €", Currency.FromCode("EUR"));
Money yen = Money.Parse("¥ 765", Currency.FromCode("JPY"));
Money yuan = Money.Parse("¥ 765", Currency.FromCode("CNY"));

// Implicit try parsing when current culture is 'nl-BE'
Money euro;
Money.TryParse("€ 765,43", out euro);

// Explicit try parsing when current culture is 'nl-BE'
Money euro;
Money.TryParse("€ 765,43", Currency.FromCode("EUR"), out euro);

Adding custom currencies

// Build custom currency
var builder = new CurrencyBuilder("BTC", "virtual")
				{
					EnglishName = "Bitcoin",
					Symbol = "฿",
                    ISONumber = "123", // iso number
					DecimalDigits = 8
				};

// Build, but will not register it
var bitcoin = builder.Build();
Money bitcoins = new Money(1.2, bitcoin);

// Build and register it for the life-time of the app domain in the namespace 'virtual'
var bitcoin = builder.Register();
Money bitcoins = new Money(1.2, "BTC"); // works if no overlap with other namespaces
Money bitcoins = new Money(1.2, Currency.FromCode("BTC", "virtual"));

// Replace ISO 4217 currency for the life-time of the app domain
Currency oldEuro = CurrencyBuilder.Unregister("EUR", "ISO-4217");

var builder = new CurrencyBuilder("EUR", "ISO-4217");
builder.LoadDataFromCurrency(oldEuro);
builder.EnglishName = "New Euro";
builder.DecimalDigits = 1;
builder.Register();

Currency newEuro = Currency.FromCode("EUR");

nodamoney's People

Contributors

carlosschults avatar gormac avatar jawn avatar oskardudycz avatar ptjhuang avatar remyduijkeren avatar rubenrorije avatar rutgervanwilligen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nodamoney's Issues

Newtonsoft Json serialization of default(Money) fails

default(Money) fails serialization round-trip of MoneyJsonConverter. Should that be fixed?

[Fact]
public void Money_default_should_serialize()
{
    var expected = new Money();
    var json = JsonConvert.SerializeObject(expected);
    var actual = JsonConvert.DeserializeObject<Money>(json); // Fails here
    actual.Should().NotBeNull();
    actual.Currency.Should().Be(expected.Currency);
    actual.Amount.Should().Be(expected.Amount);
}

Initializing Money with Double (or Single) should use the string representation instead of casting

Initializing Money with Double (or Single) should use the string representation instead of casting, like in JodaMoney. This would lead to the the most expected answer for most programming scenarios. Any Double in code will be converted to exactly the same Money with the same scale. For example, the Double '1.45d' will be converted to '1.45'.

double do = 1.45;
string s = 1.45.ToString(); // or String.Parse()?
decimal de = Decimal.Parse(s);

See also http://stackoverflow.com/a/7186298/8820 (BigDecimal in Java)

Concurrency dependency and compatability

This may or may not qualify as an issue for the library as a whole.

The 0.5.0.0 release of NodaMoney on NuGet adds a project dependency upon System.Collections.Concurrent, for the purpose of two ConcurrentDictionaries in the CurrencyRegistry. System.Collections.Concurrent does not appear to be broadly compatible with all PCL profiles, or at least the one that we're dependent upon (78), and so we're unable to use this version. Given the apparently very limited application of System.Collections.Concurrent classes, I wanted to at least float the possibility of removing the dependency in future releases (would locks suffice?).

I know I probably should just utilize a private fork and address this issue on my own, but my organization won't be supporting VS2015/C#6 for a while yet, which means needing to base off months old code before the conversion, and just generally putting up with a whole bunch of maintenance and maintainability headaches. :)

Thanks for reading; great library! I dearly want to make use of it. :)

Add override to create ExchangeRate from currency codes

ExchangeRate can now only be initiated, like:
var fx = new ExchangeRate(Currency.FromCode("EUR"), Currency.FromCode("USD"), 1.2591)

Add the option to use currency codes to initialize an ExchangeRate:
var fx = new ExchangeRate("EUR", "USD", 1.2591)

Add 'namespaces' to currency

By adding namespace functionality we can support legacy and custom currencies (like BitCoin), besides the ISO currencies. See also the newly implemented CurrencyUnit in Java 8/9.

The default should be ISO, but something like an override would be useful:

var eur = Currency.FromCode("EUR");
var xbt = Currency.FromCode("XBT", "Custom"); // or an enum

Also think how developers can add there own currencies by registering them. See an example for Cultures in .NET: http://msdn.microsoft.com/en-us/library/ms172469%28v=VS.100%29.aspx.

How should we name the classes? CurrencyFormatInfo(Builder), MoneyFormatInfo(Builder)

Doing money calculation and perform rounding at the end

By default the Money instance will round every math operation (+. -, *. /, etc) that might have fractions of cents using a RoundingMode.

This will cause issues with multiple operations and money loss. If you multiple by a couple of numbers, do some division, add a few things, do some more division, you'll end up losing multiple cents along the way. This happens frequently in financial applications and many others as well.

There needs to be a way to perform multiple calculations on a Money instance without any rounding and then round at the end. Perhaps a MoneyCalculater (or building pattern) of some sort that can provide multiple operations without rounding and in the end provide back a Money instance that is rounded.

The best is probably to use a delegate like Func<Money, Money>, Action<Money> or a custom delegate.

See an example like https://github.com/gigs2go/joda-money-calculator/tree/master/joda-money-calculator or the builder pattern in JavaMoney.

Plus operator

If I try something like this

Money money = new Money(10, "GBP");
list[gbpAnountNdx] += 10;

I do not end up with 20 GBP, I end up with the exception.
Reson? My local culture is USA, so plus operator first created sctruct Money using "USD" and then tried to perform addition, which caused exception since I attempted to add two different currencies.

Can we introduce addition operator override that would treat numbers in a proper way - look at currency, create new Money with that currency and then call existing override that sums up two Money structs?

Upcoming change in ISO 4217 for Belarusion Ruble (Amendment Number 161)

From 1 July 2016 to 31 December 2016, the banknotes of the 2000 series and the banknotes and coins of the 2009 series will be in parallel circulation and subject to obligatory acceptance without restriction in all kinds of payments to the ratio of 10,000 old for one new ruble (10,000:1).

From 1 January 2017 through 31 December 2021, the currency units of the 2000 series will be exchanged for the currency units of the 2009 series in any sum without restriction and charging commission.

See http://www.currency-iso.org/en/shared/amendments/iso-4217-amendment.html

Add coins and banknotes to Currency

We could add the possible coins and banknotes to Currency. For example for Euro (EUR) we have the following:

  • Coins:
    • Freq Used: €1, €2, 5cent, 10cent, 20cent, 50cent
    • Rarely Used: 1cent, 2cent
  • Banknotes:
    • Freq Used: €5, €10, €20, €50, €100
    • Rarely Used: €200, €500

Is this useful for anyone and how would they want to use it?

Add extension methods to CultureInfo and/or Region

For example:
var ci = new CultureInfo("nl-NL");
var currency = ci.GetCurrency();

This issue should also take into consideration the fact that a certain Culture might have 2 currencies.
One might be the official Currency, the other Currency might the most used Currency. For example many countries use the dollar for trading and/or paying for commodities, this instead of their official Currency.

Taxed money type

I wonder if it would be useful to add TaxedMoney type with a distinction between net amount and gross amount, just a proposition though. Tell me what you think.

But then, the following requirements should be met:

  • Changing tax updates the amounts, should it calculate from gross or net?
  • Two static instantiation methods to be able to instantiate from gross or from net FromNet/FromGross
  • Change of gross amount changes net amount, and change of net amount changes gross amount respectively to keep amounts synchronized

Taxation is pretty complex, and it would be great if NodaMoney handled that as well

new ExchangeRate() Value round to 4 digits only. Loss of fraction occurs

Hi!
In most cases base currency have bigger value than quote currency.
But in some situations (money order between two people with different currencies; or simply nonstandard pair where quote currency and base currency are overturned) ExchangeRate.Value is much less than 1 and loss of fraction occurs.

Maybe rounding should be more than 4 digits or to add exception if ExchangeRate.Value is less than 1 to prevent losses.

Make ExchangeRate dated

See the comments of #8 for the start issue.

ExchangeRate is/can't be dated at the moment. It would be nice to add the dates where the ExchangeRate is valid between.

Possible implementations could be:

// override of constructor
var fx = new ExchangeRate("EUR", "USD", 1.14m, dateFrom, dateTo)
var fx = new ExchangeRate("EUR", "USD", 1.14m, new Range<DateTime>(dateFrom, dateTo))
var fx = new ExchangeRate("EUR", "USD", 1.14m, new Period(dateFrom, dateTo))

// or be external
var fx = new ExchangeRate("EUR", "USD", 1.14m)
var datedFx = new Range<DateTime>(dateFrom, dateTo, fx);
var datedFx = new Period(dateFrom, dateTo, fx);

Add NativeName to Currency

Apart from the English name of a Currency, we also want to have a native name of the Currency.

RegionInfo class in .NET has these names available. See RegionInfo.CurrencyNativeName. Check if these are sufficient.

sample code doesn't work

image

I guess Currency constructor should allow null for "number" parameter, or should use default value (eg. "none").

Nuget package deploy - readme and license

Nuget package deploys Radme and License files into the root directory of the project. This is a bit unusually. Usual practice is to ask for licence acceptance and to open readme upon installation, but location of readme points to packages/package.
Can something be done regarding this?

Failing Tests - GivenIWantToParseImplicitCurrency

I have been using the library and have found that I get errors randomly on first use.

I believe I have tracked this down to a race condition in the CurrencyRegistry when constructing the list of currencies. If the currency is not returned it uses the CurrentCulture's currency, which in my case is AUD, but usually using USD in this app.

If you run all tests you'll find that random parse tests fail, this is a symptom of the race problem.

Example test output:

NodaMoney.Tests.MoneyParsableSpec.GivenIWantToTryParseImplicitCurrency.WhenParsingDollarSymbolInArgentina_ThenThisShouldReturnArgentinePeso
   Source: MoneyParsableSpec.cs line 363
   Duration: 3 ms

  Message: 
    NodaMoney.InvalidCurrencyException : The requested operation expected the currency AUD, but the actual value was the currency ARS!
  Stack Trace: 
    Money.AssertIsSameCurrency(Money left, Money right) line 297
    Money.CompareTo(Money other) line 122
    ComparableTypeAssertions`1.Be(T expected, String because, Object[] becauseArgs)
    GivenIWantToTryParseImplicitCurrency.WhenParsingDollarSymbolInArgentina_ThenThisShouldReturnArgentinePeso() line 368

Money.ToString() fails for all currency with NotApplicable (-1) decimal places

When currency is inferred from the invariant culture, which has XDR as the currency code, ToString() throws because it's trying to setup a NumberFormatInfo with -1 DecimalDigits.

ToString() shouldn't throw, as per: https://docs.microsoft.com/en-us/dotnet/api/system.object.tostring?view=netcore-3.1#notes-to-inheritors

Either don't allow Money to be created with XDR, or use a workable value for DecimalDigits in CurrencyRegistry.

This will likely cause a problem for developers who don't need multicurrency support, but have a CI process using dotnet core SDK docker images where the default culture is the invariant culture.

As a side note, Unicode chose to use 2dp, even though ISO publication is N/A. Practically XDR probably needs decimal places. https://www.unicode.org/cldr/charts/latest/supplemental/detailed_territory_currency_information.html

Currency sign / symbol isn't always correct

These should be updated. Some examples:

  • Turkish lira (TRY) is now YTL, but is really ₺
  • United Arab Emirates dirham (AED) is now ¤, but is really د.إ
  • Philippine peso (PHP) is now P, but is really ₱

Can we use the build-in Region-info? Has a lot of info, but is it 100% accurate. Also depends on fonts.

Format using ISO Code

At the moment, ToString formats money using its currency symbol, but symbols can be ambiguous. Please add a method that formats money using its unambiguous currency code instead.

See wikipedia's section on formatting rules: https://en.wikipedia.org/wiki/ISO_4217#Position_of_ISO_4217_code_in_amounts

In my opinion, formatting using the ISO code should have been the default result of calling Money.ToString() and formatting using the currency symbol should have been the result of calling Money.ToString("C")

Serializing default Money property in a class (PR#70)

Some issue with serializing defaults in this PR.

Nice Newtonsoft dependency is removed. But worth mentioning if just doing a drop-in update, this is a breaking change for users who rely on JsonSerializerSetting to fine tune JSON output. For example CamelCasePropertyContractResolver. It'll no longer have effect on Amount and Currency properties.

[Fact]
public void DefaultMoney_should_roundtrip()
{
    var expected = new MyClass { Value = default };
    // var expected = new MyClass { Value = new Money(0, "USD") }; // This works

    var serializer = new DataContractSerializer(typeof(MyClass));
    using (var ms = new MemoryStream()) {
        serializer.WriteObject(ms, expected);
        ms.Position = 0;

        var clone = serializer.ReadObject(ms); // throws Currency code can't be null error
        expected.Value.Should().Be(0);
    }
}

[DataContract]
private class MyClass
{
    [DataMember]
    public Money Value { get; set; }
}

Bug: Serialization fails on Deserialize<Money> (JavaScriptSerializer)

When serializing/deserializing the Money-class, it throws an exception when it tries to set CurrencySymbol.

at System.Globalization.NumberFormatInfo.set_CurrencySymbol(String value)
at NodaMoney.Money.ConvertToString(String format, IFormatProvider formatProvider)
at NodaMoney.Money.ToString()

There's also a problem with formatting, the currency symbol for USD is appended last, when it's supposed to be first.

var c = new Money(100m, "USD");
Console.WriteLine(c.ToString()); // Generates 100,00 $

Serialized output from JavaScriptSerializer

{ 
  "Amount" : 100,
  "Currency" : { 
      "Code" : "USD",
      "DecimalDigits" : 2,
      "EnglishName" : "United States dollar",
      "MajorUnit" : 1,
      "MinorUnit" : 0.01,
      "Number" : "840",
      "Sign" : "$"
    }
}

Add capability to parse currency amounts given with suffixes (K, M, B, and T)

Allow to parse money with suffixes such as €126.36M, or -$2.45B. Four suffixes should be recognized: K, M, B, and T. They can be given in lower or upper case, but must directly follow the number to be interpreted as a multiplier suffix.

In this case K is thousand. The numeric value of Billion is culture dependent.

Serialize Money with Entity Framework Core 2.0

Hi,
Since Noda's Money is a struct type, we cannot use it as field type for our entities in our .Net Core 2.0 project, using Entity Framework Core 2.0.

Since EF Core 2.0 now fully supports owned entities, it would be great to be able to do that!

Could you advise us a way to do that?
Thanks

Make pluggable data providers for Exchange Rates possible

The class ExchangeRate makes it possible to convert money to different currencies. But you have to manually create these exchange rates to use them.

It would be nice to have a ExchangeRateProvider that can be implemented by users of the library to attach it to their favourite provider(s) of exchange rates.

Java money has some implementations that could be used as a start example

Nuget package update fails for NodaMoney.Serialization.AspNet to 0.6.0 for target NF4.5.2

Nuget package updater throws error when trying to update package from 0.5.0 to 0.6.0 .

Could not install package 'NodaMoney.Serialization.AspNet 0.6.0'. You are trying to install this package into a project that targets '.NETFramework,Version=v4.5.2', but the package does not contain any assembly references or content files that are compatible with that framework. For more information, contact the package author.

Money serialization fails

Serialization of the Money object failes if embedded in another object.

For example I have to following class

    [DataContract]
    public class Article
    {
        [DataMember]
        public int Id { get; set; }
        [DataMember]
        public string Name { get; set; }
        [DataMember]
        public Money Amount { get; set; }
    }

and the following object

var article = new Article
{
       Id = 123,
       Amount = Money.Euro(27.15),
       Name = "Foo"
};

will result in that xml string:

<Article xmlns="...">
    <Amount Amount="27.15" Currency="EUR"/>
    <Id>123</Id>
    <Name>Foo</Name>
</Article>

When reading that string NodaMoney complaints about the LocalName differing from "Money". It's Amount in my example...

Fix for rounded value in ExchangeRate

Hi! I'm using NodaMoney with custom currencies and exchange rates and was very happy to see that custom currencies can be initialized with a high number of decimals. Recently, however, I've discovered that the constructor of the ExchangeRate rounds the instantiated exchange rate value to 6 decimals, which essentially means that I won't be able to use this object for currency conversion, as we need exchange rates with more than 6 decimals.

The culprit is found in ExchangeRate.cs, line 33: Value = Math.Round(rate, 6); // value is a ratio

I've removed the rounding step in my local checkout, but this results in failing tests that involve ExchangeRates that are instantiated with the double data type (instead of decimal). I understand why that happens and why rounding is necessary for this data type, and therefore I would like to discuss the following:

  • Why are exchange rates rounded specifically to 6 decimals? (i.e. why six? That number seems arbitrary)
  • Why is there a constructor accepting a double in the first place? Especially in the Money domain, I think it would be logical to force the use of decimals when interacting with the library. I would vouch for removing this constructor.
  • If removing that constructor is not an option, then an alternative solution would be to add an additional parameter to that constructor indicating to which number of decimals the exchange rate should be rounded. Rounding it down to 6 decimals could be the default value; but hardcoding that value into the code is very nontransparent.

I'm very interested in hearing your opinions on this issue!

System.ArgumentOutOfRangeException when printing certain currencies

Version: 1.0.5

It seems that, with some currencies, an error is thrown as ToString is trying to use the DecimalDigits value of the currency, which isn't in the valid range of 0 to 99, inclusive.

Example

new NodaMoney.Money(636, "XAG").ToString()

The XAG currency seems to have a DecimalDigits value of NotApplicable

https://github.com/remyvd/NodaMoney/blob/4d3372c44746f65c0886fec142fd65d5fc4890ef/src/NodaMoney/CurrencyRegistry.cs#L271

which resolves to -1 as an integer, so when ToString is called, the following line in Money.GetFormatProvider throws an System.ArgumentOutOfRangeException

https://github.com/remyvd/NodaMoney/blob/8e0a22c110e8620d35a1374c4e6c8483689226fc/src/NodaMoney/Money.Formattable.cs#L61

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.