go-money

repository·master·Indexed 23 days ago

https://github.com/rhymond/go-money

A Go library for handling monetary values using the smallest currency unit to avoid floating-point precision errors. It provides precise operations for arithmetic, comparison, splitting, and allocation, along with support for ISO 4217 currency codes. The library includes features for formatting money for display, custom currency registration, and implements sql.Scanner and driver.Valuer for database storage.

Tokens
4K
Snippets
5
Records
27
Agent score
82%

What's inside go-money

  1. Initialize Money values

    master

    You can initialize a Money object in two ways:

    1. Using the smallest unit (integers): This is the recommended way to avoid floating-point errors. For example, 100 represents 1 unit of the currency (e.g., 100 cents for 1 pound).
    2. Using a float amount: Use NewFromFloat to initialize money using a direct decimal amount.

    Currency is specified using money.Currency instances, and constants are provided for all ISO 4217 currency codes (e.g., money.GBP, money.EUR).

  2. Format Money for display

    master

    Convert Money objects into human-readable strings or float64 values:

    • Display(): Returns a formatted string (e.g., €1,234,567.89).
    • AsMajorUnits(): Returns a float64 representing the amount in the currency's major unit (e.g., 1234567.89).
  3. Assert Money properties

    master

    Use these methods to check the state of a Money value:

    • IsZero(): Returns true if the value is zero.
    • IsPositive(): Returns true if the value is greater than zero.
    • IsNegative(): Returns true if the value is less than zero.
    pound := money.New(100, money.GBP)
    
    pound.IsZero()     // false
    pound.IsPositive() // true
    pound.IsNegative() // false
  4. Perform arithmetic operations on Money

    master

    Perform basic math on Money objects. All operations (except Multiply) require the currencies to match.

    Operations:

    • Add(other Money) (Money, error): Adds two money amounts.
    • Subtract(other Money) (Money, error): Subtracts one money amount from another.
    • Multiply(factor float64) Money: Multiplies the amount by a factor.
    • Absolute() Money: Returns the absolute value.
    • Negative() Money: Returns the negative value.
    pound := money.New(100, money.GBP)
    twoPounds := money.New(200, money.GBP)
    
    result, err := pound.Add(twoPounds)      // £3.00, nil
    result, err = pound.Subtract(twoPounds)  // -£1.00, nil
    result := pound.Multiply(2)               // £2.00
    result := pound.Absolute()                // £1.00 (if input was -100)
    result := pound.Negative()               // -£1.00
  5. Split and Allocate Money without rounding errors

    master

    To divide money among multiple parties without losing pennies to rounding, use Split or Allocate.

    Splitting: Split(n int) ([]Money, error) divides the money into n parts. Leftover pennies are distributed round-robin among the parties (the first parties in the slice receive the extra pennies).

    Allocation: Allocate(ratios ...int) ([]Money, error) divides money based on provided integer ratios. This is a variadic function that can accept ratios as separate arguments or a slice using the ... operator. It also uses the round-robin principle for leftover pennies.

  6. Compare Money values

    master

    The package provides several comparison methods. Note: Comparisons must be made between the same currency units. If currencies do not match, methods like Equals will return an error, and Compare will return ErrCurrencyMismatch.

    Comparison Methods:

    • Equals(other Money) (bool, error)
    • GreaterThan(other Money) (bool, error)
    • GreaterThanOrEqual(other Money) (bool, error)
    • LessThan(other Money) (bool, error)
    • LessThanOrEqual(other Money) (bool, error)
    • Compare(other Money) (int, error): Returns 1 if greater, -1 if less, and 0 if equal.
    pound := money.New(100, money.GBP)
    twoPounds := money.New(200, money.GBP)
    twoEuros := money.New(200, money.EUR)
    
    pound.GreaterThan(twoPounds) // false, nil
    pound.LessThan(twoPounds)   // true, nil
    twoPounds.Equals(twoEuros) // false, error: Currencies don't match
    twoPounds.Compare(pound)    // 1, nil
    pound.Compare(twoPounds)   // -1, nil
    pound.Compare(pound)        // 0, nil
    pound.Compare(twoEuros)     // pound.amount, ErrCurrencyMismatch
  7. Configure the database value separator

    master

    The go-money package uses a global variable DBMoneyValueSeparator to determine how Money instances are serialized to and deserialized from strings in the database.

    • DefaultDBMoneyValueSeparator: A constant set to |.
    • DBMoneyValueSeparator: The active separator used by Money.Value() and Money.Scan(). You can change this to a different character if your database storage requirements differ.
  8. Customizing JSON Marshalling/Unmarshalling

    master
    The money.Money type implements json.Marshaler and json.Unmarshaller. If you need to change how Money is serialized or deserialized, you can overwrite the package-level injection points:
  9. Lookup a currency by its code

    master
    Use GetCurrency(code string) to retrieve a *Currency from the built-in collection. The input code is case-insensitive and will be converted to uppercase. If the currency is not found in the internal registry, it returns nil.
  10. Split and Allocate Money

    master

    The library provides specialized methods for dividing money without losing subunits (pennies).

    • Split(n int): Divides the money into n parts. If the amount isn't perfectly divisible, leftover subunits are distributed round-robin to the first parties.
    • Allocate(rs ...int): Divides the money based on provided ratios. Leftover subunits are distributed round-robin to the first parties.
  11. Convert sub-units to major units with ToMajorUnits

    master

    The ToMajorUnits method converts an integer amount (representing the smallest sub-unit of a currency) into a float64 representing the major unit (e.g., converting cents to dollars). It uses the Fraction field defined in the Formatter to determine the scale.

    Example: If Fraction is 2, an amount of 100 becomes 1.0.