money

package module
v0.2.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 18, 2023 License: MIT Imports: 6 Imported by: 0

README

money

githubb codecovb goreportb godocb licenseb versionb awesomeb

Package money implements immutable monetary amounts and exchange rates for Go.

Features

  • Optimized Performance - Utilizes uint64 for coefficients, reducing heap allocations and memory consumption.
  • High Precision - Supports 19 digits of precision, which allows representation of amounts between -99,999,999,999,999,999.99 and 99,999,999,999,999,999.99 inclusive.
  • Immutability - Once an amount or exchange rate is set, it remains unchanged. This immutability ensures safe concurrent access across goroutines.
  • Banker's Rounding - Methods use half-to-even rounding, also known as "banker's rounding", which minimizes cumulative rounding errors commonly seen in financial calculations.
  • No Panics - All methods are designed to be panic-free. Instead of potentially crashing your application, they return errors for issues such as overflow, division by zero, or currency mismatch.
  • Correctness - Fuzz testing is used to cross-validate arithmetic operations against the cockroachdb and shopspring decimal packages.

Getting started

Installation

To add the money package to your Go workspace:

go get github.com/govalues/money
Usage

Create amount using one of the constructors. After creating a monetary amount, various operations can be performed:

package main

import (
    "fmt"
    "github.com/govalues/decimal"
    "github.com/govalues/money"
)

func main() {
    // Constructors
    a, _ := money.NewAmount("USD", 8, 0)               // a = USD 8.00
    b, _ := money.ParseAmount("USD", "12.5")           // b = USD 12.50
    c, _ := money.NewAmountFromFloat64("USD", 2.567)   // c = USD 2.567
    d, _ := money.NewAmountFromInt64("USD", 7, 896, 3) // d = USD 7.896
    r, _ := money.NewExchRate("USD", "EUR", 9, 1)      // r = USD/EUR 0.9
    x, _ := decimal.New(2, 0)                          // x = 2

    // Operations
    fmt.Println(a.Add(b))          // USD 8.00 + USD 12.50
    fmt.Println(a.Sub(b))          // USD 8.00 - USD 12.50

    fmt.Println(a.Mul(x))          // USD 8.00 * 2
    fmt.Println(a.FMA(x, b))       // USD 8.00 * 2 + USD 12.50
    fmt.Println(r.Conv(a))         // USD 8.00 * USD/EUR 0.9

    fmt.Println(a.Quo(x))          // USD 8.00 / 2
    fmt.Println(a.QuoRem(x))       // USD 8.00 div 2, USD 8.00 mod 2
    fmt.Println(a.Rat(b))          // USD 8.00 / USD 12.50
    fmt.Println(a.Split(3))        // USD 8.00 into 3 parts

    // Rounding to 2 decimal places
    fmt.Println(c.RoundToCurr())   // 2.57
    fmt.Println(c.CeilToCurr())    // 2.57
    fmt.Println(c.FloorToCurr())   // 2.56
    fmt.Println(c.TruncToCurr())   // 2.56

    // Conversions
    fmt.Println(d.Int64(9))        // 7 896000000
    fmt.Println(d.Float64())       // 7.896
    fmt.Println(d.String())        // USD 7.896

    // Formatting
    fmt.Printf("%v\n", d)          // USD 7.896
    fmt.Printf("%[1]f %[1]c\n", d) // 7.896 USD
    fmt.Printf("%f\n", d)          // 7.896
    fmt.Printf("%c\n", d)          // USD
    fmt.Printf("%d\n", d)          // 790
}

Documentation

For detailed documentation and additional examples, visit the package documentation.

Comparison

Comparison with other popular packages:

Feature govalues rhymond v1.0.10 bojanz v1.2.1
Speed High Medium Medium
Numeric Representation Floating Point Fixed Point Floating Point
Precision 19 digits 18 digits 39 digits
Default Rounding Half to even Not supported Half up
Overflow Control Yes No[^wrap] Yes
Support for Division Yes No Yes
Support for Currency Conversion Yes No Yes

[^wrap]: rhymond does not detect overflow and returns an invalid result. For example, 92,233,720,368,547,758.07 + 0.01 results in -92,233,720,368,547,758.08.

Benchmarks
goos: linux
goarch: amd64
pkg: github.com/govalues/money-tests
cpu: AMD Ryzen 7 3700C  with Radeon Vega Mobile Gfx 
Test Case Expression govalues rhymond v1.0.10 bojanz v1.2.1 govalues vs rhymond govalues vs bojanz
Add USD 2.00 + USD 3.00 22.95n 218.30n 144.10n +851.41% +528.02%
Mul USD 2.00 * 3 21.80n 133.40n 239.60n +511.79% +998.83%
QuoFinite USD 2.00 / 4 80.12n n/a[^nodiv] 468.05n n/a +484.19%
QuoInfinite USD 2.00 / 3 602.1n n/a[^nodiv] 512.4n n/a -14.91%
Split USD 2.00 into 10 parts 374.9n 897.0n n/a[^nosplit] +139.28% n/a
Conv USD 2.00 * USD/EUR 0.8 30.88n n/a[^noconv] 348.50n n/a +1028.38%
Parse USD 1 44.99n 139.50n 99.09n +210.07% +120.26%
Parse USD 123.456 61.45n 148.60n 240.90n +141.82% +292.03%
Parse USD 123456789.1234567890 131.2n 204.4n 253.0n +55.85% +92.87%
String USD 1 38.48n 200.70n 89.92n +421.50% +133.65%
String USD 123.456 56.34n 229.90n 127.05n +308.02% +125.49%
String USD 123456789.1234567890 84.73n 383.30n 277.55n +352.38% +227.57%
Telco see specification 224.2n n/a[^nofracmul] 1944.0n n/a +766.89%

[^nodiv]: rhymond does not support division.

[^noconv]: rhymond does not support currency conversion.

[^nofracmul]: rhymond does not support multiplication by a fraction.

[^nosplit]: bojanz does not support splitting into parts.

The benchmark results shown in the table are provided for informational purposes only and may vary depending on your specific use case.

Contributing

Interested in contributing? Here's how to get started:

  1. Fork and clone the repository.
  2. Implement your changes.
  3. Write tests to cover your changes.
  4. Ensure all tests pass with go test.
  5. Commit and push to your fork.
  6. Open a pull request detailing your changes.

Note: If you're considering significant changes, please open an issue first to discuss with the maintainers. This ensures alignment with the project's objectives and roadmap.

Documentation

Overview

Package money implements immutable amounts and exchange rates.

Representation

Currency is represented as an integer index into an in-memory array that stores properties defined by ISO 4217:

  • Code: a three-letter alphabetic code.
  • Num: a three-digit numeric code.
  • Scale: a non-negative integer indicating the number of digits after the decimal point needed to represent minor units of the currency.

The currently supported currencies use scales of 0, 2, or 3:

  • A scale of 0 indicates currencies without minor units. For example, the Japanese Yen does not have minor units.
  • A scale of 2 indicates currencies that use 2 digits to represent their minor units. For example, the US Dollar represents its minor unit, 1 cent, as 0.01 dollars.
  • A scale of 3 indicates currencies with 3 digits in their minor units. For instance, the minor unit of the Omani Rial, 1 baisa, is represented as 0.001 rials.

Amount is a struct with two fields:

  • Currency: a Currency in which the amount is denominated.
  • Amount: a decimal.Decimal representing the numeric value of the amount.

ExchangeRate is a struct with three fields:

  • Base: a Currency being exchanged.
  • Quote: a Currency being obtained in exchange for the base currency.
  • Rate: a positive decimal.Decimal representing how many units of the quote currency are needed to exchange for 1 unit of the base currency.

Constraints

The range of an amount is determined by the scale of its currency. Similarly, the range of an exchange rate is determined by the scale of its quote currency. Here are the ranges for scales 0, 2, and 3:

| Example      | Scale | Minimum                              | Maximum                             |
| ------------ | ----- | ------------------------------------ | ----------------------------------- |
| Japanese Yen | 0     | -9,999,999,999,999,999,999           | 9,999,999,999,999,999,999           |
| US Dollar    | 2     |    -99,999,999,999,999,999.99        |    99,999,999,999,999,999.99        |
| Omani Rial   | 3     |     -9,999,999,999,999,999.999       |     9,999,999,999,999,999.999       |

Subnoral numbers are not supported by the underlying decimal.Decimal type. Consequently, amounts and exchange rates between -0.00000000000000000005 and 0.00000000000000000005 inclusive are rounded to 0.

Conversions

The package provides methods for converting:

See the documentation for each method for more details.

Operations

Each arithmetic operation is carried out in two steps:

  1. The operation is initially performed using uint64 arithmetic. If no overflow occurs, the exact result is immediately returned. If an overflow does occur, the operation proceeds to step 2.

  2. The operation is repeated with increased precision using big.Int arithmetic. The result is then rounded to 19 digits. If no significant digits are lost during rounding, the inexact result is returned. If any significant digit is lost, an overflow error is returned.

Step 1 was introduced to improve performance by avoiding heap allocation for big.Int and the complexities associated with big.Int arithmetic. It is expected that, in transactional financial systems, the majority of arithmetic operations will successfully compute an exact result during step 1.

The following rules are used to determine the significance of digits during step 2:

Rounding

Implicit rounding is applied when a result exceeds 19 digits. In such cases, the result is rounded to 19 digits using half-to-even rounding. This method ensures that rounding errors are evenly distributed between rounding up and rounding down.

For all arithmetic operations, the result is the one that would be obtained by computing the exact mathematical result with infinite precision and then rounding it to 19 digits.

In addition to implicit rounding, the package provides several methods for explicit rounding:

See the documentation for each method for more details.

Errors

All methods are panic-free and pure. Errors are returned in the following cases:

  • Currency Mismatch. All arithmetic operations, except for Amount.Rat, return an error if the operands are denominated in different currencies.

  • Division by Zero. Unlike the standard library, Amount.Quo, Amount.QuoRem, Amount.Rat, and ExchangeRate.Inv do not panic when dividing by 0. Instead, they return an error.

  • Overflow. Unlike standard integers, there is no "wrap around" for amounts at certain sizes. Arithmetic operations return an error for out-of-range values.

  • Underflow. All arithmetic operations, except for ExchangeRate.Inv and ExchangeRate.Mul, do not return an error in case of underflow. If the result is an amount between -0.00000000000000000005 and 0.00000000000000000005 inclusive, it is rounded to 0. ExchangeRate.Inv and ExchangeRate.Mul return an error in cases of underflow, as the result of these operations is an exchange rate, and exchange rates cannot be 0.

Example (EffectiveRate)

This example calculates the effective interest rate for a 10% nominal interest rate compounded monthly on a USD 10,000 balance.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
	"github.com/govalues/money"
)

type StatementLine struct {
	Month    int
	Days     int
	Interest money.Amount
	Balance  money.Amount
}

type Statement []StatementLine

func (s Statement) Append(month, days int, interest, balance money.Amount) Statement {
	line := StatementLine{
		Month:    month,
		Days:     days,
		Interest: interest,
		Balance:  balance,
	}
	return append(s, line)
}

func (s Statement) IncomingBalance() (money.Amount, error) {
	if len(s) == 0 {
		return money.Amount{}, fmt.Errorf("empty statement")
	}
	a, err := s[0].Balance.Sub(s[0].Interest)
	if err != nil {
		return money.Amount{}, err
	}
	return a, nil
}

func (s Statement) OutgoingBalance() (money.Amount, error) {
	if len(s) == 0 {
		return money.Amount{}, fmt.Errorf("empty statement")
	}
	return s[len(s)-1].Balance, nil
}

// PercChange computes (OutgoingBalance - IncomingBalance) / IncomingBalance.
func (s Statement) PercChange() (decimal.Decimal, error) {
	inc, err := s.IncomingBalance()
	if err != nil {
		return decimal.Decimal{}, err
	}
	out, err := s.OutgoingBalance()
	if err != nil {
		return decimal.Decimal{}, err
	}
	diff, err := out.Sub(inc)
	if err != nil {
		return decimal.Decimal{}, err
	}
	rat, err := diff.Rat(inc)
	if err != nil {
		return decimal.Decimal{}, err
	}
	return rat, nil
}

func (s Statement) TotalInterest() (money.Amount, error) {
	if len(s) == 0 {
		return money.Amount{}, fmt.Errorf("empty statement")
	}
	var err error
	total := s[0].Interest
	for i := 1; i < len(s); i++ {
		total, err = total.Add(s[i].Interest)
		if err != nil {
			return money.Amount{}, err
		}
	}
	return total, nil
}

// DailyRate computes YearlyRate / 365.
func DailyRate(yearlyRate decimal.Decimal) (decimal.Decimal, error) {
	daysInYear, err := decimal.New(365, 0)
	if err != nil {
		return decimal.Decimal{}, err
	}
	dailyRate, err := yearlyRate.Quo(daysInYear)
	if err != nil {
		return decimal.Decimal{}, err
	}
	return dailyRate, nil
}

// MonthlyInterest computes Balance * DailyRate * DaysInMonth.
func MonthlyInterest(balance money.Amount, dailyRate decimal.Decimal, daysInMonth int) (money.Amount, error) {
	var err error
	interest := balance.Zero()
	for i := 0; i < daysInMonth; i++ {
		interest, err = balance.FMA(dailyRate, interest)
		if err != nil {
			return money.Amount{}, err
		}
	}
	interest = interest.RoundToCurr()
	return interest, nil
}

func SimulateStatement(balance money.Amount, yearlyRate decimal.Decimal) (Statement, error) {
	daysInMonths := [...]int{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
	dailyRate, err := DailyRate(yearlyRate)
	if err != nil {
		return nil, err
	}
	statement := Statement{}
	for m := 0; m < len(daysInMonths); m++ {

		interest, err := MonthlyInterest(balance, dailyRate, daysInMonths[m])
		if err != nil {
			return nil, err
		}

		balance, err = balance.Add(interest)
		if err != nil {
			return nil, err
		}

		statement = statement.Append(m+1, daysInMonths[m], interest, balance)
	}
	return statement, nil
}

func main() {
	// Set up initial balance and nominal interest rate
	initialBalance := money.MustParseAmount("USD", "10000")
	nominalRate := decimal.MustParse("0.10")

	// Display initial balance and nominal interest rate
	fmt.Printf("Initial Balance = %v\n", initialBalance)
	fmt.Printf("Nominal Rate    = %.2k\n\n", nominalRate)

	// Generate the simulated statement for a year
	statement, err := SimulateStatement(initialBalance, nominalRate)
	if err != nil {
		panic(err)
	}

	// Display monthly balances, including the interest accrued each month
	fmt.Printf("%-5s %-5s %-12s %s\n", "Month", "Days", "Interest", "Balance")
	for _, line := range statement {
		fmt.Printf("%5v %5v %+11f %11f\n", line.Month, line.Days, line.Interest, line.Balance)
	}

	// Calculate total interest accrued over the year and effective interest rate
	totalInterest, err := statement.TotalInterest()
	if err != nil {
		panic(err)
	}
	effRate, err := statement.PercChange()
	if err != nil {
		panic(err)
	}

	// Display the total interest accrued and the effective interest rate
	fmt.Printf("      Total %+11f\n\n", totalInterest)
	fmt.Printf("Effective Rate = %.4k\n", effRate)

}
Output:

Initial Balance = USD 10000.00
Nominal Rate    = 10.00%

Month Days  Interest     Balance
    1    31      +84.93    10084.93
    2    28      +77.36    10162.29
    3    31      +86.31    10248.60
    4    30      +84.24    10332.84
    5    31      +87.76    10420.60
    6    30      +85.65    10506.25
    7    31      +89.23    10595.48
    8    31      +89.99    10685.47
    9    30      +87.83    10773.30
   10    31      +91.50    10864.80
   11    30      +89.30    10954.10
   12    31      +93.03    11047.13
      Total    +1047.13

Effective Rate = 10.4713%
Example (LoanAmortization)

In this example, a loan amortization table is generated for a loan with an initial amount of USD 12,000, an annual interest rate of 10%, and a repayment period of 1 year.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
	"github.com/govalues/money"
)

