{"id":2080,"url":"https://github.com/Flight-School/Money","last_synced_at":"2025-08-02T23:31:18.273Z","repository":{"id":46375931,"uuid":"138766430","full_name":"Flight-School/Money","owner":"Flight-School","description":"A precise, type-safe representation of a monetary amount in a given currency","archived":true,"fork":false,"pushed_at":"2023-08-31T15:35:17.000Z","size":167,"stargazers_count":912,"open_issues_count":1,"forks_count":34,"subscribers_count":18,"default_branch":"main","last_synced_at":"2025-07-20T19:36:41.157Z","etag":null,"topics":["currency","decimal","gyb","money","swift"],"latest_commit_sha":null,"homepage":"https://flight.school/books/numbers","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Flight-School.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null},"funding":{"github":["mattt"],"custom":"https://flight.school/books/numbers"}},"created_at":"2018-06-26T16:47:19.000Z","updated_at":"2025-07-10T18:12:48.000Z","dependencies_parsed_at":"2024-04-26T18:45:57.893Z","dependency_job_id":null,"html_url":"https://github.com/Flight-School/Money","commit_stats":{"total_commits":71,"total_committers":4,"mean_commits":17.75,"dds":"0.11267605633802813","last_synced_commit":"dbce8a736db4f6d3a46b501732e74a29efed534d"},"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/Flight-School/Money","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Flight-School%2FMoney","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Flight-School%2FMoney/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Flight-School%2FMoney/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Flight-School%2FMoney/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Flight-School","download_url":"https://codeload.github.com/Flight-School/Money/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Flight-School%2FMoney/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268472387,"owners_count":24255698,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-02T02:00:12.353Z","response_time":74,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["currency","decimal","gyb","money","swift"],"created_at":"2024-01-05T20:16:03.001Z","updated_at":"2025-08-02T23:31:17.980Z","avatar_url":"https://github.com/Flight-School.png","language":"Swift","funding_links":["https://github.com/sponsors/mattt","https://flight.school/books/numbers"],"categories":["Text","Swift"],"sub_categories":["Font"],"readme":"# Money\n\n[![Build Status][build status badge]][build status]\n[![License][license badge]][license]\n[![Swift Version][swift version badge]][swift version]\n![Cocoapods platforms][cocoapods platforms badge]\n[![Cocoapods compatible][cocoapods badge]][cocoapods]\n[![Carthage compatible][carthage badge]][carthage]\n\nA precise, type-safe representation of monetary amounts in a given currency.\n\nThis functionality is discussed in Chapter 3 of\n[Flight School Guide to Swift Numbers](https://flight.school/books/numbers).\n\n## Requirements\n\n- Swift 4.0+\n\n## Installation\n\n### Swift Package Manager\n\nAdd the Money package to your target dependencies in `Package.swift`:\n\n```swift\nimport PackageDescription\n\nlet package = Package(\n  name: \"YourProject\",\n  dependencies: [\n    .package(\n        url: \"https://github.com/Flight-School/Money\",\n        from: \"1.3.0\"\n    ),\n  ]\n)\n```\n\nThen run the `swift build` command to build your project.\n\n### CocoaPods\n\nYou can install `Money` via CocoaPods,\nby adding the following line to your `Podfile`:\n\n```ruby\npod 'Money-FlightSchool', '~\u003e 1.3.0'\n```\n\nRun the `pod install` command to download the library\nand integrate it into your Xcode project.\n\n\u003e **Note**\n\u003e The module name for this library is \"Money\" ---\n\u003e that is, to use it, you add `import Money` to the top of your Swift code\n\u003e just as you would by any other installation method.\n\u003e The pod is called \"Money-FlightSchool\"\n\u003e because there's an existing pod with the name \"Money\".\n\n### Carthage\n\nTo use `Money` in your Xcode project using Carthage,\nspecify it in `Cartfile`:\n\n```\ngithub \"Flight-School/Money\" ~\u003e 1.3.0\n```\n\nThen run the `carthage update` command to build the framework,\nand drag the built Money.framework into your Xcode project.\n\n## Usage\n\n### Creating Monetary Amounts\n\nThe `Money` type has a required associated `Currency` type.\nThese currency types are named according to their\nthree letter [ISO 4701][iso4217] currency codes.\nYou can initialize a monetary using a `Decimal` value:\n\n```swift\nlet amount = Decimal(12)\nlet monetaryAmount = Money\u003cUSD\u003e(amount)\n```\n\nSome currencies specify a minor unit.\nFor example, USD amounts are often expressed in cents,\neach worth 1/100 of a dollar.\nYou can initialize monetary amounts from a quantity of minor units.\nFor currencies that don't have a minor unit,\nsuch as JPY,\nthis is equivalent to the standard initializer.\n\n```swift\nlet twoCents = Money\u003cUSD\u003e(minorUnits: 2)\ntwoCents.amount // 0.02\n\nlet ichimonEn = Money\u003cJPY\u003e(minorUnits: 10_000)\nichimonEn.amount // 10000\n```\n\nYou can also create monetary amounts using\ninteger, floating-point, and string literals.\n\n```swift\n12 as Money\u003cUSD\u003e\n12.00 as Money\u003cUSD\u003e\n\"12.00\" as Money\u003cUSD\u003e\n```\n\n**Important**:\nSwift floating-point literals are currently initialized\nusing binary floating-point number type,\nwhich cannot precisely express certain values.\nAs a workaround, monetary amounts initialized\nfrom a floating-point literal are rounded\nto the number of places of the minor currency unit.\nIf you want to express a smaller fractional monetary amount,\ninitialize from a string literal or `Decimal` value instead.\n\n```swift\nlet preciseAmount: Money\u003cUSD\u003e = \"123.4567\"\nlet roundedAmount: Money\u003cUSD\u003e = 123.4567\n\npreciseAmount.amount // 123.4567\nroundedAmount.amount // 123.46\n```\n\nFor more information, see https://bugs.swift.org/browse/SR-920.\n\n### Comparing Monetary Amounts\n\nYou can compare two monetary amounts with the same currency:\n\n```swift\nlet amountInWallet: Money\u003cUSD\u003e = 60.00\nlet price: Money\u003cUSD\u003e = 19.99\n\namountInWallet \u003e= price // true\n```\n\nAttempting to compare monetary amounts with different currencies\nresults in a compiler error:\n\n```swift\nlet dollarAmount: Money\u003cUSD\u003e = 123.45\nlet euroAmount: Money\u003cEUR\u003e = 4567.89\n\ndollarAmount == euroAmount // Error: Binary operator '==' cannot be applied\n```\n\n### Adding, Subtracting, and Multiplying Monetary Amounts\n\nMonetary amounts can be added, subtracted, and multiplied\nusing the standard binary arithmetic operators (`+`, `-`, `*`):\n\n```swift\nlet prices: [Money\u003cUSD\u003e] = [2.19, 5.39, 20.99, 2.99, 1.99, 1.99, 0.99]\nlet subtotal = prices.reduce(0.00, +) // \"$36.53\"\nlet tax = 0.08 * subtotal // \"$2.92\"\nlet total = subtotal + tax // \"$39.45\"\n```\n\n**Important**: Multiplying a monetary amount by a floating-point number\nresults in an amount rounded to the number of places\nof the minor currency unit.\nIf you want to produce a smaller fractional monetary amount,\nmultiply by a `Decimal` value instead.\n\n### Formatting Monetary Amounts\n\nYou can create a localized representation of a monetary amount\nusing `NumberFormatter`.\nSet the `currencyCode` property of the formatter\nto the `currency.code` property of the `Money` value\nand pass the `amount` property to the formatter `string(for:)` method.\n\n```swift\nlet allowance: Money\u003cUSD\u003e = 10.00\nlet formatter = NumberFormatter()\nformatter.numberStyle = .currency\nformatter.locale = Locale(identifier: \"fr-FR\")\nformatter.currencyCode = allowance.currency.code\nformatter.string(for: allowance.amount) // \"10,00 $US\"\n```\n\n### Encoding and Decoding Monetary Amounts\n\n#### Encoding\n\nBy default,\n`Money` values are encoded as keyed containers,\nwith `amount` encoded as a number value.\n\n```swift\nlet value: Money\u003cUSD\u003e = 123.45\n\nlet encoder = JSONEncoder()\nlet data = try encoder.encode(value)\nString(data: data, encoding: .utf8) // #\"{\"amount\":123.45,\"currencyCode\":\"USD\"}\"#\n```\n\nTo configure encoding behavior,\nset either the `JSONEncoder.moneyEncodingOptions` property\nor the `CodingUserInfoKey.moneyEncodingOptions` key\nin the encoder's `userInfo` property.\n\n```swift\nvar encoder = JSONEncoder()\nencoder.moneyEncodingOptions = [.omitCurrency, .encodeAmountAsString]\n\nlet data = try encoder.encode([value])\nString(data: data, encoding: .utf8) // #\"[\"123.45\"]\"#\n```\n\n#### Decoding\n\nThe default decoding behavior is flexible,\nsupporting both keyed and single value containers,\nwith string or number values for `amount`.\n\n```swift\nlet json = #\"\"\"\n[\n    { \"currencyCode\": \"USD\", \"amount\": \"100.00\" },\n    50.00,\n    \"10\"\n]\n\"\"\"#.data(using: .utf8)!\n\nlet decoder = JSONDecoder()\nlet values = try decoder.decode([Money\u003cUSD\u003e].self, from: json)\nvalues.first?.amount // 100.00\nvalues.last?.currency.code // \"USD\"\n```\n\nTo configure decoding behavior,\nset either the `JSONDecoder.moneyDecodingOptions` property\nor the `CodingUserInfoKey.moneyDecodingOptions` key\nin the decoder's `userInfo` property.\n\n```swift\nvar decoder = JSONDecoder()\ndecoder.moneyDecodingOptions = [.requireExplicitCurrency]\n```\n\n**Important**:\nFoundation decoders currently decode number values\nusing a binary floating-point number type,\nwhich cannot precisely express certain values.\nAs a workaround,\nyou can specify the `requireStringAmount` decoding option\nto require monetary amounts to be\ndecoded precisely from a string representation.\n\n```swift\nlet json = #\"\"\"\n{ \"currencyCode\": \"USD\", \"amount\": \"27.31\" }\n\"\"\"#.data(using: .utf8)!\n\nvar decoder = JSONDecoder()\n\ntry decoder.decode(Money\u003cUSD\u003e.self, from: json) // DecodingError\n\ndecoder.moneyDecodingOptions = [.requireStringAmount]\nlet preciseAmount = try decoder.decode(Money\u003cUSD\u003e.self, from: json)\npreciseAmount.amount // 27.31\n```\n\nAlternatively,\nyou can the `roundFloatingPointAmount` decoding option\nto round decoded floating-point values\nto the number of places of the minor currency unit.\n\n```swift\nlet json = #\"\"\"\n{ \"currencyCode\": \"USD\", \"amount\": 27.31 }\n\"\"\"#.data(using: .utf8)!\n\nvar decoder = JSONDecoder()\n\nlet impreciseAmount = try decoder.decode(Money\u003cUSD\u003e.self, from: json)\nimpreciseAmount.amount // 27.30999999...\n\ndecoder.moneyDecodingOptions = [.roundFloatingPointAmount]\nlet roundedAmount = try decoder.decode(Money\u003cUSD\u003e.self, from: json)\nroundedAmount.amount // 27.31\n```\n\nFor more information, see https://bugs.swift.org/browse/SR-7054.\n\n#### Customizing Coding Keys\n\nBy default,\n`Money` values are encoded and decoded with the string keys\n`\"amount\"` and `\"currencyCode\"`, which\ncorrespond to their respective properties.\n\nIf you're working with data that encodes monetary amounts differently,\nyou can set the `keyDecodingStrategy` property of `JSONDecoder`\nto map to different key names:\n\n```swift\nlet json = #\"\"\"\n {\n    \"value\": \"3.33\",\n    \"currency\": \"USD\"\n }\n \"\"\"#.data(using: .utf8)!\n\nlet decoder = JSONDecoder()\ndecoder.keyDecodingStrategy = .custom({ keys in\n    switch keys.last?.stringValue {\n    case \"value\":\n        return MoneyCodingKeys.amount\n    case \"currency\":\n        return MoneyCodingKeys.currencyCode\n    default:\n        return keys.last!\n    }\n})\n\nlet amount = try decoder.decode(Money\u003cUSD\u003e.self, from: json) // $3.33\n```\n\nAlternatively,\nyou can create structures that match the shape of your data\nand derive computed properties that return `Money` types:\n\n```swift\nstruct Item: Codable {\n    struct Price: Codable {\n        let value: String\n        let currency: String\n    }\n\n    let name: String\n    private let unitPrice: Price\n\n    var unitPriceInUSD: Money\u003cUSD\u003e? {\n        guard unitPrice.currency == USD.code else { return nil }\n        return Money(unitPrice.value)\n    }\n}\n\nlet json = #\"\"\"\n {\n    \"name\": \"Widget\",\n    \"unitPrice\": {\n       \"value\": \"3.33\",\n       \"currency\": \"USD\"\n    }\n }\n \"\"\"#.data(using: .utf8)!\n\nlet decoder = JSONDecoder()\nlet item = try decoder.decode(Item.self, from: json)\nitem.unitPriceInUSD // $3.33\n```\n\n### Supporting Multiple Currencies\n\nConsider a `Product` structure with a `price` property.\nIf you only support a single currency, such as US Dollars,\nyou would define `price` to be of type `Money\u003cUSD\u003e`:\n\n```swift\nstruct Product {\n    var price: Money\u003cUSD\u003e\n}\n```\n\nIf you want to support multiple currencies, however,\nyou can't specify an explicit currency type in the property declaration.\nInstead, the `Product` would have to be defined as a generic type:\n\n```swift\nstruct Product\u003cCurrency: CurrencyType\u003e {\n    var price: Money\u003cCurrency\u003e\n}\n```\n\nUnfortunately, this approach is unwieldy,\nas each type that interacts with `Product` would also need to be generic,\nand so on, until the entire code base is generic over the currency type.\n\n```swift\nclass ViewController\u003cCurrency: CurrencyType\u003e : UIViewController { ... } // 😭\n```\n\nA better solution would be to define a new `Price` protocol\nwith requirements that match the `Money` type:\n\n```swift\nprotocol Price {\n    var amount: Decimal { get }\n    var currency: CurrencyType.Type { get }\n}\n\nextension Money: Price {}\n```\n\nDoing this allows prices to be defined in multiple currencies\nwithout making `Product` generic over the currency type:\n\n```swift\nstruct Product {\n    var price: Price\n}\n\nlet product = Product(price: 12.00 as Money\u003cUSD\u003e)\nproduct.price // \"$12.00\"\n```\n\nIf you want to support only certain currencies, such as US Dollars and Euros,\nyou can define a `SupportedCurrency` protocol\nand add conformance to each currency type through an extension:\n\n```swift\nprotocol SupportedCurrency: CurrencyType {}\nextension USD: SupportedCurrency {}\nextension EUR: SupportedCurrency {}\n\nextension Money: Price where Currency: SupportedCurrency {}\n```\n\nNow, attempting to create a `Product` with a price in an unsupported currency\nresults in a compiler error:\n\n```swift\nProduct(price: 100.00 as Money\u003cEUR\u003e)\nProduct(price: 100.00 as Money\u003cGBP\u003e) // Error\n```\n\n#### Supported Currencies\n\nThis package provides a `Currency` type for\neach of the currencies defined by the [ISO 4217][iso4217] standard\nwith the exception of special codes,\nsuch as USN (US Dollar, Next day) and\nXBC (Bond Markets Unit European Unit of Account 9).\n\nThe [source file][currency.swift] defining the available currencies\nis generated from a [CSV file][iso4217.csv] using [GYB][gyb].\nThis data source is up-to-date with\n[ISO 4217 Amendment Number 169](https://www.currency-iso.org/en/shared/amendments/iso-4217-amendment.html),\npublished on August 17, 2018.\n\nYou can regenerate `Sources/Money/Currency.swift` from `Resources/iso4217.csv`\nby installing [GYB][gyb]\nand running the `make` command from the terminal:\n\n```terminal\n$ make\n```\n\n\u003e We don't currently have a mechanism to automatically update this data source.\n\u003e Please [open an issue](https://github.com/Flight-School/Money/issues/new)\n\u003e if you're aware of any new amendments made to ISO 4217.\n\nYou can lookup any built-in currency types by its three-letter code\nusing the `iso4217Currency(for:)` function.\n\n```swift\niso4217Currency(for: \"USD\")?.name // \"US Dollar\"\niso4217Currency(for: \"invalid\") // nil\n```\n\n### Adding Custom Currencies\n\nYou can create your own custom currency types by defining an enumeration\nthat conforms to the `CurrencyType` protocol.\nFor example, here's how you might represent Bitcoin (BTC):\n\n```swift\nenum BTC: CurrencyType {\n    static var name: String { return \"Bitcoin\" }\n    static var code: String { return \"BTC\" }\n    static var minorUnit: Int { return 8 }\n}\n\nlet satoshi: Money\u003cBTC\u003e = 0.00000001\n```\n\n`NumberFormatter` only supports currencies defined by ISO 4217,\nso you'll have to configure the symbol, currency code,\nand any other necessary parameters:\n\n```swift\nlet formatter = NumberFormatter()\nformatter.numberStyle = .currency\nformatter.currencySymbol = \"₿\"\nformatter.currencyCode = \"BTC\"\nformatter.maximumFractionDigits = 8\n\nformatter.string(for: satoshi.amount) // ₿0.00000001\n```\n\n\u003e **Important**:\n\u003e The `iso4217Currency(for:) returns only built-in currencies,\n\u003e so calling `iso4217Currency(for: \"BTC\")` would return `nil`.\n\n### Showing Off with Emoji\n\nIf you're the type of person who enjoys putting clip art in your source code,\nhere's a trick that'll _really_ impress your teammates:\n\n```swift\ntypealias 💵 = Money\u003cUSD\u003e\ntypealias 💴 = Money\u003cJPY\u003e\ntypealias 💶 = Money\u003cEUR\u003e\ntypealias 💷 = Money\u003cGBP\u003e\n\nlet tubeFare: 💷 = 2.40 // \"£2.40\"\n```\n\n## Alternatives to Consider\n\nA type-safe `Money` structure like the one provided by this package\ncan reduce the likelihood of certain kinds of programming errors.\nHowever, you may find the cost of using this abstraction\nto outweigh the benefits it can provide in your code base.\n\nIf that's the case,\nyou might consider implementing your own simple `Money` type\nwith a nested `Currency` enumeration like this:\n\n```swift\nstruct Money {\n   enum Currency: String {\n      case USD, EUR, GBP, CNY // supported currencies here\n   }\n\n   var amount: Decimal\n   var currency: Currency\n}\n```\n\nIt's ultimately up to you to decide what kind of abstraction\nis best for your particular use case.\nWhatever you choose,\njust make sure to represent monetary amounts using a `Decimal` type\nwith an explicit currency.\n\n## License\n\nMIT\n\n## Contact\n\nMattt ([@mattt](https://twitter.com/mattt))\n\n[build status]: https://github.com/Flight-School/Money/actions?query=workflow%3ACI\n[build status badge]: https://github.com/Flight-School/Money/workflows/CI/badge.svg\n[currency.swift]: https://github.com/Flight-School/Money/blob/main/Sources/Money/Currency.swift\n[iso4217]: https://en.wikipedia.org/wiki/ISO_4217\n[iso4217.csv]: https://github.com/Flight-School/Money/blob/main/Resources/iso4217.csv\n[gyb]: https://nshipster.com/swift-gyb/\n[license]: https://opensource.org/licenses/MIT\n[license badge]: https://img.shields.io/cocoapods/l/Money-FlightSchool.svg\n[swift version]: https://swift.org/download/\n[swift version badge]: https://img.shields.io/badge/swift%20version-4.0+-orange.svg\n[cocoapods platforms badge]: https://img.shields.io/cocoapods/p/Money-FlightSchool.svg\n[cocoapods]: https://cocoapods.org/pods/Money-FlightSchool\n[cocoapods badge]: https://img.shields.io/cocoapods/v/Money-FlightSchool.svg\n[carthage]: https://github.com/Carthage/Carthage\n[carthage badge]: https://img.shields.io/badge/Carthage-compatible-4BC51D.svg\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FFlight-School%2FMoney","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FFlight-School%2FMoney","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FFlight-School%2FMoney/lists"}