Repository navigation
Releases
2.9.0
Changed
- Breaking:
StandardRoundingandNoRoundingare nowsealed.IRoundingStrategyremains the extension point
for custom rounding. Money.Absreturns a value in the operand'sMoneyContextinstead of the current thread context.Splitreturns shares in the source value'sMoneyContextinstead of the current thread context, and rounds shares to
the context'sMaxScalewhen set, falling back to the currency's decimal digits. Splitting EUR in a context with
MaxScale4 now yields shares at 4 decimals. The shares still sum to the original amount.- The Saudi riyal (SAR) symbol is the Unicode 17.0 sign
.ر.س.andSRare alternative symbols. FastMoneyarithmetic that overflows, including++and--, throwsOverflowExceptionwith the message "Value was
either too large or too small for a FastMoney." and the arithmetic overflows as an inner exception.FastMoneyconstruction accepts the full range, -922,337,203,685,477.5808 to 922,337,203,685,477.5807. Amounts in the
last fraction above 922,337,203,685,477 no longer throwArgumentOutOfRangeException.CurrencyInfo.GetFormat(typeof(NumberFormatInfo))returns a shared, read-onlyNumberFormatInfowhen the source
culture is read-only. Mutating it throwsInvalidOperationException. A mutable culture or a caller-owned
NumberFormatInfostill gets a per-call clone.- Improved
Moneyperformance: construction 73% faster with no allocation, addition and subtraction 21% faster,
ToInt32/ToInt64about 89% faster,MoneyContext.CurrentContextover 83% faster. - Improved
FastMoneyperformance: construction 45% faster, division by a non-integerdecimal68% faster,SqlMoney
conversion over 92% faster, conversion to and fromMoneyabout 50% faster. - Improved formatting and parsing: formatting allocates only the result string (90% less memory) and
TryFormat(Span<char>)is allocation-free forC,G,I,NandF; parsing is allocation-free on .NET 9 and
later andTryParseno longer throws internally.
2.8.0
Added
GetCurrencyInfo()extension methods onCultureInfoandRegionInfofor easy access toCurrencyInfo
#32.Contextis now settable in an object initializer orwithexpression onMoneyandFastMoney, so an existing
value can be moved to anotherMoneyContext#120. The stored amount
is kept as-is and is not re-rounded, somoney with { Context = noRounding }reinterprets the value instead of
recalculating it.FastMoneyvalidates the new context and rejects aMaxScaleabove 4 or aPrecisionabove 19.MoneyJsonConverterhas a constructor taking aMoneyContext. Register such an instance in
JsonSerializerOptions.Convertersto control the context that deserialized values get. Create the context once and
reuse it, because creating one scans the registered contexts for an equivalent set of options.
Changed
- Breaking: Deserializing
Moneynow uses the currentMoneyContextinstead of a no-rounding context, so a
deserialized value behaves like a constructed one in arithmetic #119.
Amounts with more decimals than the currency allows are now rounded while reading. To keep the exact serialized amount,
deserialize inside a scope with theNoRoundingstrategy, or register aMoneyJsonConverterconfigured with such a
context inJsonSerializerOptions.Converters. Only System.Text.Json has that per-serializer opt-out; for
Newtonsoft.Json, XML,DataContractSerializerandBinaryFormattera scope is the only escape, so stored amounts with
more decimals than the current context allows now change value when read (EUR 0.005reads back asEUR 0.00). FastMoneynow validates the currency when it is set in an object initializer orwithexpression, throwing
InvalidCurrencyExceptionfor a currency needing more than 4 decimal places. Previously only the constructor checked.MoneyJsonConverterno longer claimsMoney?itself and lets System.Text.Json handle it through its own nullable
converter. A JSONnullread directly asMoneystill throwsJsonException.
2.7.0
Added
- FromMinorUnits and ToMinorUnits methods on Money and FastMoney #118.
Changed
- Improved performance for Money creation, arithmetic, and formatting (up to 30%) by encoding
MinorUnit = 2hint
directly into theCurrencystruct's 15th bit for faster rounding and lookups. - IRoundingStrategy.Round() uses Currency as a parameter instead of CurrencyInfo.
- Fixed
IntroductionOndate for SLE currency #117 by @General-66. - Compact format use given digits as significant digits where the default is 2,
values below 1000 are displayed as normal currency values where > 100 without decimals #111,
Removed
Currency.IsIso4217is removed, useCurrencyInfo.IsIso4217instead.
Full Changelog: 2.6.0...2.7.0
2.6.0
Added
- Support .NET 10.0
- Lower-case formats, like 'c/g/i' will do compact notation, like USD 1.2K, €3.4M (#111, #113)
- Formatting format 'I' will use the international currency symbol (US$), where 'C' will use the local currency code ($).
Changed
- ISO 4217 AMENDMENT NUMBER 180, Bulgaria will use EUR from 1 January 2026, and BGN will move to the historic list.
Full Changelog: 2.5.0...2.6.0
2.5.0
This is a big update where MoneyContext is added. Every created Money object now has the context in which it was created, and this MoneyContext can be configured to your specific context, like rounding, scales, etc. This would solve the issue that some users didn't want to round Money automatically.
But before using the MoneyContext, maybe the new FastMoney type is enough for your use case. FastMoney is a smaller type, based on long, with a fixed scale of four decimals.
And the final big change is the internal size of Money: Money is now the same size as a Decimal, a 16 bytes struct!
See the README for more info.
Added
- Add MoneyContext to configure money behavior like rounding, scale and precision. This can be specified globally,
per thread or by money instance. This should solve much of the discussion in issue #27 about internal rounding. - Add extra constructors on Money to create with a given MoneyContext, instead of MidpointRounding.
- Add MoneyContext property on Money.
- Add Scale property on Money.
- Add NodaMoney.DependencyInjection package to register MoneyContext .NET DI.
- Add the FastMoney struct, based on long, for a smaller footprint and faster operations with a default MoneyContext of { Precision = 19, MaxScale = 4, RoundingStrategy = new StandardRounding(MidpointRounding.ToEven) }.
Changed
- Optimized Money struct size. This was 18 bytes (padded 24 bytes), but is now 16 bytes (padded 16 bytes) (33% less).
This means Money is the same size as Decimal struct!!! - Improved Parsing: memory allocation (75% less) and performance (2x)
- Improved Increment(++) and Decrement(--): zero memory allocation (was 32 B) and performance (3x)
Removed
- IConvertible implementation for Money. Methods that don't make sense to convert from and to Money are removed, like ToBoolean, ToDateTime, etc.
- Removed From-methods and numeric casts on Money where constructors exist or are more appropriate, like FromDecimal, FromInt32 FromInt64, etc.
- Remove Money constructors and factory methods with MidpointRounding param for non-decimal numeric types, like
new Money(double, Currency, MidpointRounding).
Full Changelog: 2.3.0...2.5.0
2.3.0
Added
- CurrencyInfo.TryFromCode method to get CurrencyInfo from code without throwing an exception.
Full Changelog: 2.2.1...2.3.0
2.2.1
2.2.0
Added
- ISO 4217 AMENDMENT NUMBER 179, add new currency XAD for the Finance Department Arab Monetary Fund (AMF)
Changed
- Allow ExchangeRate to have the same currency as both base and quote by @gliljas in #103
- No rounding for Currencies where MinorUnit is NotApplicable, like
Currency(Info).NoCurrency(Breaking Change). - Updated System.Text.Json dependency to allow versions from 4.7.2 and up for better compatibility and flexibility.
Removed
- Removed NumberStyle param for Parse- and TryParse-methods (Breaking Change). Money expects to parse a Currency number. Pre-parse with Decimal.Parse() if more fine-grained control is needed.
- CurrencyInfo.MinorUnitAsExponentOfBase10 changed to internal (Breaking Change)
Full Changelog: 2.1.1...2.2.0
2.1.1
Added
- Allow creating Money using 'with' expression
- Add format N, Number format (e.g., "2,765.43")
- Add format F, Fixed point format (e.g., "2765,43")
- Add compatibility with Native AOT and Trimming
Changed
- Aligned the expiration date of the Netherlands Antillean guilder (ANG) with the amended timeline (ISO 4217 AMENDMENT NUMBER 176.)
- More defensive parsing in JSON converters by @gliljas in #102
- Migrate from SLN to SLNX solution file format
Removed
- Removed Microsoft.Bcl.HashCode dependency for .NET Standard 2.0
Full Changelog: 2.1.0...2.1.1
2.1.0
Added
- ISpanFormattable and IUtf8SpanFormattable implemented
- Partially implemented INumber by adding Radix, Zero, One, NegativeOne,
Abs(), IsNegative(), IsPositive(), IsZero(), MinMagnitude(), MaxMagnitude()
Changed
- Rename SafeDivide to Split and move in NodaMoney namespace (should have been in v2.0.0)
- NotNullWhenAttribute is now internal by @gliljas in #101
Full Changelog: 2.0.0...2.1.0