type ScheduleLine struct {
	Month     int
	Repayment money.Amount
	Principal money.Amount
	Interest  money.Amount
	Balance   money.Amount
}

type AmortizationSchedule []ScheduleLine

func (p AmortizationSchedule) Append(month int, repayment, principal, interest, balance money.Amount) AmortizationSchedule {
	newLine := ScheduleLine{
		Month:     month,
		Repayment: repayment,
		Principal: principal,
		Interest:  interest,
		Balance:   balance,
	}
	return append(p, newLine)
}

func (p AmortizationSchedule) TotalRepayment() (money.Amount, error) {
	if len(p) == 0 {
		return money.Amount{}, fmt.Errorf("empty schedule")
	}
	var err error
	total := p[0].Repayment
	for i := 1; i < len(p); i++ {
		total, err = total.Add(p[i].Repayment)
		if err != nil {
			return money.Amount{}, err
		}
	}
	return total, nil
}

func (p AmortizationSchedule) TotalPrincipal() (money.Amount, error) {
	if len(p) == 0 {
		return money.Amount{}, fmt.Errorf("empty schedule")
	}
	var err error
	total := p[0].Principal
	for i := 1; i < len(p); i++ {
		total, err = total.Add(p[i].Principal)
		if err != nil {
			return money.Amount{}, err
		}
	}
	return total, nil
}

func (p AmortizationSchedule) TotalInterest() (money.Amount, error) {
	if len(p) == 0 {
		return money.Amount{}, fmt.Errorf("empty schedule")
	}
	var err error
	total := p[0].Interest
	for i := 1; i < len(p); i++ {
		total, err = total.Add(p[i].Interest)
		if err != nil {
			return money.Amount{}, err
		}
	}
	return total, nil
}

// MonthlyRate computes YearlyRate / 12.
func MonthlyRate(yearlyRate decimal.Decimal) (decimal.Decimal, error) {
	monthsInYear, err := decimal.New(12, 0)
	if err != nil {
		return decimal.Decimal{}, err
	}
	monthlyRate, err := yearlyRate.Quo(monthsInYear)
	if err != nil {
		return decimal.Decimal{}, err
	}
	return monthlyRate, nil
}

// AnnuityPayment computes Amount * Rate / (1 - (1 + Rate)^(-Periods)).
func AnnuityPayment(amount money.Amount, rate decimal.Decimal, periods int) (money.Amount, error) {
	one := rate.One()

	num, err := amount.Mul(rate)
	if err != nil {
		return money.Amount{}, err
	}

	den, err := rate.Add(one)
	if err != nil {
		return money.Amount{}, err
	}
	den, err = den.Pow(-periods)
	if err != nil {
		return money.Amount{}, err
	}
	den, err = one.Sub(den)
	if err != nil {
		return money.Amount{}, err
	}
	res, err := num.Quo(den)
	if err != nil {
		return money.Amount{}, err
	}
	return res.RoundToCurr(), nil
}

func SimulateSchedule(balance money.Amount, yearlyRate decimal.Decimal, years int) (AmortizationSchedule, error) {
	months := years * 12
	monthlyRate, err := MonthlyRate(yearlyRate)
	if err != nil {
		return nil, err
	}
	repayment, err := AnnuityPayment(balance, monthlyRate, months)
	if err != nil {
		return nil, err
	}
	schedule := AmortizationSchedule{}
	for i := 0; i < months; i++ {
		interest, err := balance.Mul(monthlyRate)
		if err != nil {
			return nil, err
		}
		interest = interest.RoundToCurr()
		principal, err := repayment.Sub(interest)
		if err != nil {
			return nil, err
		}
		balance, err = balance.Sub(principal)
		if err != nil {
			return nil, err
		}
		schedule = schedule.Append(i+1, repayment, principal, interest, balance)
	}
	return schedule, nil
}

func main() {
	// Set up initial loan balance and interest rate
	initialBalance := money.MustParseAmount("USD", "12000")
	yearlyRate := decimal.MustParse("0.10")
	years := 1

	// Display the initial loan balance and interest rate
	fmt.Printf("Initial Balance = %v\n", initialBalance)
	fmt.Printf("Interest Rate   = %.2k\n\n", yearlyRate)

	// Generate the amortization schedule
	schedule, err := SimulateSchedule(initialBalance, yearlyRate, years)
	if err != nil {
		panic(err)
	}

	// Display the amortization schedule, showing the monthly
	// repayment, principal, interest and outstanding loan balance
	fmt.Println("Month  Repayment   Principal   Interest    Outstanding")
	for _, line := range schedule {
		fmt.Printf("%5d %12f %11f %11f %11f\n", line.Month, line.Repayment, line.Principal, line.Interest, line.Balance)
	}

	// Calculate and display the total amounts repaid, both principal and interest
	totalRepayment, err := schedule.TotalRepayment()
	if err != nil {
		panic(err)
	}
	totalPrincipal, err := schedule.TotalPrincipal()
	if err != nil {
		panic(err)
	}
	totalInterest, err := schedule.TotalInterest()
	if err != nil {
		panic(err)
	}

	// Display the total repayment, principal repayment and interest payment over the loan period
	fmt.Printf("Total %12f %11f %11f\n", totalRepayment, totalPrincipal, totalInterest)

}
Output:

Initial Balance = USD 12000.00
Interest Rate   = 10.00%

Month  Repayment   Principal   Interest    Outstanding
    1      1054.99      954.99      100.00    11045.01
    2      1054.99      962.95       92.04    10082.06
    3      1054.99      970.97       84.02     9111.09
    4      1054.99      979.06       75.93     8132.03
    5      1054.99      987.22       67.77     7144.81
    6      1054.99      995.45       59.54     6149.36
    7      1054.99     1003.75       51.24     5145.61
    8      1054.99     1012.11       42.88     4133.50
    9      1054.99     1020.54       34.45     3112.96
   10      1054.99     1029.05       25.94     2083.91
   11      1054.99     1037.62       17.37     1046.29
   12      1054.99     1046.27        8.72        0.02
Total     12659.88    11999.98      659.90
Example (ParsingISO8583)

In this example, we parse the string "840D000000001234", which represents -12.34 USD, according to the specification for "DE54, Additional Amounts" in ISO 8583.

package main

import (
	"fmt"
	"strconv"

	"github.com/govalues/money"
)

func FromISO8583(s string) (money.Amount, error) {

	n, err := strconv.ParseInt(s[4:], 10, 64)
	if err != nil {
		return money.Amount{}, err
	}
	a, err := money.NewAmountFromMinorUnits(s[:3], n)
	if err != nil {
		return money.Amount{}, err
	}

	if s[3:4] == "D" {
		a = a.Neg()
	}
	return a, nil
}

func main() {
	a, _ := FromISO8583("840D000000001234")
	fmt.Println(a)
}
Output:

USD -12.34
Example (ParsingProtobuf)

This is an example of how to a parse a monetary amount formatted as money.proto.

package main

import (
	"fmt"

	"github.com/govalues/money"
)

func FromMoneyProto(curr string, units int64, nanos int32) (money.Amount, error) {
	return money.NewAmountFromInt64(curr, units, int64(nanos), 9)
}

func ToMoneyProto(a money.Amount) (curr string, units int64, nanos int32, ok bool) {
	curr = a.Curr().Code()
	whole, frac, ok := a.Int64(9)
	return curr, whole, int32(frac), ok
}

func main() {
	a, _ := FromMoneyProto("USD", 5, 670000000)
	fmt.Println(a)
	fmt.Println(ToMoneyProto(a))
}
Output:

USD 5.67
USD 5 670000000 true
Example (ParsingStripe)

This is an example of how to a parse a monetary amount formatted according to Stripe API specification.

package main

import (
	"fmt"
	"strings"

	"github.com/govalues/money"
)

func FromStripe(curr string, units int64) (money.Amount, error) {
	return money.NewAmountFromMinorUnits(curr, units)
}

func ToStripe(a money.Amount) (curr string, units int64, ok bool) {
	curr = strings.ToLower(a.Curr().Code())
	units, ok = a.MinorUnits()
	return curr, units, ok
}

func main() {
	a, _ := FromStripe("usd", 567)
	fmt.Println(a)
	fmt.Println(ToStripe(a))
}
Output:

USD 5.67
usd 567 true
Example (TaxCalculation)

In this example, the sales tax amount is calculated for a product with a given price after tax, using a specified tax rate.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
	"github.com/govalues/money"
)

func TaxAmount(price money.Amount, taxRate decimal.Decimal) (money.Amount, money.Amount, error) {

	one := taxRate.One()
	taxRate, err := taxRate.Add(one)
	if err != nil {
		return money.Amount{}, money.Amount{}, err
	}
	subtotal, err := price.Quo(taxRate)
	if err != nil {
		return money.Amount{}, money.Amount{}, err
	}

	subtotal = subtotal.TruncToCurr()

	tax, err := price.Sub(subtotal)
	if err != nil {
		return money.Amount{}, money.Amount{}, err
	}

	return subtotal, tax, nil
}

func main() {
	price := money.MustParseAmount("USD", "9.99")
	taxRate := decimal.MustParse("0.0725")

	subtotal, tax, err := TaxAmount(price, taxRate)
	if err != nil {
		panic(err)
	}

	fmt.Printf("Subtotal         = %v\n", subtotal)
	fmt.Printf("Sales tax %-6k = %v\n", taxRate, tax)
	fmt.Printf("Total price      = %v\n", price)
}
Output:

Subtotal         = USD 9.31
Sales tax 7.25%  = USD 0.68
Total price      = USD 9.99

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Amount

type Amount struct {
	// contains filtered or unexported fields
}

Amount type represents a monetary amount. Its zero value corresponds to "XXX 0", where XXX indicates an unknown currency. Amount is designed to be safe for concurrent use by multiple goroutines.

func MustNewAmount added in v0.1.0

func MustNewAmount(curr string, coef int64, scale int) Amount

MustNewAmount is like NewAmount but panics if the amount cannot be constructed. It simplifies safe initialization of global variables holding amounts.

Example (Currencies)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	fmt.Println(money.MustNewAmount("JPY", 567, 2))
	fmt.Println(money.MustNewAmount("USD", 567, 2))
	fmt.Println(money.MustNewAmount("OMR", 567, 2))
}
Output:

JPY 5.67
USD 5.67
OMR 5.670
Example (Scales)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	fmt.Println(money.MustNewAmount("USD", 567, 0))
	fmt.Println(money.MustNewAmount("USD", 567, 1))
	fmt.Println(money.MustNewAmount("USD", 567, 2))
	fmt.Println(money.MustNewAmount("USD", 567, 3))
	fmt.Println(money.MustNewAmount("USD", 567, 4))
}
Output:

USD 567.00
USD 56.70
USD 5.67
USD 0.567
USD 0.0567

func MustParseAmount

func MustParseAmount(curr, amount string) Amount

MustParseAmount is like ParseAmount but panics if any of the strings cannot be parsed. This function simplifies safe initialization of global variables holding amounts.

Example (Currencies)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	fmt.Println(money.MustParseAmount("JPY", "5.67"))
	fmt.Println(money.MustParseAmount("USD", "5.67"))
	fmt.Println(money.MustParseAmount("OMR", "5.67"))
}
Output:

JPY 5.67
USD 5.67
OMR 5.670
Example (Scales)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	fmt.Println(money.MustParseAmount("USD", "0.0567"))
	fmt.Println(money.MustParseAmount("USD", "0.567"))
	fmt.Println(money.MustParseAmount("USD", "5.67"))
	fmt.Println(money.MustParseAmount("USD", "56.7"))
	fmt.Println(money.MustParseAmount("USD", "567"))
}
Output:

USD 0.0567
USD 0.567
USD 5.67
USD 56.70
USD 567.00

func NewAmount

func NewAmount(curr string, coef int64, scale int) (Amount, error)

NewAmount returns an amount equal to coef / 10^scale. If the scale of the amount is less than the scale of the currency, the result will be zero-padded to the right.

NewAmount returns an error if:

  • the currency code is not valid;
  • the scale is negative or greater than decimal.MaxScale;
  • the integer part of the result has more than (decimal.MaxPrec - Currency.Scale) digits. For example, when currency is US Dollars, NewAmount will return an error if the integer part of the result has more than 17 digits (19 - 2 = 17).
Example (Currencies)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	fmt.Println(money.NewAmount("JPY", 567, 2))
	fmt.Println(money.NewAmount("USD", 567, 2))
	fmt.Println(money.NewAmount("OMR", 567, 2))
}
Output:

JPY 5.67 <nil>
USD 5.67 <nil>
OMR 5.670 <nil>
Example (Scales)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	fmt.Println(money.NewAmount("USD", 567, 0))
	fmt.Println(money.NewAmount("USD", 567, 1))
	fmt.Println(money.NewAmount("USD", 567, 2))
	fmt.Println(money.NewAmount("USD", 567, 3))
	fmt.Println(money.NewAmount("USD", 567, 4))
}
Output:

USD 567.00 <nil>
USD 56.70 <nil>
USD 5.67 <nil>
USD 0.567 <nil>
USD 0.0567 <nil>

func NewAmountFromDecimal added in v0.2.0

func NewAmountFromDecimal(curr Currency, amount decimal.Decimal) (Amount, error)

NewAmountFromDecimal returns an amount with the specified currency and value. If the scale of the amount is less than the scale of the currency, the result will be zero-padded to the right. See also method Amount.Decimal.

NewAmountFromDecimal returns an error if the integer part of the result has more than (decimal.MaxPrec - Currency.Scale) digits. For example, when currency is US Dollars, NewAmountFromDecimal will return an error if the integer part of the result has more than 17 digits (19 - 2 = 17).

Example
package main

import (
	"fmt"

	"github.com/govalues/decimal"
	"github.com/govalues/money"
)

func main() {
	d := decimal.MustParse("5.67")
	fmt.Println(money.NewAmountFromDecimal(money.JPY, d))
	fmt.Println(money.NewAmountFromDecimal(money.USD, d))
	fmt.Println(money.NewAmountFromDecimal(money.OMR, d))
}
Output:

JPY 5.67 <nil>
USD 5.67 <nil>
OMR 5.670 <nil>

func NewAmountFromFloat64 added in v0.2.0

func NewAmountFromFloat64(curr string, amount float64) (Amount, error)

NewAmountFromFloat64 converts a float to a (possibly rounded) amount. See also method Amount.Float64.

NewAmountFromFloat64 returns an error if:

  • the currency code is not valid;
  • the float is a special value (NaN or Inf);
  • the integer part of the result has more than (decimal.MaxPrec - Currency.Scale) digits. For example, when currency is US Dollars, NewAmountFromFloat64 will return an error if the integer part of the result has more than 17 digits (19 - 2 = 17).
Example (Currencies)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	fmt.Println(money.NewAmountFromFloat64("JPY", 5.67e0))
	fmt.Println(money.NewAmountFromFloat64("USD", 5.67e0))
	fmt.Println(money.NewAmountFromFloat64("OMR", 5.67e0))
}
Output:

JPY 5.67 <nil>
USD 5.67 <nil>
OMR 5.670 <nil>
Example (Scales)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	fmt.Println(money.NewAmountFromFloat64("USD", 5.67e-2))
	fmt.Println(money.NewAmountFromFloat64("USD", 5.67e-1))
	fmt.Println(money.NewAmountFromFloat64("USD", 5.67e0))
	fmt.Println(money.NewAmountFromFloat64("USD", 5.67e1))
	fmt.Println(money.NewAmountFromFloat64("USD", 5.67e2))
}
Output:

USD 0.0567 <nil>
USD 0.567 <nil>
USD 5.67 <nil>
USD 56.70 <nil>
USD 567.00 <nil>

func NewAmountFromInt64 added in v0.2.0

func NewAmountFromInt64(curr string, whole, frac int64, scale int) (Amount, error)

NewAmountFromInt64 converts a pair of integers, representing the whole and fractional parts, to a (possibly rounded) amount equal to whole + frac / 10^scale. NewAmountFromInt64 deletes trailing zeros up to the scale of the currency. This method is useful for converting amounts from protobuf format. See also method Amount.Int64.

NewAmountFromInt64 returns an error if:

  • the currency code is not valid;
  • the whole and fractional parts have different signs;
  • the scale is negative or greater than decimal.MaxScale;
  • frac / 10^scale is not within the range (-1, 1);
  • the integer part of the result has more than (decimal.MaxPrec - Currency.Scale) digits. For example, when currency is US Dollars, NewAmountFromInt64 will return an error if the integer part of the result has more than 17 digits (19 - 2 = 17).
Example (Currencies)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	fmt.Println(money.NewAmountFromInt64("JPY", 5, 67, 2))
	fmt.Println(money.NewAmountFromInt64("USD", 5, 67, 2))
	fmt.Println(money.NewAmountFromInt64("OMR", 5, 67, 2))
}
Output:

JPY 5.67 <nil>
USD 5.67 <nil>
OMR 5.670 <nil>
Example (Scales)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	fmt.Println(money.NewAmountFromInt64("USD", 5, 67, 2))
	fmt.Println(money.NewAmountFromInt64("USD", 5, 67, 3))
	fmt.Println(money.NewAmountFromInt64("USD", 5, 67, 4))
	fmt.Println(money.NewAmountFromInt64("USD", 5, 67, 5))
	fmt.Println(money.NewAmountFromInt64("USD", 5, 67, 6))
}
Output:

USD 5.67 <nil>
USD 5.067 <nil>
USD 5.0067 <nil>
USD 5.00067 <nil>
USD 5.000067 <nil>

func NewAmountFromMinorUnits added in v0.2.0

func NewAmountFromMinorUnits(curr string, units int64) (Amount, error)

NewAmountFromMinorUnits converts an integer, representing minor units of currency (e.g. cents, pennies, fens), to an amount. See also method Amount.MinorUnits.

NewAmountFromMinorUnits returns an error if currency code is not valid.

Example (Currencies)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	fmt.Println(money.NewAmountFromMinorUnits("JPY", 567))
	fmt.Println(money.NewAmountFromMinorUnits("USD", 567))
	fmt.Println(money.NewAmountFromMinorUnits("OMR", 567))
}
Output:

JPY 567 <nil>
USD 5.67 <nil>
OMR 0.567 <nil>
Example (Scales)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	fmt.Println(money.NewAmountFromMinorUnits("USD", 5))
	fmt.Println(money.NewAmountFromMinorUnits("USD", 56))
	fmt.Println(money.NewAmountFromMinorUnits("USD", 567))
	fmt.Println(money.NewAmountFromMinorUnits("USD", 5670))
	fmt.Println(money.NewAmountFromMinorUnits("USD", 56700))
}
Output:

USD 0.05 <nil>
USD 0.56 <nil>
USD 5.67 <nil>
USD 56.70 <nil>
USD 567.00 <nil>

func ParseAmount

func ParseAmount(curr, amount string) (Amount, error)

ParseAmount converts currency and decimal strings to a (possibly rounded) amount. If the scale of the amount is less than the scale of the currency, the result will be zero-padded to the right. See also constructors ParseCurr and decimal.Parse.

Example (Currencies)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	fmt.Println(money.ParseAmount("JPY", "5.67"))
	fmt.Println(money.ParseAmount("USD", "5.67"))
	fmt.Println(money.ParseAmount("OMR", "5.67"))
}
Output:

JPY 5.67 <nil>
USD 5.67 <nil>
OMR 5.670 <nil>
Example (Scales)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	fmt.Println(money.ParseAmount("USD", "0.0567"))
	fmt.Println(money.ParseAmount("USD", "0.567"))
	fmt.Println(money.ParseAmount("USD", "5.67"))
	fmt.Println(money.ParseAmount("USD", "56.7"))
	fmt.Println(money.ParseAmount("USD", "567"))
}
Output:

USD 0.0567 <nil>
USD 0.567 <nil>
USD 5.67 <nil>
USD 56.70 <nil>
USD 567.00 <nil>

func (Amount) Abs

func (a Amount) Abs() Amount

Abs returns the absolute value of the amount.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("USD", "-5.67")
	fmt.Println(a.Abs())
}
Output:

USD 5.67

func (Amount) Add

func (a Amount) Add(b Amount) (Amount, error)

Add returns the (possibly rounded) sum of amounts a and b.

Add returns an error if:

  • amounts are denominated in different currencies;
  • the integer part of the result has more than (decimal.MaxPrec - Currency.Scale) digits. For example, when currency is US Dollars, Add will return an error if the integer part of the result has more than 17 digits (19 - 2 = 17).
Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("USD", "5.67")
	b := money.MustParseAmount("USD", "23.00")
	fmt.Println(a.Add(b))
}
Output:

USD 28.67 <nil>

func (Amount) Ceil

func (a Amount) Ceil(scale int) Amount

Ceil returns an amount rounded up to the specified number of digits after the decimal point using rounding toward positive infinity. If the given scale is less than the scale of the currency, the amount will be rounded up to the scale of the currency instead. See also methods Amount.CeilToCurr, Amount.Floor.

Example (Currencies)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("JPY", "5.678")
	b := money.MustParseAmount("USD", "5.678")
	c := money.MustParseAmount("OMR", "5.678")
	fmt.Println(a.Ceil(0))
	fmt.Println(b.Ceil(0))
	fmt.Println(c.Ceil(0))
}
Output:

JPY 6
USD 5.68
OMR 5.678
Example (Scales)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("USD", "5.6789")
	fmt.Println(a.Ceil(0))
	fmt.Println(a.Ceil(1))
	fmt.Println(a.Ceil(2))
	fmt.Println(a.Ceil(3))
	fmt.Println(a.Ceil(4))
}
Output:

USD 5.68
USD 5.68
USD 5.68
USD 5.679
USD 5.6789

func (Amount) CeilToCurr

func (a Amount) CeilToCurr() Amount

CeilToCurr returns an amount rounded up to the scale of its currency using rounding toward positive infinity. See also methods Amount.Ceil, Amount.SameScaleAsCurr.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("JPY", "5.678")
	b := money.MustParseAmount("USD", "5.678")
	c := money.MustParseAmount("OMR", "5.678")
	fmt.Println(a.CeilToCurr())
	fmt.Println(b.CeilToCurr())
	fmt.Println(c.CeilToCurr())
}
Output:

JPY 6
USD 5.68
OMR 5.678

func (Amount) Clamp added in v0.2.0

func (a Amount) Clamp(min, max Amount) (Amount, error)

Clamp compares amounts and returns:

min if a < min
max if a > max
  d otherwise

See also method Amount.CmpTotal.

Clamp returns an error if:

  • amounts are denominated in different currencies;
  • min is greater than max numerically.
Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	min := money.MustParseAmount("USD", "-20")
	max := money.MustParseAmount("USD", "20")
	a := money.MustParseAmount("USD", "-5.67")
	b := money.MustParseAmount("USD", "0")
	c := money.MustParseAmount("USD", "23")
	fmt.Println(a.Clamp(min, max))
	fmt.Println(b.Clamp(min, max))
	fmt.Println(c.Clamp(min, max))
}
Output:

USD -5.67 <nil>
USD 0.00 <nil>
USD 20.00 <nil>

func (Amount) Cmp

func (a Amount) Cmp(b Amount) (int, error)

Cmp compares amounts and returns:

-1 if a < b
 0 if a = b
+1 if a > b

See also methods Amount.CmpAbs, Amount.CmpTotal.

Cmp returns an error if amounts are denominated in different currencies.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("USD", "-23.00")
	b := money.MustParseAmount("USD", "5.67")
	fmt.Println(a.Cmp(b))
	fmt.Println(a.Cmp(a))
	fmt.Println(b.Cmp(a))
}
Output:

-1 <nil>
0 <nil>
1 <nil>

func (Amount) CmpAbs added in v0.2.0

func (a Amount) CmpAbs(b Amount) (int, error)

CmpAbs compares absolute values of amounts and returns:

-1 if |a| < |b|
 0 if |a| = |b|
+1 if |a| > |b|

See also methods Amount.Cmp, Amount.CmpTotal.

CmpAbs returns an error if amounts are denominated in different currencies.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("USD", "-23.00")
	b := money.MustParseAmount("USD", "5.67")
	fmt.Println(a.CmpAbs(b))
	fmt.Println(a.CmpAbs(a))
	fmt.Println(b.CmpAbs(a))
}
Output:

1 <nil>
0 <nil>
-1 <nil>

func (Amount) CmpTotal

func (a Amount) CmpTotal(b Amount) (int, error)

CmpTotal compares the representation of amounts and returns:

-1 if a < b
-1 if a = b and a.scale > b.scale
 0 if a = b and a.scale = b.scale
+1 if a = b and a.scale < b.scale
+1 if a > b

See also methods Amount.Cmp, Amount.CmpAbs.

CmpTotal returns an error if amounts are denominated in different currencies.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("USD", "2.00")
	b := money.MustParseAmount("USD", "2.000")
	fmt.Println(a.CmpTotal(b))
	fmt.Println(a.CmpTotal(a))
	fmt.Println(b.CmpTotal(a))
}
Output:

1 <nil>
0 <nil>
-1 <nil>

func (Amount) CopySign

func (a Amount) CopySign(b Amount) Amount

CopySign returns an amount with the same sign as amount b. The currency of amount b is ignored. CopySign treates 0 as positive. See also method Amount.Sign.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("USD", "23.00")
	b := money.MustParseAmount("USD", "-5.67")
	fmt.Println(a.CopySign(b))
	fmt.Println(b.CopySign(a))
}
Output:

USD -23.00
USD 5.67

func (Amount) Curr

func (a Amount) Curr() Currency

Curr returns the currency of the amount.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("USD", "5.67")
	fmt.Println(a.Curr())
}
Output:

USD

func (Amount) Decimal added in v0.2.0

func (a Amount) Decimal() decimal.Decimal

Decimal returns the decimal representation of the amount.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("USD", "5.67")
	fmt.Println(a.Decimal())
}
Output:

5.67

func (Amount) FMA

func (a Amount) FMA(e decimal.Decimal, b Amount) (Amount, error)

FMA returns the (possibly rounded) fused multiply-addition of amounts a, b, and factor e. It computes a * e + b without any intermediate rounding. This method is useful for improving the accuracy and performance of algorithms that involve the accumulation of products, such as daily interest accrual.

FMA returns an error if:

  • amounts are denominated in different currencies;
  • the integer part of the result has more than (decimal.MaxPrec - Currency.Scale) digits. For example, when currency is US Dollars, FMA will return an error if the integer part of the result has more than 17 digits (19 - 2 = 17).
Example
package main

import (
	"fmt"

	"github.com/govalues/decimal"
	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("USD", "5.67")
	b := money.MustParseAmount("USD", "23.00")
	e := decimal.MustParse("2")
	fmt.Println(a.FMA(e, b))
}
Output:

USD 34.34 <nil>

func (Amount) Float64 added in v0.0.2

func (a Amount) Float64() (f float64, ok bool)

Float64 returns the nearest binary floating-point number rounded using rounding half to even (banker's rounding). See also constructor NewAmountFromFloat64.

This conversion may lose data, as float64 has a smaller precision than the decimal type.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("USD", "0.10")
	b := money.MustParseAmount("USD", "123.456")
	c := money.MustParseAmount("USD", "1234567890.123456789")
	fmt.Println(a.Float64())
	fmt.Println(b.Float64())
	fmt.Println(c.Float64())
}
Output:

0.1 true
123.456 true
1.2345678901234567e+09 true

func (Amount) Floor

func (a Amount) Floor(scale int) Amount

Floor returns an amount rounded down to the specified number of digits after the decimal point using rounding toward negative infinity. If the given scale is less than the scale of the currency, the amount will be rounded down to the scale of the currency instead. See also methods Amount.FloorToCurr, Amount.Ceil.

Example (Currencies)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("JPY", "5.678")
	b := money.MustParseAmount("USD", "5.678")
	c := money.MustParseAmount("OMR", "5.678")
	fmt.Println(a.Floor(0))
	fmt.Println(b.Floor(0))
	fmt.Println(c.Floor(0))
}
Output:

JPY 5
USD 5.67
OMR 5.678
Example (Scales)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("USD", "5.6789")
	fmt.Println(a.Floor(0))
	fmt.Println(a.Floor(1))
	fmt.Println(a.Floor(2))
	fmt.Println(a.Floor(3))
	fmt.Println(a.Floor(4))
}
Output:

USD 5.67
USD 5.67
USD 5.67
USD 5.678
USD 5.6789

func (Amount) FloorToCurr

func (a Amount) FloorToCurr() Amount

FloorToCurr returns an amount rounded down to the scale of its currency using rounding toward negative infinity. See also methods Amount.Floor, Amount.SameScaleAsCurr.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("JPY", "5.678")
	b := money.MustParseAmount("USD", "5.678")
	c := money.MustParseAmount("OMR", "5.678")
	fmt.Println(a.FloorToCurr())
	fmt.Println(b.FloorToCurr())
	fmt.Println(c.FloorToCurr())
}
Output:

JPY 5
USD 5.67
OMR 5.678

func (Amount) Format

func (a Amount) Format(state fmt.State, verb rune)

Format implements the fmt.Formatter interface. The following format verbs are available:

| Verb   | Example     | Description                |
| ------ | ----------- | -------------------------- |
| %s, %v | USD 5.678   | Currency and amount        |
| %q     | "USD 5.678" | Quoted currency and amount |
| %f     | 5.678       | Amount                     |
| %d     | 568         | Amount in minor units      |
| %c     | USD         | Currency                   |

The '-' format flag can be used with all verbs. The '+', ' ', '0' format flags can be used with all verbs except %c.

Precision is only supported for the %f verb. The default precision is equal to the actual scale of the amount.

Example (Currencies)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("JPY", "5")
	b := money.MustParseAmount("USD", "5")
	c := money.MustParseAmount("OMR", "5")
	fmt.Println("| v         | f     | d    | c   |")
	fmt.Println("| --------- | ----- | ---- | --- |")
	fmt.Printf("| %-9[1]v | %5[1]f | %4[1]d | %[1]c |\n", a)
	fmt.Printf("| %-9[1]v | %5[1]f | %4[1]d | %[1]c |\n", b)
	fmt.Printf("| %-9[1]v | %5[1]f | %4[1]d | %[1]c |\n", c)
}
Output:

| v         | f     | d    | c   |
| --------- | ----- | ---- | --- |
| JPY 5     |     5 |    5 | JPY |
| USD 5.00  |  5.00 |  500 | USD |
| OMR 5.000 | 5.000 | 5000 | OMR |
Example (Verbs)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("USD", "5.678")
	fmt.Printf("%v\n", a)
	fmt.Printf("%[1]f %[1]c\n", a)
	fmt.Printf("%f\n", a)
	fmt.Printf("%d\n", a)
	fmt.Printf("%c\n", a)
}
Output:

USD 5.678
5.678 USD
5.678
568
USD

func (Amount) Int64 added in v0.0.2

func (a Amount) Int64(scale int) (whole, frac int64, ok bool)

Int64 returns a pair of integers representing the whole and (possibly rounded) fractional parts of the amount. If given scale is greater than the scale of the amount, then the fractional part is zero-padded to the right. If given scale is smaller than the scale of the amount, then the fractional part is rounded using rounding half to even (banker's rounding). The relationship between the amount and the returned values can be expressed as a = whole + frac / 10^scale. This method is useful for converting amounts to protobuf format. See also constructor NewAmountFromInt64.

Int64 returns false if:

  • given scale is smaller than the scale of the currency;
  • the result cannot be represented as a pair of int64 values.
Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("USD", "5.678")
	fmt.Println(a.Int64(0))
	fmt.Println(a.Int64(1))
	fmt.Println(a.Int64(2))
	fmt.Println(a.Int64(3))
	fmt.Println(a.Int64(4))
}
Output:

0 0 false
0 0 false
5 68 true
5 678 true
5 6780 true

func (Amount) IsInt

func (a Amount) IsInt() bool

IsInt returns true if there are no significant digits after the decimal point.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("USD", "1.00")
	b := money.MustParseAmount("USD", "1.01")
	fmt.Println(a.IsInt())
	fmt.Println(b.IsInt())
}
Output:

true
false

func (Amount) IsNeg

func (a Amount) IsNeg() bool

IsNeg returns:

true  if a < 0
false otherwise
Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("USD", "-5.67")
	b := money.MustParseAmount("USD", "23.00")
	c := money.MustParseAmount("USD", "0.00")
	fmt.Println(a.IsNeg())
	fmt.Println(b.IsNeg())
	fmt.Println(c.IsNeg())
}
Output:

true
false
false

func (Amount) IsOne

func (a Amount) IsOne() bool

IsOne returns:

true  if a = -1 or a = 1
false otherwise
Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("USD", "1.00")
	b := money.MustParseAmount("USD", "2.00")
	fmt.Println(a.IsOne())
	fmt.Println(b.IsOne())
}
Output:

true
false

func (Amount) IsPos

func (a Amount) IsPos() bool

IsPos returns:

true  if a > 0
false otherwise
Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("USD", "-5.67")
	b := money.MustParseAmount("USD", "23.00")
	c := money.MustParseAmount("USD", "0.00")
	fmt.Println(a.IsPos())
	fmt.Println(b.IsPos())
	fmt.Println(c.IsPos())
}
Output:

false
true
false

func (Amount) IsZero

func (a Amount) IsZero() bool

IsZero returns:

true  if a = 0
false otherwise
Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("USD", "-5.67")
	b := money.MustParseAmount("USD", "23.00")
	c := money.MustParseAmount("USD", "0.00")
	fmt.Println(a.IsZero())
	fmt.Println(b.IsZero())
	fmt.Println(c.IsZero())
}
Output:

false
false
true

func (Amount) Max

func (a Amount) Max(b Amount) (Amount, error)

Max returns the larger amount. See also method Amount.CmpTotal.

Max returns an error if amounts are denominated in different currencies.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("USD", "23.00")
	b := money.MustParseAmount("USD", "-5.67")
	fmt.Println(a.Max(b))
}
Output:

USD 23.00 <nil>

func (Amount) Min

func (a Amount) Min(b Amount) (Amount, error)

Min returns the smaller amount. See also method Amount.CmpTotal.

Min returns an error if amounts are denominated in different currencies.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("USD", "23.00")
	b := money.MustParseAmount("USD", "-5.67")
	fmt.Println(a.Min(b))
}
Output:

USD -5.67 <nil>

func (Amount) MinScale added in v0.2.0

func (a Amount) MinScale() int

MinScale returns the smallest scale that the amount can be rescaled to without rounding. See also method Amount.Trim.

Example (Currencies)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("JPY", "5.0000")
	b := money.MustParseAmount("USD", "5.0000")
	c := money.MustParseAmount("OMR", "5.0000")
	fmt.Println(a.MinScale())
	fmt.Println(b.MinScale())
	fmt.Println(c.MinScale())
}
Output:

0
2
3
Example (Scales)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("USD", "5.6000")
	b := money.MustParseAmount("USD", "5.6700")
	c := money.MustParseAmount("USD", "5.6780")
	fmt.Println(a.MinScale())
	fmt.Println(b.MinScale())
	fmt.Println(c.MinScale())
}
Output:

2
2
3

func (Amount) MinorUnits

func (a Amount) MinorUnits() (units int64, ok bool)

MinorUnits returns a (possibly rounded) amount in minor units of currency (e.g. cents, pennies, fens). If the scale of the amount is greater than the scale of the currency, then the fractional part is rounded using rounding half to even (banker's rounding). See also constructor NewAmountFromMinorUnits.

If the result cannot be represented as an int64, then false is returned.

Example (Currencies)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("JPY", "5.678")
	b := money.MustParseAmount("USD", "5.678")
	c := money.MustParseAmount("OMR", "5.678")
	fmt.Println(a.MinorUnits())
	fmt.Println(b.MinorUnits())
	fmt.Println(c.MinorUnits())
}
Output:

6 true
568 true
5678 true
Example (Scales)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("USD", "0.0567")
	b := money.MustParseAmount("USD", "0.567")
	c := money.MustParseAmount("USD", "5.67")
	d := money.MustParseAmount("USD", "56.7")
	e := money.MustParseAmount("USD", "567")
	fmt.Println(a.MinorUnits())
	fmt.Println(b.MinorUnits())
	fmt.Println(c.MinorUnits())
	fmt.Println(d.MinorUnits())
	fmt.Println(e.MinorUnits())
}
Output:

6 true
57 true
567 true
5670 true
56700 true

func (Amount) Mul

func (a Amount) Mul(e decimal.Decimal) (Amount, error)

Mul returns the (possibly rounded) product of amount a and factor e.

Mul returns an error if the integer part of the result has more than (decimal.MaxPrec - Currency.Scale) digits. For example, when currency is US Dollars, Mul will return an error if the integer part of the result has more than 17 digits (19 - 2 = 17).

Example
package main

import (
	"fmt"

	"github.com/govalues/decimal"
	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("USD", "5.67")
	e := decimal.MustParse("2")
	fmt.Println(a.Mul(e))
}
Output:

USD 11.34 <nil>

func (Amount) Neg

func (a Amount) Neg() Amount

Neg returns an amount with the opposite sign.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("USD", "5.67")
	fmt.Println(a.Neg())
}
Output:

USD -5.67

func (Amount) One

func (a Amount) One() Amount

One returns an amount with a value of 1, having the same currency and scale as amount a. See also methods Amount.Zero, Amount.ULP.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("JPY", "5")
	b := money.MustParseAmount("JPY", "5.6")
	c := money.MustParseAmount("JPY", "5.67")
	fmt.Println(a.One())
	fmt.Println(b.One())
	fmt.Println(c.One())
}
Output:

JPY 1
JPY 1.0
JPY 1.00

func (Amount) Quantize

func (a Amount) Quantize(b Amount) (Amount, error)

Quantize returns an amount rescaled to the same scale as amount b. The currency and the sign of amount b are ignored. See also methods Amount.Scale, Amount.SameScale, Amount.Rescale.

Quantize returns an error if the integer part of the result has more than (decimal.MaxPrec - b.Scale()) digits.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("JPY", "5.678")
	x := money.MustParseAmount("JPY", "1")
	y := money.MustParseAmount("JPY", "0.1")
	z := money.MustParseAmount("JPY", "0.01")
	fmt.Println(a.Quantize(x))
	fmt.Println(a.Quantize(y))
	fmt.Println(a.Quantize(z))
}
Output:

JPY 6 <nil>
JPY 5.7 <nil>
JPY 5.68 <nil>

func (Amount) Quo

func (a Amount) Quo(e decimal.Decimal) (Amount, error)

Quo returns the (possibly rounded) quotient of amount a and divisor e. See also methods Amount.QuoRem, Amount.Rat, and Amount.Split.

Quo returns an error if:

  • the divisor is 0;
  • the integer part of the result has more than (decimal.MaxPrec - Currency.Scale) digits. For example, when currency is US Dollars, Quo will return an error if the integer part of the result has more than 17 digits (19 - 2 = 17).
Example
package main

import (
	"fmt"

	"github.com/govalues/decimal"
	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("USD", "5.67")
	e := decimal.MustParse("2")
	fmt.Println(a.Quo(e))
}
Output:

USD 2.835 <nil>

func (Amount) QuoRem added in v0.1.2

func (a Amount) QuoRem(e decimal.Decimal) (q, r Amount, err error)

QuoRem returns the quotient q and remainder r of amount a and divisor e such that a = e * q + r, where q has scale equal to the scale of its currency and the sign of the reminder r is the same as the sign of the dividend d. See also methods Amount.Quo, Amount.Rat, and Amount.Split.

QuoRem returns an error if:

  • the divisor is 0;
  • the integer part of the result has more than decimal.MaxPrec digits.
Example
package main

import (
	"fmt"

	"github.com/govalues/decimal"
	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("JPY", "5.67")
	b := money.MustParseAmount("USD", "5.67")
	c := money.MustParseAmount("OMR", "5.67")
	e := decimal.MustParse("2")
	fmt.Println(a.QuoRem(e))
	fmt.Println(b.QuoRem(e))
	fmt.Println(c.QuoRem(e))
}
Output:

JPY 2 JPY 1.67 <nil>
USD 2.83 USD 0.01 <nil>
OMR 2.835 OMR 0.000 <nil>

func (Amount) Rat

func (a Amount) Rat(b Amount) (decimal.Decimal, error)

Rat returns the (possibly rounded) ratio between amounts a and b. This method is particularly useful for calculating exchange rates between two currencies or determining percentages within a single currency. See also methods Amount.Quo, Amount.QuoRem, and Amount.Split.

Rat returns an error if:

  • the divisor is 0;
  • the integer part of the result has more than decimal.MaxPrec digits.
Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("EUR", "8")
	b := money.MustParseAmount("USD", "10")
	fmt.Println(a.Rat(b))
}
Output:

0.8 <nil>

func (Amount) Rescale added in v0.1.0

func (a Amount) Rescale(scale int) (Amount, error)

Rescale returns an amount rounded or zero-padded to the given number of digits after the decimal point. If the specified scale is less than the scale of the currency, the amount will be rounded to the scale of the currency instead. See also method Amount.Round.

Rescale returns an error if the integer part of the result more than (decimal.MaxPrec - scale) digits.

Example (Currencies)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("JPY", "5.678")
	b := money.MustParseAmount("USD", "5.678")
	c := money.MustParseAmount("OMR", "5.678")
	fmt.Println(a.Rescale(0))
	fmt.Println(b.Rescale(0))
	fmt.Println(c.Rescale(0))
}
Output:

JPY 6 <nil>
USD 5.68 <nil>
OMR 5.678 <nil>
Example (Scales)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("USD", "5.6789")
	fmt.Println(a.Rescale(0))
	fmt.Println(a.Rescale(1))
	fmt.Println(a.Rescale(2))
	fmt.Println(a.Rescale(3))
	fmt.Println(a.Rescale(4))
}
Output:

USD 5.68 <nil>
USD 5.68 <nil>
USD 5.68 <nil>
USD 5.679 <nil>
USD 5.6789 <nil>

func (Amount) Round

func (a Amount) Round(scale int) Amount

Round returns an amount rounded to the specified number of digits after the decimal point using rounding half to even (banker's rounding). If the given scale is less than the scale of the currency, the amount will be rounded to the scale of the currency instead. See also methods Amount.Rescale, Amount.RoundToCurr.

Example (Currencies)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("JPY", "5.678")
	b := money.MustParseAmount("USD", "5.678")
	c := money.MustParseAmount("OMR", "5.678")
	fmt.Println(a.Round(0))
	fmt.Println(b.Round(0))
	fmt.Println(c.Round(0))
}
Output:

JPY 6
USD 5.68
OMR 5.678
Example (Scales)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("USD", "5.6789")
	fmt.Println(a.Round(0))
	fmt.Println(a.Round(1))
	fmt.Println(a.Round(2))
	fmt.Println(a.Round(3))
	fmt.Println(a.Round(4))
}
Output:

USD 5.68
USD 5.68
USD 5.68
USD 5.679
USD 5.6789

func (Amount) RoundToCurr

func (a Amount) RoundToCurr() Amount

RoundToCurr returns an amount rounded to the scale of its currency using rounding half to even (banker's rounding). See also methods Amount.Round, Amount.SameScaleAsCurr.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("JPY", "5.678")
	b := money.MustParseAmount("USD", "5.678")
	c := money.MustParseAmount("OMR", "5.678")
	fmt.Println(a.RoundToCurr())
	fmt.Println(b.RoundToCurr())
	fmt.Println(c.RoundToCurr())
}
Output:

JPY 6
USD 5.68
OMR 5.678

func (Amount) SameCurr

func (a Amount) SameCurr(b Amount) bool

SameCurr returns true if amounts are denominated in the same currency. See also method Amount.Curr.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("JPY", "23")
	b := money.MustParseAmount("USD", "5.67")
	c := money.MustParseAmount("USD", "1.23")
	fmt.Println(a.SameCurr(b))
	fmt.Println(b.SameCurr(c))
}
Output:

false
true

func (Amount) SameScale

func (a Amount) SameScale(b Amount) bool

SameScale returns true if amounts have the same scale. See also methods Amount.Scale, Amount.Quantize.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("JPY", "23")
	b := money.MustParseAmount("USD", "5.67")
	c := money.MustParseAmount("USD", "1.23")
	fmt.Println(a.SameScale(b))
	fmt.Println(b.SameScale(c))
}
Output:

false
true

func (Amount) SameScaleAsCurr

func (a Amount) SameScaleAsCurr() bool

SameScaleAsCurr returns true if the scale of the amount is equal to the scale of its currency. See also methods Amount.Scale, Currency.Scale, Amount.RoundToCurr.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("USD", "5.67")
	b := money.MustParseAmount("USD", "5.678")
	c := money.MustParseAmount("USD", "5.6789")
	fmt.Println(a.SameScaleAsCurr())
	fmt.Println(b.SameScaleAsCurr())
	fmt.Println(c.SameScaleAsCurr())
}
Output:

true
false
false

func (Amount) Scale

func (a Amount) Scale() int

Scale returns the number of digits after the decimal point. See also method Amount.MinScale.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("USD", "23.0000")
	b := money.MustParseAmount("USD", "5.67")
	fmt.Println(a.Scale())
	fmt.Println(b.Scale())
}
Output:

4
2

func (Amount) Sign

func (a Amount) Sign() int

Sign returns:

-1 if a < 0
 0 if a = 0
+1 if a > 0
Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("USD", "-5.67")
	b := money.MustParseAmount("USD", "23.00")
	c := money.MustParseAmount("USD", "0.00")
	fmt.Println(a.Sign())
	fmt.Println(b.Sign())
	fmt.Println(c.Sign())
}
Output:

-1
1
0

func (Amount) Split

func (a Amount) Split(parts int) ([]Amount, error)

Split returns a slice of amounts that sum up to the original amount, ensuring the parts are as equal as possible. If the original amount cannot be divided equally among the specified number of parts, the remainder is distributed among the first parts of the slice. See also methods Amount.Quo, Amount.QuoRem, and Amount.Rat.

Split returns an error if the number of parts is not a positive integer.

Example (Parts)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("USD", "5.67")
	fmt.Println(a.Split(1))
	fmt.Println(a.Split(2))
	fmt.Println(a.Split(3))
	fmt.Println(a.Split(4))
	fmt.Println(a.Split(5))
}
Output:

[USD 5.67] <nil>
[USD 2.84 USD 2.83] <nil>
[USD 1.89 USD 1.89 USD 1.89] <nil>
[USD 1.42 USD 1.42 USD 1.42 USD 1.41] <nil>
[USD 1.14 USD 1.14 USD 1.13 USD 1.13 USD 1.13] <nil>
Example (Scales)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("USD", "0.0567")
	b := money.MustParseAmount("USD", "0.567")
	c := money.MustParseAmount("USD", "5.67")
	d := money.MustParseAmount("USD", "56.7")
	e := money.MustParseAmount("USD", "567")
	fmt.Println(a.Split(2))
	fmt.Println(b.Split(2))
	fmt.Println(c.Split(2))
	fmt.Println(d.Split(2))
	fmt.Println(e.Split(2))
}
Output:

[USD 0.0284 USD 0.0283] <nil>
[USD 0.284 USD 0.283] <nil>
[USD 2.84 USD 2.83] <nil>
[USD 28.35 USD 28.35] <nil>
[USD 283.50 USD 283.50] <nil>

func (Amount) String

func (a Amount) String() string

String implements the fmt.Stringer interface and returns a string representation of an amount. See also methods Currency.String, Decimal.String, Amount.Format.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("USD", "5.67")
	b := money.MustParseAmount("EUR", "-0.010000")
	fmt.Println(a.String())
	fmt.Println(b.String())
}
Output:

USD 5.67
EUR -0.010000

func (Amount) Sub

func (a Amount) Sub(b Amount) (Amount, error)

Sub returns the (possibly rounded) difference between amounts a and b.

Sub returns an error if:

  • amounts are denominated in different currencies;
  • the integer part of the result has more than (decimal.MaxPrec - Currency.Scale) digits. For example, when currency is US Dollars, Sub will return an error if the integer part of the result has more than 17 digits (19 - 2 = 17).
Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("USD", "5.67")
	b := money.MustParseAmount("USD", "23.00")
	fmt.Println(a.Sub(b))
}
Output:

USD -17.33 <nil>

func (Amount) SubAbs added in v0.2.0

func (a Amount) SubAbs(b Amount) (Amount, error)

SubAbs returns the (possibly rounded) absolute difference between amounts a and b.

SubAbs returns an error if:

  • amounts are denominated in different currencies;
  • the integer part of the result has more than (decimal.MaxPrec - Currency.Scale) digits. For example, when currency is US Dollars, SubAbs will return an error if the integer part of the result has more than 17 digits (19 - 2 = 17).
Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("USD", "5.67")
	b := money.MustParseAmount("USD", "23.00")
	fmt.Println(a.SubAbs(b))
}
Output:

USD 17.33 <nil>

func (Amount) Trim added in v0.1.0

func (a Amount) Trim(scale int) Amount

Trim returns an amount with trailing zeros removed up to the given scale. If the given scale is less than the scale of the currency, the zeros will be removed up to the scale of the currency instead. See also method Amount.TrimToCurr.

Example (Currencies)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("JPY", "5.000")
	b := money.MustParseAmount("USD", "5.000")
	c := money.MustParseAmount("OMR", "5.000")
	fmt.Println(a.Trim(0))
	fmt.Println(b.Trim(0))
	fmt.Println(c.Trim(0))
}
Output:

JPY 5
USD 5.00
OMR 5.000
Example (Scales)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("USD", "5.0000")
	fmt.Println(a.Trim(0))
	fmt.Println(a.Trim(1))
	fmt.Println(a.Trim(2))
	fmt.Println(a.Trim(3))
	fmt.Println(a.Trim(4))
}
Output:

USD 5.00
USD 5.00
USD 5.00
USD 5.000
USD 5.0000

func (Amount) TrimToCurr added in v0.1.0

func (a Amount) TrimToCurr() Amount

TrimToCurr returns an amount with trailing zeros removed up the scale of its currency. See also method Amount.Trim.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("JPY", "5.000")
	b := money.MustParseAmount("USD", "5.000")
	c := money.MustParseAmount("OMR", "5.000")
	fmt.Println(a.TrimToCurr())
	fmt.Println(b.TrimToCurr())
	fmt.Println(c.TrimToCurr())
}
Output:

JPY 5
USD 5.00
OMR 5.000

func (Amount) Trunc

func (a Amount) Trunc(scale int) Amount

Trunc returns an amount truncated to the specified number of digits after the decimal point using rounding toward zero. If the given scale is less than the scale of the currency, the amount will be truncated to the scale of the currency instead. See also method Amount.TruncToCurr.

Example (Currencies)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("JPY", "5.678")
	b := money.MustParseAmount("USD", "5.678")
	c := money.MustParseAmount("OMR", "5.678")
	fmt.Println(a.Trunc(0))
	fmt.Println(b.Trunc(0))
	fmt.Println(c.Trunc(0))
}
Output:

JPY 5
USD 5.67
OMR 5.678
Example (Scales)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("USD", "5.6789")
	fmt.Println(a.Trunc(0))
	fmt.Println(a.Trunc(1))
	fmt.Println(a.Trunc(2))
	fmt.Println(a.Trunc(3))
	fmt.Println(a.Trunc(4))
}
Output:

USD 5.67
USD 5.67
USD 5.67
USD 5.678
USD 5.6789

func (Amount) TruncToCurr

func (a Amount) TruncToCurr() Amount

TruncToCurr returns an amount truncated to the scale of its currency using rounding toward zero. See also methods Amount.Trunc, Amount.SameScaleAsCurr.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("JPY", "5.678")
	b := money.MustParseAmount("USD", "5.678")
	c := money.MustParseAmount("OMR", "5.678")
	fmt.Println(a.TruncToCurr())
	fmt.Println(b.TruncToCurr())
	fmt.Println(c.TruncToCurr())
}
Output:

JPY 5
USD 5.67
OMR 5.678

func (Amount) ULP

func (a Amount) ULP() Amount

ULP (Unit in the Last Place) returns the smallest representable positive difference between two amounts with the same scale as amount a. It can be useful for implementing rounding and comparison algorithms. See also methods Amount.Zero, Amount.One.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("JPY", "5")
	b := money.MustParseAmount("JPY", "5.6")
	c := money.MustParseAmount("JPY", "5.67")
	fmt.Println(a.ULP())
	fmt.Println(b.ULP())
	fmt.Println(c.ULP())
}
Output:

JPY 1
JPY 0.1
JPY 0.01

func (Amount) WithinOne

func (a Amount) WithinOne() bool

WithinOne returns:

true  if -1 < a < 1
false otherwise
Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("USD", "1.00")
	b := money.MustParseAmount("USD", "0.99")
	c := money.MustParseAmount("USD", "-1.00")
	fmt.Println(a.WithinOne())
	fmt.Println(b.WithinOne())
	fmt.Println(c.WithinOne())
}
Output:

false
true
false

func (Amount) Zero

func (a Amount) Zero() Amount

Zero returns an amount with a value of 0, having the same currency and scale as amount a. See also methods Amount.One, Amount.ULP.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("JPY", "5")
	b := money.MustParseAmount("JPY", "5.6")
	c := money.MustParseAmount("JPY", "5.67")
	fmt.Println(a.Zero())
	fmt.Println(b.Zero())
	fmt.Println(c.Zero())
}
Output:

JPY 0
JPY 0.0
JPY 0.00

type Currency

type Currency uint8

Currency type represents a currency in the global financial system. The zero value is "XXX", which indicates an unknown currency.

Currency is implemented as an integer index into an in-memory array that stores information such as code and scale. This design ensures safe concurrency for multiple goroutines accessing the same Currency value.

When persisting a currency value, use the alphabetic code returned by the Currency.Code method, rather than the integer index, as mapping between index and a particular currency may change in future versions.

const (
	XXX Currency = 0   // No Currency
	XTS Currency = 1   // Test Currency
	AED Currency = 2   // U.A.E. Dirham
	AFN Currency = 3   // Afghani
	ALL Currency = 4   // Lek
	AMD Currency = 5   // Armenian Dram
	ANG Currency = 6   // Netherlands Antillian Guilder
	AOA Currency = 7   // Kwanza
	ARS Currency = 8   // Argentine Peso
	AUD Currency = 9   // Australian Dollar
	AWG Currency = 10  // Aruban Guilder
	AZN Currency = 11  // Azerbaijan Manat
	BAM Currency = 12  // Convertible Mark
	BBD Currency = 13  // Barbados Dollar
	BDT Currency = 14  // Taka
	BGN Currency = 15  // Bulgarian Lev
	BHD Currency = 16  // Bahraini Dinar
	BIF Currency = 17  // Burundi Franc
	BMD Currency = 18  // Bermudian Dollar
	BND Currency = 19  // Brunei Dollar
	BOB Currency = 20  // Boliviano
	BRL Currency = 21  // Brazilian Real
	BSD Currency = 22  // Bahamian Dollar
	BTN Currency = 23  // Bhutan Ngultrum
	BWP Currency = 24  // Pula
	BYN Currency = 25  // Belarussian Ruble
	BZD Currency = 26  // Belize Dollar
	CAD Currency = 27  // Canadian Dollar
	CDF Currency = 28  // Franc Congolais
	CHF Currency = 29  // Swiss Franc
	CLP Currency = 30  // Chilean Peso
	CNY Currency = 31  // Yuan Renminbi
	COP Currency = 32  // Colombian Peso
	CRC Currency = 33  // Costa Rican Colon
	CUP Currency = 34  // Cuban Peso
	CVE Currency = 35  // Cape Verde Escudo
	CZK Currency = 36  // Czech Koruna
	DJF Currency = 37  // Djibouti Franc
	DKK Currency = 38  // Danish Krone
	DOP Currency = 39  // Dominican Peso
	DZD Currency = 40  // Algerian Dinar
	EGP Currency = 41  // Egyptian Pound
	ERN Currency = 42  // Eritean Nakfa
	ETB Currency = 43  // Ethiopian Birr
	EUR Currency = 44  // Euro
	FJD Currency = 45  // Fiji Dollar
	FKP Currency = 46  // Falkland Islands Pound
	GBP Currency = 47  // Pound Sterling
	GEL Currency = 48  // Lari
	GHS Currency = 49  // Cedi
	GIP Currency = 50  // Gibraltar Pound
	GMD Currency = 51  // Dalasi
	GNF Currency = 52  // Guinea Franc
	GTQ Currency = 53  // Quetzal
	GWP Currency = 54  // Guinea-Bissau Peso
	GYD Currency = 55  // Guyana Dollar
	HKD Currency = 56  // Hong Kong Dollar
	HNL Currency = 57  // Lempira
	HRK Currency = 58  // Croatian Kuna
	HTG Currency = 59  // Gourde
	HUF Currency = 60  // Forint
	IDR Currency = 61  // Rupiah
	ILS Currency = 62  // Israeli Shequel
	INR Currency = 63  // Indian Rupee
	IQD Currency = 64  // Iraqi Dinar
	IRR Currency = 65  // Iranian Rial
	ISK Currency = 66  // Iceland Krona
	JMD Currency = 67  // Jamaican Dollar
	JOD Currency = 68  // Jordanian Dinar
	JPY Currency = 69  // Yen
	KES Currency = 70  // Kenyan Shilling
	KGS Currency = 71  // Som
	KHR Currency = 72  // Riel
	KMF Currency = 73  // Comoro Franc
	KPW Currency = 74  // North Korean Won
	KRW Currency = 75  // Won
	KWD Currency = 76  // Kuwaiti Dinar
	KYD Currency = 77  // Cayman Islands Dollar
	KZT Currency = 78  // Tenge
	LAK Currency = 79  // Kip
	LBP Currency = 80  // Lebanese Pound
	LKR Currency = 81  // Sri Lanka Rupee
	LRD Currency = 82  // Liberian Dollar
	LSL Currency = 83  // Lesotho Loti
	LYD Currency = 84  // Libyan Dinar
	MAD Currency = 85  // Moroccan Dirham
	MDL Currency = 86  // Moldovan Leu
	MGA Currency = 87  // Malagasy Ariary
	MKD Currency = 88  // Denar
	MMK Currency = 89  // Kyat
	MNT Currency = 90  // Tugrik
	MOP Currency = 91  // Pataca
	MRU Currency = 92  // Ouguiya
	MUR Currency = 93  // Mauritius Rupee
	MVR Currency = 94  // Rufiyaa
	MWK Currency = 95  // Malawi Kwacha
	MXN Currency = 96  // Mexican Peso
	MYR Currency = 97  // Malaysian Ringgit
	MZN Currency = 98  // Mozambique Metical
	NAD Currency = 99  // Namibia Dollar
	NGN Currency = 100 // Naira
	NIO Currency = 101 // Cordoba Oro
	NOK Currency = 102 // Norwegian Krone
	NPR Currency = 103 // Nepalese Rupee
	NZD Currency = 104 // New Zealand Dollar
	OMR Currency = 105 // Rial Omani
	PAB Currency = 106 // Balboa
	PEN Currency = 107 // Sol
	PGK Currency = 108 // Kina
	PHP Currency = 109 // Philippine Peso
	PKR Currency = 110 // Pakistan Rupee
	PLN Currency = 111 // Zloty
	PYG Currency = 112 // Guarani
	QAR Currency = 113 // Qatari Rial
	RON Currency = 114 // Leu
	RSD Currency = 115 // Serbian Dinar
	RUB Currency = 116 // Russian Ruble
	RWF Currency = 117 // Rwanda Franc
	SAR Currency = 118 // Saudi Riyal
	SBD Currency = 119 // Solomon Islands Dollar
	SCR Currency = 120 // Seychelles Rupee
	SDG Currency = 121 // Sudanese Pound
	SEK Currency = 122 // Swedish Krona
	SGD Currency = 123 // Singapore Dollar
	SHP Currency = 124 // St. Helena Pound
	SLL Currency = 125 // Leone
	SOS Currency = 126 // Somali Shilling
	SRD Currency = 127 // Surinam Dollar
	SSP Currency = 128 // South Sudanese Pound
	STN Currency = 129 // Dobra
	SYP Currency = 130 // Syrian Pound
	SZL Currency = 131 // Lilangeni
	THB Currency = 132 // Baht
	TJS Currency = 133 // Somoni
	TMT Currency = 134 // Manat
	TND Currency = 135 // Tunisian Dinar
	TOP Currency = 136 // Pa'anga
	TRY Currency = 137 // Turkish Lira
	TTD Currency = 138 // Trinidad and Tobago Dollar
	TWD Currency = 139 // New Taiwan Dollar
	TZS Currency = 140 // Tanzanian Shilling
	UAH Currency = 141 // Ukrainian Hryvnia
	UGX Currency = 142 // Uganda Shilling
	USD Currency = 143 // U.S. Dollar
	UYU Currency = 144 // Peso Uruguayo
	UZS Currency = 145 // Uzbekistan Sum
	VES Currency = 146 // Sovereign Bolivar
	VND Currency = 147 // Dong
	VUV Currency = 148 // Vatu
	WST Currency = 149 // Tala
	XAF Currency = 150 // CFA Franc BEAC
	XCD Currency = 151 // East Caribbean Dollar
	XOF Currency = 152 // CFA Franc BCEAO
	XPF Currency = 153 // CFP Franc
	YER Currency = 154 // Yemeni Rial
	ZAR Currency = 155 // Rand
	ZMW Currency = 156 // Zambian Kwacha
	ZWL Currency = 157 // Zimbabwe Dollar
)

func MustParseCurr

func MustParseCurr(curr string) Currency

MustParseCurr is like ParseCurr but panics if the string cannot be parsed. It simplifies safe initialization of global variables holding currencies.

Example (Codes)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	fmt.Println(money.MustParseCurr("usd"))
	fmt.Println(money.MustParseCurr("USD"))
	fmt.Println(money.MustParseCurr("840"))
}
Output:

USD
USD
USD
Example (Currencies)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	fmt.Println(money.MustParseCurr("JPY"))
	fmt.Println(money.MustParseCurr("USD"))
	fmt.Println(money.MustParseCurr("OMR"))
}
Output:

JPY
USD
OMR

func ParseCurr

func ParseCurr(curr string) (Currency, error)

ParseCurr converts a string to currency. The input string must be in one of the following formats:

USD
usd
840

ParseCurr returns an error if the string does not represent a valid currency code.

Example (Codes)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	fmt.Println(money.ParseCurr("usd"))
	fmt.Println(money.ParseCurr("USD"))
	fmt.Println(money.ParseCurr("840"))
}
Output:

USD <nil>
USD <nil>
USD <nil>
Example (Currencies)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	fmt.Println(money.ParseCurr("JPY"))
	fmt.Println(money.ParseCurr("USD"))
	fmt.Println(money.ParseCurr("OMR"))
}
Output:

JPY <nil>
USD <nil>
OMR <nil>

func (Currency) Code

func (c Currency) Code() string

Code returns the 3-letter code assigned to the currency by the ISO 4217 standard. This code is a unique identifier of the currency and is used in international finance and commerce. This method always returns a valid code.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	j := money.JPY
	u := money.USD
	o := money.OMR
	fmt.Println(j.Code())
	fmt.Println(u.Code())
	fmt.Println(o.Code())
}
Output:

JPY
USD
OMR

func (Currency) Format

func (c Currency) Format(state fmt.State, verb rune)

Format implements the fmt.Formatter interface. The following format verbs are available:

| Verb       | Example | Description     |
| ---------- | ------- | --------------- |
| %c, %s, %v | USD     | Currency        |
| %q         | "USD"   | Quoted currency |

The '-' format flag can be used with all verbs.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	fmt.Printf("%c\n", money.USD)
}
Output:

USD

func (Currency) MarshalText

func (c Currency) MarshalText() ([]byte, error)

MarshalText implements encoding.TextMarshaler interface. Also see method Currency.String.

Example
package main

import (
	"encoding/json"
	"fmt"

	"github.com/govalues/money"
)

type Value struct {
	Currency money.Currency `json:"currency"`
}

func main() {
	v := Value{
		Currency: money.USD,
	}
	b, _ := json.Marshal(v)
	fmt.Println(string(b))
}
Output:

{"currency":"USD"}

func (Currency) Num

func (c Currency) Num() string

Num returns the 3-digit code assigned to the currency by the ISO 4217 standard. If the currency does not have such a code, the method will return an empty string.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	j := money.JPY
	u := money.USD
	o := money.OMR
	fmt.Println(j.Num())
	fmt.Println(u.Num())
	fmt.Println(o.Num())
}
Output:

392
840
512

func (Currency) Scale

func (c Currency) Scale() int

Scale returns the number of digits after the decimal point required for representing the minor unit of a currency. The currently supported currencies use scales of 0, 2, or 3:

  • A scale of 0 indicates currencies without minor units. For example, the Japanese Yen does not have minor units.
  • A scale of 2 indicates currencies that use 2 digits to represent their minor units. For example, the US Dollar represents its minor unit, 1 cent, as 0.01 dollars.
  • A scale of 3 indicates currencies with 3 digits in their minor units. For instance, the minor unit of the Omani Rial, 1 baisa, is represented as 0.001 rials.
Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	j := money.JPY
	u := money.USD
	o := money.OMR
	fmt.Println(j.Scale())
	fmt.Println(u.Scale())
	fmt.Println(o.Scale())
}
Output:

0
2
3

func (*Currency) Scan added in v0.1.3

func (c *Currency) Scan(v any) error

Scan implements the sql.Scanner interface. See also method ParseCurr.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	u := money.XXX
	_ = u.Scan("USD")
	fmt.Println(u)
}
Output:

USD

func (Currency) String

func (c Currency) String() string

String method implements the fmt.Stringer interface and returns a string representation of the Currency value. See also method Currency.Format.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	c := money.USD
	fmt.Println(c.String())
}
Output:

USD

func (*Currency) UnmarshalText

func (c *Currency) UnmarshalText(text []byte) error

UnmarshalText implements encoding.TextUnmarshaler interface. Also see method ParseCurr.

Example
package main

import (
	"encoding/json"
	"fmt"

	"github.com/govalues/money"
)

type Value struct {
	Currency money.Currency `json:"currency"`
}

func main() {
	var v Value
	_ = json.Unmarshal([]byte(`{"currency":"USD"}`), &v)
	fmt.Println(v)
}
Output:

{USD}

func (Currency) Value added in v0.1.3

func (c Currency) Value() (driver.Value, error)

Value implements the driver.Valuer interface. See also method Currency.String.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	u := money.USD
	fmt.Println(u.Value())
}
Output:

USD <nil>

type ExchangeRate

type ExchangeRate struct {
	// contains filtered or unexported fields
}

ExchangeRate represents a unidirectional exchange rate between two currencies. The zero value corresponds to an exchange rate of "XXX/XXX 0", where XXX indicates an unknown currency. This type is designed to be safe for concurrent use by multiple goroutines.

func MustNewExchRate added in v0.2.0

func MustNewExchRate(base, quote string, coef int64, scale int) ExchangeRate

MustNewExchRate is like NewExchRate but panics if the rate cannot be constructed. It simplifies safe initialization of global variables holding rates.

Example (Currencies)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	fmt.Println(money.MustNewExchRate("EUR", "JPY", 567, 2))
	fmt.Println(money.MustNewExchRate("EUR", "USD", 567, 2))
	fmt.Println(money.MustNewExchRate("EUR", "OMR", 567, 2))
}
Output:

EUR/JPY 5.67
EUR/USD 5.67
EUR/OMR 5.670
Example (Scales)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	fmt.Println(money.MustNewExchRate("EUR", "USD", 567, 0))
	fmt.Println(money.MustNewExchRate("EUR", "USD", 567, 1))
	fmt.Println(money.MustNewExchRate("EUR", "USD", 567, 2))
	fmt.Println(money.MustNewExchRate("EUR", "USD", 567, 3))
	fmt.Println(money.MustNewExchRate("EUR", "USD", 567, 4))
}
Output:

EUR/USD 567.00
EUR/USD 56.70
EUR/USD 5.67
EUR/USD 0.567
EUR/USD 0.0567

func MustParseExchRate

func MustParseExchRate(base, quote, rate string) ExchangeRate

MustParseExchRate is like ParseExchRate but panics if any of the strings cannot be parsed. It simplifies safe initialization of global variables holding exchange rates.

Example (Currencies)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	fmt.Println(money.MustParseExchRate("EUR", "JPY", "5.67"))
	fmt.Println(money.MustParseExchRate("EUR", "USD", "5.67"))
	fmt.Println(money.MustParseExchRate("EUR", "OMR", "5.67"))
}
Output:

EUR/JPY 5.67
EUR/USD 5.67
EUR/OMR 5.670
Example (Scales)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	fmt.Println(money.MustParseExchRate("EUR", "USD", "0.0567"))
	fmt.Println(money.MustParseExchRate("EUR", "USD", "0.567"))
	fmt.Println(money.MustParseExchRate("EUR", "USD", "5.67"))
	fmt.Println(money.MustParseExchRate("EUR", "USD", "56.7"))
	fmt.Println(money.MustParseExchRate("EUR", "USD", "567"))
}
Output:

EUR/USD 0.0567
EUR/USD 0.567
EUR/USD 5.67
EUR/USD 56.70
EUR/USD 567.00

func NewExchRate

func NewExchRate(base, quote string, coef int64, scale int) (ExchangeRate, error)

NewExchRate returns a rate equal to coef / 10^scale. If the scale of the rate is less than the scale of the quote currency, the result will be zero-padded to the right.

NewExchRate returns an error if:

  • the currency codes are not valid;
  • the coefficient is 0 or negative
  • the scale is negative or greater than decimal.MaxScale;
  • the integer part of the result has more than (decimal.MaxPrec - Currency.Scale) digits. For example, when the quote currency is US Dollars, NewAmount will return an error if the integer part of the result has more than 17 digits (19 - 2 = 17).
Example (Currencies)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	fmt.Println(money.NewExchRate("EUR", "JPY", 567, 2))
	fmt.Println(money.NewExchRate("EUR", "USD", 567, 2))
	fmt.Println(money.NewExchRate("EUR", "OMR", 567, 2))
}
Output:

EUR/JPY 5.67 <nil>
EUR/USD 5.67 <nil>
EUR/OMR 5.670 <nil>
Example (Scales)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	fmt.Println(money.NewExchRate("EUR", "USD", 567, 0))
	fmt.Println(money.NewExchRate("EUR", "USD", 567, 1))
	fmt.Println(money.NewExchRate("EUR", "USD", 567, 2))
	fmt.Println(money.NewExchRate("EUR", "USD", 567, 3))
	fmt.Println(money.NewExchRate("EUR", "USD", 567, 4))
}
Output:

EUR/USD 567.00 <nil>
EUR/USD 56.70 <nil>
EUR/USD 5.67 <nil>
EUR/USD 0.567 <nil>
EUR/USD 0.0567 <nil>

func NewExchRateFromDecimal added in v0.2.0

func NewExchRateFromDecimal(base, quote Currency, rate decimal.Decimal) (ExchangeRate, error)

NewExchRateFromDecimal returns a rate with the specified currencies and value. If the scale of the rate is less than the scale of quote currency, the result will be zero-padded to the right. See also method ExchangeRate.Decimal.

NewExchRateFromDecimal returns an error if the integer part of the result has more than (decimal.MaxPrec - Currency.Scale) digits. For example, when the quote currency is US Dollars, NewExchRateFromDecimal will return an error if the integer part of the result has more than 17 digits (19 - 2 = 17).

Example
package main

import (
	"fmt"

	"github.com/govalues/decimal"
	"github.com/govalues/money"
)

func main() {
	r := decimal.MustParse("5.67")
	fmt.Println(money.NewExchRateFromDecimal(money.EUR, money.JPY, r))
	fmt.Println(money.NewExchRateFromDecimal(money.EUR, money.USD, r))
	fmt.Println(money.NewExchRateFromDecimal(money.EUR, money.OMR, r))
}
Output:

EUR/JPY 5.67 <nil>
EUR/USD 5.67 <nil>
EUR/OMR 5.670 <nil>

func NewExchRateFromFloat64 added in v0.2.0

func NewExchRateFromFloat64(base, quote string, rate float64) (ExchangeRate, error)

NewExchRateFromFloat64 converts a float to a (possibly rounded) rate. See also method ExchangeRate.Float64.

NewExchRateFromFloat64 returns an error if:

  • the currency codes are not valid;
  • the float is a 0 or negative;
  • the float is a special value (NaN or Inf);
  • the integer part of the result has more than (decimal.MaxPrec - Currency.Scale) digits. For example, when the quote currency is US Dollars, NewExchRateFromFloat64 will return an error if the integer part of the result has more than 17 digits (19 - 2 = 17).
Example (Currencies)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	fmt.Println(money.NewExchRateFromFloat64("EUR", "JPY", 5.67e0))
	fmt.Println(money.NewExchRateFromFloat64("EUR", "USD", 5.67e0))
	fmt.Println(money.NewExchRateFromFloat64("EUR", "OMR", 5.67e0))
}
Output:

EUR/JPY 5.67 <nil>
EUR/USD 5.67 <nil>
EUR/OMR 5.670 <nil>
Example (Scales)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	fmt.Println(money.NewExchRateFromFloat64("EUR", "USD", 5.67e-2))
	fmt.Println(money.NewExchRateFromFloat64("EUR", "USD", 5.67e-1))
	fmt.Println(money.NewExchRateFromFloat64("EUR", "USD", 5.67e0))
	fmt.Println(money.NewExchRateFromFloat64("EUR", "USD", 5.67e1))
	fmt.Println(money.NewExchRateFromFloat64("EUR", "USD", 5.67e2))
}
Output:

EUR/USD 0.0567 <nil>
EUR/USD 0.567 <nil>
EUR/USD 5.67 <nil>
EUR/USD 56.70 <nil>
EUR/USD 567.00 <nil>

func NewExchRateFromInt64 added in v0.2.0

func NewExchRateFromInt64(base, quote string, whole, frac int64, scale int) (ExchangeRate, error)

NewExchRateFromInt64 converts a pair of integers, representing the whole and fractional parts, to a (possibly rounded) rate equal to whole + frac / 10^scale. NewExchRateFromInt64 deletes trailing zeros up to the scale of the quote currency. This method is useful for converting rates from protobuf format. See also method ExchangeRate.Int64.

NewExchRateFromInt64 returns an error if:

  • the currency codes are not valid;
  • the whole part is negative;
  • the fractional part is negative;
  • the scale is negative or greater than decimal.MaxScale;
  • frac / 10^scale is not within the range (-1, 1);
  • the integer part of the result has more than (decimal.MaxPrec - Currency.Scale) digits. For example, when the quote currency is US Dollars, NewAmountFromInt64 will return an error if the integer part of the result has more than 17 digits (19 - 2 = 17).
Example (Currencies)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	fmt.Println(money.NewExchRateFromInt64("EUR", "JPY", 5, 67, 2))
	fmt.Println(money.NewExchRateFromInt64("EUR", "USD", 5, 67, 2))
	fmt.Println(money.NewExchRateFromInt64("EUR", "OMR", 5, 67, 2))
}
Output:

EUR/JPY 5.67 <nil>
EUR/USD 5.67 <nil>
EUR/OMR 5.670 <nil>
Example (Scales)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	fmt.Println(money.NewExchRateFromInt64("EUR", "USD", 5, 67, 2))
	fmt.Println(money.NewExchRateFromInt64("EUR", "USD", 5, 67, 3))
	fmt.Println(money.NewExchRateFromInt64("EUR", "USD", 5, 67, 4))
	fmt.Println(money.NewExchRateFromInt64("EUR", "USD", 5, 67, 5))
	fmt.Println(money.NewExchRateFromInt64("EUR", "USD", 5, 67, 6))
}
Output:

EUR/USD 5.67 <nil>
EUR/USD 5.067 <nil>
EUR/USD 5.0067 <nil>
EUR/USD 5.00067 <nil>
EUR/USD 5.000067 <nil>

func ParseExchRate

func ParseExchRate(base, quote, rate string) (ExchangeRate, error)

ParseExchRate converts currency and decimal strings to a (possibly rounded) rate. If the scale of the rate is less than the scale of the quote currency, the result will be zero-padded to the right. See also constructors ParseCurr and decimal.Parse.

Example (Currencies)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	fmt.Println(money.ParseExchRate("EUR", "JPY", "5.67"))
	fmt.Println(money.ParseExchRate("EUR", "USD", "5.67"))
	fmt.Println(money.ParseExchRate("EUR", "OMR", "5.67"))
}
Output:

EUR/JPY 5.67 <nil>
EUR/USD 5.67 <nil>
EUR/OMR 5.670 <nil>
Example (Scales)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	fmt.Println(money.ParseExchRate("EUR", "USD", "0.0567"))
	fmt.Println(money.ParseExchRate("EUR", "USD", "0.567"))
	fmt.Println(money.ParseExchRate("EUR", "USD", "5.67"))
	fmt.Println(money.ParseExchRate("EUR", "USD", "56.7"))
	fmt.Println(money.ParseExchRate("EUR", "USD", "567"))
}
Output:

EUR/USD 0.0567 <nil>
EUR/USD 0.567 <nil>
EUR/USD 5.67 <nil>
EUR/USD 56.70 <nil>
EUR/USD 567.00 <nil>

func (ExchangeRate) Base

func (r ExchangeRate) Base() Currency

Base returns the currency being exchanged.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	r := money.MustParseExchRate("EUR", "USD", "1.2500")
	fmt.Println(r.Base())
}
Output:

EUR

func (ExchangeRate) CanConv

func (r ExchangeRate) CanConv(b Amount) bool

CanConv returns true if ExchangeRate.Conv can be used to convert the given amount.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	r := money.MustParseExchRate("USD", "EUR", "0.9000")
	a := money.MustParseAmount("USD", "123.00")
	b := money.MustParseAmount("EUR", "456.00")
	c := money.MustParseAmount("JPY", "789")
	fmt.Println(r.CanConv(a))
	fmt.Println(r.CanConv(b))
	fmt.Println(r.CanConv(c))
}
Output:

true
false
false

func (ExchangeRate) Ceil added in v0.2.0

func (r ExchangeRate) Ceil(scale int) (ExchangeRate, error)

Ceil returns a rate rounded up to the specified number of digits after the decimal point using rounding toward positive infinity. If the given scale is less than the scale of the quote currency, the rate will be rounded up to the scale of the quote currency instead. See also method ExchangeRate.Floor.

Example (Currencies)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	r := money.MustParseExchRate("EUR", "JPY", "5.678")
	q := money.MustParseExchRate("EUR", "USD", "5.678")
	p := money.MustParseExchRate("EUR", "OMR", "5.678")
	fmt.Println(r.Ceil(0))
	fmt.Println(q.Ceil(0))
	fmt.Println(p.Ceil(0))
}
Output:

EUR/JPY 6 <nil>
EUR/USD 5.68 <nil>
EUR/OMR 5.678 <nil>
Example (Scales)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	r := money.MustParseExchRate("EUR", "USD", "5.6789")
	fmt.Println(r.Ceil(0))
	fmt.Println(r.Ceil(1))
	fmt.Println(r.Ceil(2))
	fmt.Println(r.Ceil(3))
	fmt.Println(r.Ceil(4))
}
Output:

EUR/USD 5.68 <nil>
EUR/USD 5.68 <nil>
EUR/USD 5.68 <nil>
EUR/USD 5.679 <nil>
EUR/USD 5.6789 <nil>

func (ExchangeRate) Conv

func (r ExchangeRate) Conv(b Amount) (Amount, error)

Conv returns a (possibly rounded) amount converted from the base currency to the quote currency. See also method ExchangeRate.CanConv.

Conv returns an error if:

  • the base currency of the exchange rate does not match the currency of the given amount.
  • the integer part of the result has more than (decimal.MaxPrec - Currency.Scale) digits. For example, when converting to US Dollars, Conv will return an error if the integer part of the result has more than 17 digits (19 - 2 = 17).
Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseAmount("EUR", "100.00")
	r := money.MustParseExchRate("EUR", "JPY", "160.00")
	q := money.MustParseExchRate("EUR", "USD", "1.2500")
	p := money.MustParseExchRate("EUR", "OMR", "0.42000")
	fmt.Println(r.Conv(a))
	fmt.Println(q.Conv(a))
	fmt.Println(p.Conv(a))
}
Output:

JPY 16000.0000 <nil>
USD 125.000000 <nil>
OMR 42.0000000 <nil>

func (ExchangeRate) Decimal added in v0.2.0

func (r ExchangeRate) Decimal() decimal.Decimal

Decimal returns the decimal representation of the rate. It is equal to the number of units of the quote currency needed to exchange for 1 unit of the base currency.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	r := money.MustParseExchRate("EUR", "USD", "1.2500")
	fmt.Println(r.Decimal())
}
Output:

1.2500

func (ExchangeRate) Float64 added in v0.2.0

func (r ExchangeRate) Float64() (f float64, ok bool)

Float64 returns the nearest binary floating-point number rounded using rounding half to even (banker's rounding). See also constructor NewExchRateFromFloat64.

This conversion may lose data, as float64 has a smaller precision than the decimal type.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	r := money.MustParseExchRate("EUR", "USD", "0.10")
	q := money.MustParseExchRate("EUR", "USD", "123.456")
	p := money.MustParseExchRate("EUR", "USD", "1234567890.123456789")
	fmt.Println(r.Float64())
	fmt.Println(q.Float64())
	fmt.Println(p.Float64())
}
Output:

0.1 true
123.456 true
1.2345678901234567e+09 true

func (ExchangeRate) Floor added in v0.2.0

func (r ExchangeRate) Floor(scale int) (ExchangeRate, error)

Floor returns a rate rounded down to the specified number of digits after the decimal point using rounding toward negative infinity. If the given scale is less than the scale of the quote currency, the rate will be rounded down to the scale of the quote currency instead. See also method ExchangeRate.Ceil.

Floor returns an error if the result is 0.

Example (Currencies)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseExchRate("EUR", "JPY", "5.678")
	b := money.MustParseExchRate("EUR", "USD", "5.678")
	c := money.MustParseExchRate("EUR", "OMR", "5.678")
	fmt.Println(a.Floor(0))
	fmt.Println(b.Floor(0))
	fmt.Println(c.Floor(0))
}
Output:

EUR/JPY 5 <nil>
EUR/USD 5.67 <nil>
EUR/OMR 5.678 <nil>
Example (Scales)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseExchRate("EUR", "USD", "5.6789")
	fmt.Println(a.Floor(0))
	fmt.Println(a.Floor(1))
	fmt.Println(a.Floor(2))
	fmt.Println(a.Floor(3))
	fmt.Println(a.Floor(4))
}
Output:

EUR/USD 5.67 <nil>
EUR/USD 5.67 <nil>
EUR/USD 5.67 <nil>
EUR/USD 5.678 <nil>
EUR/USD 5.6789 <nil>

func (ExchangeRate) Format

func (r ExchangeRate) Format(state fmt.State, verb rune)

Format implements the fmt.Formatter interface. The following format verbs are available:

| Verb   | Example          | Description                   |
| ------ | ---------------- | ----------------------------- |
| %s, %v | EUR/USD 1.2500   | Currency pair and rate        |
| %q     | "EUR/USD 1.2500" | Quoted currency pair and rate |
| %f     | 1.2500           | Rate                          |
| %b     | EUR              | Base currency                 |
| %c     | USD              | Quote currency                |

The '-' format flag can be used with all verbs. The '0' format flags can be used with all verbs except %c.

Precision is only supported for the %f verb. The default precision is equal to the actual scale of the exchange rate.

Example (Currencies)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseExchRate("EUR", "JPY", "5")
	b := money.MustParseExchRate("EUR", "USD", "5")
	c := money.MustParseExchRate("EUR", "OMR", "5")
	fmt.Println("| v             | f     | b   | c   |")
	fmt.Println("| ------------- | ----- | --- | --- |")
	fmt.Printf("| %-13[1]v | %5[1]f | %[1]b | %[1]c |\n", a)
	fmt.Printf("| %-13[1]v | %5[1]f | %[1]b | %[1]c |\n", b)
	fmt.Printf("| %-13[1]v | %5[1]f | %[1]b | %[1]c |\n", c)
}
Output:

| v             | f     | b   | c   |
| ------------- | ----- | --- | --- |
| EUR/JPY 5     |     5 | EUR | JPY |
| EUR/USD 5.00  |  5.00 | EUR | USD |
| EUR/OMR 5.000 | 5.000 | EUR | OMR |
Example (Verbs)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	r := money.MustParseExchRate("USD", "EUR", "1.2500")
	fmt.Printf("%v\n", r)
	fmt.Printf("%[1]f %[1]b-%[1]c\n", r)
	fmt.Printf("%f\n", r)
	fmt.Printf("%b\n", r)
	fmt.Printf("%c\n", r)
}
Output:

USD/EUR 1.2500
1.2500 USD-EUR
1.2500
USD
EUR

func (ExchangeRate) Int64 added in v0.2.0

func (r ExchangeRate) Int64(scale int) (whole, frac int64, ok bool)

Int64 returns a pair of integers representing the whole and (possibly rounded) fractional parts of the rate. If given scale is greater than the scale of the rate, then the fractional part is zero-padded to the right. If given scale is smaller than the scale of the rate, then the fractional part is rounded using rounding half to even (banker's rounding). The relationship between the rate and the returned values can be expressed as r = whole + frac / 10^scale. This method is useful for converting rates to protobuf format. See also constructor NewExchRateFromInt64.

Int64 returns false if:

  • given scale is smaller than the scale of the quote currency;
  • the result cannot be represented as a pair of int64 values.
Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseExchRate("EUR", "USD", "5.678")
	fmt.Println(a.Int64(0))
	fmt.Println(a.Int64(1))
	fmt.Println(a.Int64(2))
	fmt.Println(a.Int64(3))
	fmt.Println(a.Int64(4))
}
Output:

0 0 false
0 0 false
5 68 true
5 678 true
5 6780 true

func (ExchangeRate) Inv

func (r ExchangeRate) Inv() (ExchangeRate, error)

Inv returns the inverse of the exchange rate.

Inv returns an error if:

  • the rate is 0;
  • the inverse of the rate is 0;
  • the integer part of the result has more than (decimal.MaxPrec - Currency.Scale) digits. For example, when the base currency is US Dollars, Inv will return an error if the integer part of the result has more than 17 digits (19 - 2 = 17).
Example (Currencies)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	r := money.MustParseExchRate("EUR", "JPY", "5.67")
	q := money.MustParseExchRate("EUR", "USD", "5.67")
	p := money.MustParseExchRate("EUR", "OMR", "5.67")
	fmt.Println(r.Inv())
	fmt.Println(q.Inv())
	fmt.Println(p.Inv())
}
Output:

JPY/EUR 0.1763668430335097002 <nil>
USD/EUR 0.1763668430335097002 <nil>
OMR/EUR 0.1763668430335097002 <nil>
Example (Scales)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	r := money.MustParseExchRate("EUR", "USD", "0.0567")
	q := money.MustParseExchRate("EUR", "USD", "0.567")
	p := money.MustParseExchRate("EUR", "USD", "5.67")
	o := money.MustParseExchRate("EUR", "USD", "56.7")
	n := money.MustParseExchRate("EUR", "USD", "567")
	fmt.Println(r.Inv())
	fmt.Println(q.Inv())
	fmt.Println(p.Inv())
	fmt.Println(o.Inv())
	fmt.Println(n.Inv())
}
Output:

USD/EUR 17.63668430335097002 <nil>
USD/EUR 1.763668430335097002 <nil>
USD/EUR 0.1763668430335097002 <nil>
USD/EUR 0.01763668430335097 <nil>
USD/EUR 0.001763668430335097 <nil>

func (ExchangeRate) IsOne

func (r ExchangeRate) IsOne() bool

IsOne returns:

true  if r == 1
false otherwise
Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	r := money.MustParseExchRate("EUR", "USD", "1.00")
	q := money.MustParseExchRate("EUR", "USD", "1.25")
	fmt.Println(r.IsOne())
	fmt.Println(q.IsOne())
}
Output:

true
false

func (ExchangeRate) IsPos added in v0.2.0

func (r ExchangeRate) IsPos() bool

IsPos returns:

true  if r > 0
false otherwise
Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	r := money.ExchangeRate{}
	q := money.MustParseExchRate("EUR", "USD", "1.25")
	fmt.Println(r.IsPos())
	fmt.Println(q.IsPos())
}
Output:

false
true

func (ExchangeRate) IsZero

func (r ExchangeRate) IsZero() bool

IsZero returns:

true  if r == 0
false otherwise
Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	r := money.ExchangeRate{}
	q := money.MustParseExchRate("USD", "EUR", "1.25")
	fmt.Println(r.IsZero())
	fmt.Println(q.IsZero())
}
Output:

true
false

func (ExchangeRate) MinScale added in v0.2.0

func (r ExchangeRate) MinScale() int

MinScale returns the smallest scale that the rate can be rescaled to without rounding. See also method ExchangeRate.Trim.

Example (Currencies)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	r := money.MustParseExchRate("EUR", "JPY", "5.0000")
	q := money.MustParseExchRate("EUR", "USD", "5.0000")
	p := money.MustParseExchRate("EUR", "OMR", "5.0000")
	fmt.Println(r.MinScale())
	fmt.Println(q.MinScale())
	fmt.Println(p.MinScale())
}
Output:

0
2
3
Example (Scales)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	r := money.MustParseExchRate("EUR", "USD", "5.6000")
	q := money.MustParseExchRate("EUR", "USD", "5.6700")
	p := money.MustParseExchRate("EUR", "USD", "5.6780")
	fmt.Println(r.MinScale())
	fmt.Println(q.MinScale())
	fmt.Println(p.MinScale())
}
Output:

2
2
3

func (ExchangeRate) Mul

Mul returns an exchange rate with the same base and quote currencies, but with the rate multiplied by a factor.

Mul returns an error if:

  • the result is 0 or negative;
  • the integer part of the result has more than (decimal.MaxPrec - Currency.Scale) digits. For example, when the quote currency is US Dollars, Mul will return an error if the integer part of the result has more than 17 digits (19 - 2 = 17).
Example
package main

import (
	"fmt"

	"github.com/govalues/decimal"
	"github.com/govalues/money"
)

func main() {
	r := money.MustParseExchRate("EUR", "USD", "5.67")
	d := decimal.MustParse("0.9")
	e := decimal.MustParse("1.0")
	f := decimal.MustParse("1.1")
	fmt.Println(r.Mul(d))
	fmt.Println(r.Mul(e))
	fmt.Println(r.Mul(f))
}
Output:

EUR/USD 5.103 <nil>
EUR/USD 5.670 <nil>
EUR/USD 6.237 <nil>

func (ExchangeRate) Quantize added in v0.2.0

func (r ExchangeRate) Quantize(q ExchangeRate) (ExchangeRate, error)

Quantize returns a rate rescaled to the same scale as rate q. The currency and the sign of rate q are ignored. See also methods ExchangeRate.Scale, ExchangeRate.SameScale, ExchangeRate.Rescale.

Quantize returns an error if:

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	r := money.MustParseExchRate("EUR", "JPY", "5.678")
	x := money.MustParseExchRate("EUR", "JPY", "1")
	y := money.MustParseExchRate("EUR", "JPY", "0.1")
	z := money.MustParseExchRate("EUR", "JPY", "0.01")
	fmt.Println(r.Quantize(x))
	fmt.Println(r.Quantize(y))
	fmt.Println(r.Quantize(z))
}
Output:

EUR/JPY 6 <nil>
EUR/JPY 5.7 <nil>
EUR/JPY 5.68 <nil>

func (ExchangeRate) Quote

func (r ExchangeRate) Quote() Currency

Quote returns the currency being obtained in exchange for the base currency.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	r := money.MustParseExchRate("EUR", "USD", "1.2500")
	fmt.Println(r.Quote())
}
Output:

USD

func (ExchangeRate) Rescale added in v0.1.0

func (r ExchangeRate) Rescale(scale int) (ExchangeRate, error)

Rescale returns a rate rounded or zero-padded to the given number of digits after the decimal point. If the specified scale is less than the scale of the quote currency, the amount will be rounded to the scale of the quote currency instead. See also method ExchangeRate.Round.

Rescale returns an error if:

  • the result is 0;
  • the integer part of the result has more than (decimal.MaxPrec - scale) digits.
Example (Currencies)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	r := money.MustParseExchRate("EUR", "JPY", "5.678")
	q := money.MustParseExchRate("EUR", "USD", "5.678")
	p := money.MustParseExchRate("EUR", "OMR", "5.678")
	fmt.Println(r.Rescale(0))
	fmt.Println(q.Rescale(0))
	fmt.Println(p.Rescale(0))
}
Output:

EUR/JPY 6 <nil>
EUR/USD 5.68 <nil>
EUR/OMR 5.678 <nil>
Example (Scales)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	r := money.MustParseExchRate("EUR", "USD", "5.6789")
	fmt.Println(r.Rescale(0))
	fmt.Println(r.Rescale(1))
	fmt.Println(r.Rescale(2))
	fmt.Println(r.Rescale(3))
	fmt.Println(r.Rescale(4))
}
Output:

EUR/USD 5.68 <nil>
EUR/USD 5.68 <nil>
EUR/USD 5.68 <nil>
EUR/USD 5.679 <nil>
EUR/USD 5.6789 <nil>

func (ExchangeRate) Round

func (r ExchangeRate) Round(scale int) (ExchangeRate, error)

Round returns a rate rounded to the specified number of digits after the decimal point using rounding half to even (banker's rounding). If the given scale is less than the scale of the quote currency, the rate will be rounded to the scale of the quote currency instead. See also method ExchangeRate.Rescale.

Round returns an error if the result is 0.

Example (Currencies)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	r := money.MustParseExchRate("EUR", "JPY", "5.678")
	q := money.MustParseExchRate("EUR", "USD", "5.678")
	p := money.MustParseExchRate("EUR", "OMR", "5.678")
	fmt.Println(r.Round(0))
	fmt.Println(q.Round(0))
	fmt.Println(p.Round(0))
}
Output:

EUR/JPY 6 <nil>
EUR/USD 5.68 <nil>
EUR/OMR 5.678 <nil>
Example (Scales)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	r := money.MustParseExchRate("EUR", "USD", "5.6789")
	fmt.Println(r.Round(0))
	fmt.Println(r.Round(1))
	fmt.Println(r.Round(2))
	fmt.Println(r.Round(3))
	fmt.Println(r.Round(4))
}
Output:

EUR/USD 5.68 <nil>
EUR/USD 5.68 <nil>
EUR/USD 5.68 <nil>
EUR/USD 5.679 <nil>
EUR/USD 5.6789 <nil>

func (ExchangeRate) SameCurr

func (r ExchangeRate) SameCurr(q ExchangeRate) bool

SameCurr returns true if exchange rates are denominated in the same base and quote currencies. See also methods ExchangeRate.Base and ExchangeRate.Quote.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	r := money.MustParseExchRate("EUR", "OMR", "0.42000")
	q := money.MustParseExchRate("EUR", "USD", "1.2500")
	p := money.MustParseExchRate("EUR", "USD", "5.6700")
	fmt.Println(r.SameCurr(q))
	fmt.Println(q.SameCurr(p))
}
Output:

false
true

func (ExchangeRate) SameScale

func (r ExchangeRate) SameScale(q ExchangeRate) bool

SameScale returns true if exchange rates have the same scale. See also method ExchangeRate.Scale.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	r := money.MustParseExchRate("OMR", "EUR", "2.30000")
	q := money.MustParseExchRate("USD", "EUR", "0.9000")
	p := money.MustParseExchRate("SAR", "USD", "0.2700")
	fmt.Println(r.SameScale(q))
	fmt.Println(q.SameScale(p))
}
Output:

false
true

func (ExchangeRate) Scale

func (r ExchangeRate) Scale() int

Scale returns the number of digits after the decimal point. See also method ExchangeRate.MinScale.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	r := money.MustParseExchRate("USD", "EUR", "0.80")
	q := money.MustParseExchRate("OMR", "USD", "0.38000")
	fmt.Println(r.Scale())
	fmt.Println(q.Scale())
}
Output:

2
5

func (ExchangeRate) Sign added in v0.2.0

func (r ExchangeRate) Sign() int

Sign returns:

 0 if r = 0
+1 if r > 0
Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	r := money.ExchangeRate{}
	q := money.MustParseExchRate("EUR", "USD", "1.25")
	fmt.Println(r.Sign())
	fmt.Println(q.Sign())
}
Output:

0
1

func (ExchangeRate) String

func (r ExchangeRate) String() string

String method implements the fmt.Stringer interface and returns a string representation of the exchange rate. See also methods Currency.String and Decimal.String.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	r := money.MustParseExchRate("EUR", "USD", "1.2500")
	q := money.MustParseExchRate("OMR", "USD", "0.0100")
	fmt.Println(r.String())
	fmt.Println(q.String())
}
Output:

EUR/USD 1.2500
OMR/USD 0.0100

func (ExchangeRate) Trim added in v0.2.0

func (r ExchangeRate) Trim(scale int) ExchangeRate

Trim returns a rate with trailing zeros removed up to the given scale. If the given scale is less than the scale of the quorte currency, the zeros will be removed up to the scale of the quote currency instead.

Example (Currencies)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	r := money.MustParseExchRate("EUR", "JPY", "5.000")
	q := money.MustParseExchRate("EUR", "USD", "5.000")
	p := money.MustParseExchRate("EUR", "OMR", "5.000")
	fmt.Println(r.Trim(0))
	fmt.Println(q.Trim(0))
	fmt.Println(p.Trim(0))
}
Output:

EUR/JPY 5
EUR/USD 5.00
EUR/OMR 5.000
Example (Scales)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseExchRate("EUR", "USD", "5.0000")
	fmt.Println(a.Trim(0))
	fmt.Println(a.Trim(1))
	fmt.Println(a.Trim(2))
	fmt.Println(a.Trim(3))
	fmt.Println(a.Trim(4))
}
Output:

EUR/USD 5.00
EUR/USD 5.00
EUR/USD 5.00
EUR/USD 5.000
EUR/USD 5.0000

func (ExchangeRate) Trunc added in v0.2.0

func (r ExchangeRate) Trunc(scale int) (ExchangeRate, error)

Trunc returns a rate truncated to the specified number of digits after the decimal point using rounding toward zero. If the given scale is less than the scale of the quote currency, the rate will be truncated to the scale of the quote currency instead.

Trunc returns an error if the result is 0.

Example (Currencies)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseExchRate("EUR", "JPY", "5.678")
	b := money.MustParseExchRate("EUR", "USD", "5.678")
	c := money.MustParseExchRate("EUR", "OMR", "5.678")
	fmt.Println(a.Trunc(0))
	fmt.Println(b.Trunc(0))
	fmt.Println(c.Trunc(0))
}
Output:

EUR/JPY 5 <nil>
EUR/USD 5.67 <nil>
EUR/OMR 5.678 <nil>
Example (Scales)
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	a := money.MustParseExchRate("EUR", "USD", "5.6789")
	fmt.Println(a.Trunc(0))
	fmt.Println(a.Trunc(1))
	fmt.Println(a.Trunc(2))
	fmt.Println(a.Trunc(3))
	fmt.Println(a.Trunc(4))
}
Output:

EUR/USD 5.67 <nil>
EUR/USD 5.67 <nil>
EUR/USD 5.67 <nil>
EUR/USD 5.678 <nil>
EUR/USD 5.6789 <nil>

func (ExchangeRate) WithinOne

func (r ExchangeRate) WithinOne() bool

WithinOne returns:

true  if 0 <= r < 1
false otherwise
Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	r := money.MustParseExchRate("EUR", "USD", "1.2500")
	q := money.MustParseExchRate("USD", "EUR", "0.8000")
	fmt.Println(r.WithinOne())
	fmt.Println(q.WithinOne())
}
Output:

false
true

type NullCurrency added in v0.2.0

type NullCurrency struct {
	Currency Currency
	Valid    bool
}

NullCurrency represents a currency that can be null. Its zero value is null. NullCurrency is not thread-safe.

func (*NullCurrency) Scan added in v0.2.0

func (n *NullCurrency) Scan(value any) error

Scan implements the sql.Scanner interface. See also method ParseCurr.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	var n, m money.NullCurrency
	_ = n.Scan("USD")
	_ = m.Scan(nil)
	fmt.Println(n)
	fmt.Println(m)
}
Output:

{USD true}
{XXX false}

func (NullCurrency) Value added in v0.2.0

func (n NullCurrency) Value() (driver.Value, error)

Value implements the driver.Valuer interface. See also method Currency.String.

Example
package main

import (
	"fmt"

	"github.com/govalues/money"
)

func main() {
	n := money.NullCurrency{
		Currency: money.USD,
		Valid:    true,
	}
	m := money.NullCurrency{
		Currency: money.XXX,
		Valid:    false,
	}
	fmt.Println(n.Value())
	fmt.Println(m.Value())
}
Output:

USD <nil>
<nil> <nil>

Directories

Path Synopsis
scripts

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL