{"id":26028600,"url":"https://github.com/sernamar/dinero","last_synced_at":"2025-10-08T19:39:33.840Z","repository":{"id":255525805,"uuid":"849534200","full_name":"sernamar/dinero","owner":"sernamar","description":"A Clojure library for working with money","archived":false,"fork":false,"pushed_at":"2025-09-24T15:10:50.000Z","size":292,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-10-02T19:26:20.108Z","etag":null,"topics":["bitcoin","clojure","currencies","money"],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sernamar.png","metadata":{"files":{"readme":"README.org","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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,"publiccode":null,"codemeta":null}},"created_at":"2024-08-29T19:02:55.000Z","updated_at":"2025-09-24T15:10:54.000Z","dependencies_parsed_at":"2024-09-18T11:22:09.944Z","dependency_job_id":"5c7402ab-1c79-439e-b93d-065e1d0df7dd","html_url":"https://github.com/sernamar/dinero","commit_stats":null,"previous_names":["sernamar/dinero"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/sernamar/dinero","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sernamar%2Fdinero","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sernamar%2Fdinero/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sernamar%2Fdinero/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sernamar%2Fdinero/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sernamar","download_url":"https://codeload.github.com/sernamar/dinero/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sernamar%2Fdinero/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279000704,"owners_count":26082805,"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-10-08T02:00:06.501Z","response_time":56,"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":["bitcoin","clojure","currencies","money"],"created_at":"2025-03-06T17:18:51.684Z","updated_at":"2025-10-08T19:39:33.834Z","avatar_url":"https://github.com/sernamar.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"** dinero                                                          :noexport:\n[[https://clojars.org/com.sernamar/dinero][file:https://img.shields.io/clojars/v/com.sernamar/dinero.svg]]\n\n/dinero/ is a Clojure library designed for managing monetary amounts and currencies. It offers support for precise arithmetic operations, formatting, and parsing, all tailored to different locales and currencies.\n\nThis library is heavily inspired by [[https://github.com/JavaMoney/jsr354-ri][Moneta]], which is part of the [[https://javamoney.github.io/][JavaMoney]] project.\n\nIt supports three types of monetary amounts:\n- =Money=: represents monetary amounts with arbitrary precision and scale, ensuring accurate numerical computations during arithmetic operations.\n- =FastMoney=: represents monetary amounts using a fixed scale, offering a balance between performance and accuracy while being precise enough for most applications.\n- =RoundedMoney=: represents monetary amounts that are automatically rounded after each arithmetic operation, ensuring consistent precision.\n\nIt also offers functionality to format monetary amounts and parse strings representing monetary amounts. It takes care of different formats and currencies based on the user's locale settings, ensuring accurate and locale-sensitive representations.\n\nIn terms of currencies, it supports all ISO 4217 currencies by default, allowing for seamless handling of all internationally recognized currencies like the Euro (=EUR=) and British Pound (=GBP=). You can also extend support to non-ISO currencies, such as cryptocurrencies like Bitcoin (=BTC=), or even custom currencies specific to your domain, through an EDN configuration file.\n** Table of contents :TOC_3:\n  - [[#installation][Installation]]\n  - [[#configuration][Configuration]]\n  - [[#usage][Usage]]\n    - [[#monetary-amounts][Monetary amounts]]\n    - [[#currencies][Currencies]]\n    - [[#formatting][Formatting]]\n    - [[#parsing][Parsing]]\n    - [[#equality-and-comparison][Equality and comparison]]\n    - [[#arithmetic-operations][Arithmetic operations]]\n    - [[#rounding][Rounding]]\n    - [[#currency-conversion][Currency conversion]]\n  - [[#license][License]]\n\n** Installation\nClojure CLI/deps.edn:\n#+begin_src shell\n  com.sernamar/dinero {:mvn/version \"0.3.0\"}\n#+end_src\nLeiningen/Boot:\n#+begin_src shell\n  [com.sernamar/dinero \"0.3.0\"]\n#+end_src\n** Configuration\nBefore using this library, you can configure the default currency and default rounding mode using a configuration file named =config.edn=, which should be located in the root directory of the project.\n\nFor example, to set /euros/ as the default currency and the /half even/ method as the default rounding method, the =config.edn= file should have the following content:\n#+begin_src clojure\n  {:default-currency :eur\n   :default-rounding-mode :half-even}\n#+end_src\n** Usage\n*** Monetary amounts\nThis library support three types of monetary amounts:\n- =Money=: represents monetary amounts with arbitrary precision and scale, ensuring accurate numerical computations during arithmetic operations.\n- =FastMoney=: represents monetary amounts using a fixed scale, offering a balance between performance and accuracy while being precise enough for most applications.\n- =RoundedMoney=: represents monetary amounts that are automatically rounded after each arithmetic operation.\n**** Monetary amounts of type =Money=\nYou can use =money-of= to create monetary amounts with arbitrary precision and scale. It accepts two arguments:\n- =amount=: can be either an integer, a floating-point number, a =BigDecimal= or a =String=.\n- =currency=: can be a keyword, a string, or a symbol, in either uppercase or lowercase.\nIf the =currency= is not specified, the =money-of= function will use the default currency set in the configuration file. If a currency is provided, it will override the default and use the specified currency instead:\n#+begin_src clojure\n  (require '[dinero.core :as dinero])\n\n  (dinero/money-of 1)\n  ;; =\u003e {:amount 1M, :currency :eur}\n\n  (dinero/money-of 1 :gbp)\n  ;; =\u003e {:amount 1M, :currency :gbp}\n#+end_src\nFor convenience, you can use the =with-currency= macro to bind the default currency in the macro's body. This way, if the default currency isn’t set in the configuration file, you won’t need to specify the currency when creating monetary amounts:\n#+begin_src clojure\n  (dinero/with-currency :gbp\n    (dinero/money-of 1))\n  ;; =\u003e {:amount 1M, :currency :gbp}\n#+end_src\nIf none the =amount= nor the =currency= is specified, it uses =0= as the amount, and the default currency as the currency:\n#+begin_src clojure\n  (dinero/money-of)\n  ;; =\u003e {:amount 0M, :currency :eur}\n#+end_src\nAlthough you can use either an integer, a floating-point number, a =BigDecimal= or a =String= as the =amount= argument, they are all parsed and stored as =BigDecimals=:\n#+begin_src clojure\n  (dinero/money-of 1 :eur)\n  ;; =\u003e {:amount 1M, :currency :eur}\n\n  (dinero/money-of 1.23 :eur)\n  ;; =\u003e {:amount 1.23M, :currency :eur}\n\n  (dinero/money-of 1.23M :eur)\n  ;; =\u003e {:amount 1.23M, :currency :eur}\n\n  (dinero/money-of \"1.23\" :eur)\n  ;; =\u003e {:amount 1.23M, :currency :eur}\n#+end_src\n/WARNING/:\n#+begin_quote\nBe aware that using floating-point numbers can lead to rounding errors in certain calculations, as Clojure reads them as =Doubles=, which are 64-bit IEEE 754 floating point numbers. This means you get double precision, with about 15-17 significant decimal digits of precision.\n\nSo for accurate numerical computations, especially in financial applications, don't use floating-point numbers; use =BigDecimals= or =Strings= instead, as they will be parsed accurately.\n#+begin_src clojure\n  ;;; Not safe, as it uses a floating-point number, losing precision when parsing\n  (dinero/money-of 0.123456789123456789123456789 :eur)\n  ;; =\u003e {:amount 0.12345678912345678M, :currency :eur}\n\n  ;;; Safe, as it uses BigDecimal or String\n  (dinero/money-of 0.123456789123456789123456789M :eur)\n  ;; =\u003e {:amount 0.123456789123456789123456789M, :currency :eur}\n  (dinero/money-of \"0.123456789123456789123456789\" :eur)\n  ;; =\u003e {:amount 0.123456789123456789123456789M, :currency :eur}\n#+end_src\n#+end_quote\n**** Monetary amounts of type =FastMoney=\nYou can use =fast-money-of= to create monetary amounts optimized for performance while maintaining sufficient accuracy. It accepts up to two arguments:\n- =amount=: can be an integer, a floating-point number, a =BigDecimal=, or a =String=.\n- =currency=: can be a keyword, a string, or a symbol, in either uppercase or lowercase.\n\nIf the =currency= is not specified, the =fast-money-of= function will use the default currency from the configuration file. This type of monetary amount uses a fixed scale for calculations, ensuring fast operations while remaining precise enough for most applications:\n#+begin_src clojure\n  (dinero/fast-money-of 1 :eur)\n  ;; =\u003e {:amount 1M, :currency :eur}\n#+end_src\n**** Monetary amounts of type =RoundedMoney=\nYou can use =rounded-money-of= to create monetary amounts that are automatically rounded after each arithmetic operation. This function accepts up to 4 arguments:\n- =amount=: can be an integer, a floating-point number, a =BigDecimal= or a =String=.\n- =currency=: can be a keyword, a string, or a symbol, in either uppercase or lowercase.\n- =scale=: the number of decimal places to which the amount will be rounded.\n- =rounding-mode=: the rounding mode to use when rounding the amount.\nIf =currency= is not specified, the =rounded-money-of= function will use the default currency from the configuration file. If =scale= is not provided, the minor units of the given currency will be used. If =rounding-mode= is not specified, the default rounding mode will be applied (or =:half-even= if the default rounding mode is not set in the configuration file):\n#+begin_src clojure\n  (dinero/rounded-money-of 1234.5678 :eur)\n  ;; =\u003e {:amount 1234.57M, :currency :eur, :scale 2, :rounding-mode :half-even}\n\n  (dinero/rounded-money-of 1234.5678 :eur 0)\n  ;; =\u003e {:amount 1235M, :currency :eur, :scale 0, :rounding-mode :half-even}\n\n  (dinero/rounded-money-of 1234.5678 :eur 0 :down)\n  ;; =\u003e {:amount 1234M, :currency :eur, :scale 0, :rounding-mode :down}\n#+end_src\n**** Amount, currency, and rounding information\nGiven a monetary amount, you can get its amount and currency using the =get-amount= and =get-currency= functions:\n#+begin_src clojure\n  (let [money (dinero/money-of 1 :eur)]\n    (dinero/get-amount money))\n  ;; =\u003e 1M\n  (let [money (dinero/money-of 1 :eur)]\n    (dinero/get-currency money))\n  ;; =\u003e :eur\n#+end_src\nFor rounded monetary amounts, you can also use the =get-scale= and =get-rounding-mode= functions to retrieve the scale and rounding mode applied during the rounding process:\n#+begin_src clojure\n  (let [money (dinero/rounded-money-of 1 :eur)]\n    (dinero/get-scale money))\n  ;; =\u003e 2\n\n  (let [money (dinero/rounded-money-of 1 :eur)]\n    (dinero/get-rounding-mode money))\n  ;; =\u003e :half-even\n#+end_src\n*** Currencies\nThis library supports all ISO 4217 currencies by default, providing seamless handling of all internationally recognized currencies like the Euro (=EUR=) and British Pound (=GBP=). Additionally, you can extend support to non-ISO currencies, such as cryptocurrencies like Bitcoin (=BTC=), or even custom currencies specific to your domain, by editing the =resources/currencies.edn= file. The format for defining currencies is as follows:\n#+begin_src clojure\n  {:eur {:type :iso-4217, :currency-code \"EUR\", :minor-units 2},\n   :gbp {:type :iso-4217, :currency-code \"GBP\", :minor-units 2},\n   :btc {:type :crypto, :currency-code \"BTC\", :symbol \"₿\", :minor-units 8}}\n#+end_src\nFor ISO 4217 currencies, the =:symbol= key should not be used, as the library automatically relies on the symbol defined by the locale. For example, the British Pound (=GBP=) is represented as =£= in =java.util.Locale/UK=, while in =java.util.Locale/FRANCE=, it appears as =£GB=. This ensures that the correct symbol is displayed based on the user's locale settings.\n\nFor non-ISO currencies, such as Bitcoin, the =:symbol= key is required because they are not supported by =java.util.Locale=. Since their symbols are not locale-specific, we define a single symbol in the =resources/currencies.edn= file, which is used consistently across all locales.\n\nThis approach provides flexibility in handling both standardized and custom currencies, allowing your application to adapt to a wide range of monetary systems.\n*** Formatting\nAs already mentioned, monetary amounts could be stored internally with more decimal places than the smallest unit of the currency. Although this may be important for accurate numerical computations, you might be interested in displaying amounts in a user-friendly format.\n\nTo display monetary amounts in a user-friendly format, you can use the =format-money= function. This function will convert the internal representation of the monetary amount into a string with a more readable format.\n\nThe =format-money= function accepts a map of configuration options as its second argument. The available options are:\n- locale\n- rounding-mode\n- decimal-places\n- symbol-style: accepts either =:symbol= (default) or =:code=.\nFor example:\n#+begin_src clojure\n  (require '[dinero.core :as dinero]\n           '[dinero.format :as format])\n\n  (let [m1 (dinero/money-of 1234.5678 :eur)\n        germany java.util.Locale/GERMANY]\n    (println (format/format-money m1 {:locale germany}))\n    (println (format/format-money m1 {:locale germany :symbol-style :code}))\n    (println (format/format-money m1 {:locale germany :rounding-mode :down :symbol-style :code}))\n    (println (format/format-money m1 {:locale germany :rounding-mode :down :decimal-places 0 :symbol-style :code})))\n  ;; 1.234,57 €\n  ;; 1.234,57 EUR\n  ;; 1.234,56 EUR\n  ;; 1.234 EUR\n#+end_src\nYou can also use the =format-money-with-pattern= function, which uses the given formatting pattern to format the monetary amount. This function also accepts a map of configuration options as its third argument, supporting these options:\n- locale\n- rounding-mode\nFor example:\n#+begin_src clojure\n  (let [m1 (dinero/money-of 1234.5678 :eur)\n        germany java.util.Locale/GERMANY]\n    (println (format/format-money-with-pattern m1 \"#,##0.00 ¤\" {:locale germany}))\n    (println (format/format-money-with-pattern m1 \"#,##0.00 ¤¤\" {:locale germany}))\n    (println (format/format-money-with-pattern m1 \"#,##0.00 euros\" {:locale germany}))\n    (println (format/format-money-with-pattern m1 \"#,##0.000 ¤\" {:locale germany}))\n    (println (format/format-money-with-pattern m1 \"#,##0 ¤\" {:locale germany}))\n    (println (format/format-money-with-pattern m1 \"#,##0 ¤\" {:locale germany :rounding-mode :down})))\n  ;; 1.234,57 €\n  ;; 1.234,57 EUR\n  ;; 1.234,57 euros\n  ;; 1.234,568 €\n  ;; 1.235 €\n  ;; 1.234 €\n#+end_src\n*** Parsing\nThis library supports parsing strings with both ISO 4217 currencies (e.g., Euro) and non-ISO 4217 currencies (e.g., Bitcoin), whether they use currency symbols (e.g., =€= or =₿=) or currency codes (e.g., =EUR= or =BTC=).\n\nTo parse a string representing a monetary amount, use the =parse-string= function, which accepts a map of configuration options as its second argument. The available options are:\n- =:locale=: a =java.util.Locale= object used for parsing. If =NIL=, the default locale is used.\n- =:currencies=: a sequence of currencies to attempt during parsing. If =NIL=, it defaults to either the configured currency or the locale's default currency.\n- =:try-all-currencies?=: a boolean flag. If =TRUE=, the function will attempt to parse the string using all currencies available in =resources/currencies.edn= if the provided currencies fail. Defaults to =FALSE=.\n#+begin_src clojure\n  (require '[dinero.parse :as parse])\n\n  (parse/parse-string \"1.234,56 €\" {:locale java.util.Locale/GERMANY})\n  ;; =\u003e {:amount 1234.56M, :currency :eur}\n\n  (parse/parse-string \"1.234,56 EUR\" {:locale java.util.Locale/GERMANY})\n  ;; =\u003e {:amount 1234.56M, :currency :eur}\n\n  (parse/parse-string \"1.234,56 £\" {:locale java.util.Locale/GERMANY :currencies [:eur :gbp]})\n  ;; =\u003e {:amount 1234.56M, :currency :gbp}\n\n  (parse/parse-string \"1.234,56 GBP\" {:locale java.util.Locale/GERMANY :currencies [:eur :gbp]})\n  ;; =\u003e {:amount 1234.56M, :currency :gbp}\n\n  (parse/parse-string \"1.234,56 £\" {:locale java.util.Locale/GERMANY :try-all-currencies? true})\n  ;; =\u003e {:amount 1234.56M, :currency :gbp}\n\n  (parse/parse-string \"1.234,56 ₿\" {:locale java.util.Locale/GERMANY :currencies [:btc]})\n  ;; =\u003e {:amount 1234.56M, :currency :btc}\n\n  (parse/parse-string \"1.234,56 BTC\" {:locale java.util.Locale/GERMANY :currencies [:btc]})\n  ;; =\u003e {:amount 1234.56M, :currency :btc}\n\n  (parse/parse-string \"1.234,56 ₿\" {:locale java.util.Locale/GERMANY :try-all-currencies? true})\n  ;; =\u003e {:amount 1234.56M, :currency :btc}\n\n  (parse/parse-string \"1.234,56 ₿\" {:locale java.util.Locale/GERMANY :currencies [:eur :gbp] :try-all-currencies? true})\n  ;; =\u003e {:amount 1234.56M, :currency :btc}\n#+end_src\nThe =parse-string= function is capable of differentiating between the same currency symbol used in different locales. For example, the dollar sign (=$=) represents both US dollars (=USD=) and Canadian dollars (=CAD=), depending on the locale:\n#+begin_src clojure\n  (parse/parse-string \"$1,234.56\" {:locale java.util.Locale/US})\n  ;; =\u003e {:amount 1234.56M, :currency :usd}\n\n  (parse/parse-string \"$1,234.56\" {:locale java.util.Locale/CANADA})\n  ;; =\u003e {:amount 1234.56M, :currency :cad}\n#+end_src\nIf =parse-string= cannot recognize the format or the currency in the string, it throws a =java.text.ParseException=:\n#+begin_src clojure\n  ;; unrecognized format for java.util.Locale/GERMANY\n  (parse/parse-string \"1,234.56 €\" {:locale java.util.Locale/GERMANY})\n  ;; Unhandled java.text.ParseException\n  ;; Unparseable number: \"1,234.56 €\"\n\n  ;; unrecognized currency for java.util.Locale/GERMANY\n  (parse/parse-string \"1.234,56 £\" {:locale java.util.Locale/GERMANY})\n  ;; Unhandled java.text.ParseException\n  ;; Unparseable number: \"1.234,56 £\"\n\n  ;; unrecognized currency for any java.util.Locale\n  (parse/parse-string \"1.234,56 ₿\" {:locale java.util.Locale/GERMANY})\n  ;; Unhandled java.text.ParseException\n  ;; Unparseable number: \"1.234,56 ₿\"\n#+end_src\n*** Equality and comparison\nYou could use the following functions to do equality and comparison operations on monetary amounts: ~=~, =not==, =money\u003c=, =money\u003c==, =money\u003e=, =money\u003e==, =money-zero?=, =money-pos?=, and =money-neg?=.\n\nFor example:\n#+begin_src clojure\n  (require '[dinero.core :as dinero]\n           '[dinero.math :as math])\n\n  (let [m1 (dinero/money-of 1 :eur)\n        m2 (dinero/money-of 1 :eur)]\n    (= m1 m2))\n  ;; =\u003e true\n\n  (let [m1 (dinero/money-of 1 :eur)\n        m2 (dinero/money-of 1 :gbp)]\n    (= m1 m2))\n    ;; =\u003e false\n\n  (let [m1 (dinero/money-of 1 :eur)\n        m2 (dinero/money-of 2 :eur)]\n    (not= m1 m2))\n  ;; =\u003e true\n\n  (let [m1 (dinero/money-of 1 :eur)\n        m2 (dinero/money-of 2 :eur)]\n    (math/money\u003c m1 m2))\n  ;; =\u003e true\n\n  (let [m1 (dinero/money-of 1 :eur)\n        m2 (dinero/money-of 2 :eur)]\n    (math/money\u003e m1 m2))\n  ;; =\u003e false\n\n  (let [money (dinero/money-of 0 :eur)]\n    (math/money-zero? money))\n  ;; =\u003e true\n\n  (let [money (dinero/money-of -1 :eur)]\n    (math/money-pos? money))\n  ;; =\u003e false\n\n  (let [money (dinero/money-of -1 :eur)]\n    (math/money-neg? money))\n  ;; =\u003e true\n#+end_src\n*** Arithmetic operations\nYou can use =add=, =substract=, =multiply=, and =divide= to perform arithmetic operations on monetary amounts:\n#+begin_src clojure\n  (require '[dinero.core :as dinero]\n           '[dinero.math :as math])\n\n  (let [m1 (dinero/money-of 1 :eur)\n        m2 (dinero/money-of 1 :eur)]\n    (math/add m1 m2))\n  ;; =\u003e {:amount 2M, :currency :eur}\n\n  (let [m1 (dinero/money-of 1 :eur)\n        m2 (dinero/money-of 1 :eur)]\n    (math/subtract m1 m2))\n  ;; =\u003e {:amount 0M, :currency :eur}\n\n  (let [money (dinero/money-of 1 :eur)\n        factor 2]\n    (math/multiply money factor))\n  ;; =\u003e {:amount 2M, :currency :eur}\n\n  (let [money (dinero/money-of 2 :eur)\n        divisor 2]\n    (math/divide money divisor))\n  ;; =\u003e {:amount 1M, :currency :eur}\n#+end_src\nNote that =add= and =substract= can be used to add and substract more than two monetary amounts:\n#+begin_src clojure\n  (let [m1 (dinero/money-of 1 :eur)\n        m2 (dinero/money-of 2 :eur)\n        m3 (dinero/money-of 3 :eur)]\n    (math/add m1 m2 m3))\n  ;; =\u003e {:amount 6M, :currency :eur}\n\n  (let [m1 (dinero/money-of 3 :eur)\n        m2 (dinero/money-of 2 :eur)\n        m3 (dinero/money-of 1 :eur)]\n    (math/subtract m1 m2 m3))\n  ;; =\u003e {:amount 0M, :currency :eur}\n#+end_src\nAdding or substracting monetary amounts with different currencies throws an =ExceptionInfo= exception:\n#+begin_src clojure\n  (let [m1 (dinero/money-of 1 :eur)\n        m2 (dinero/money-of 1 :gbp)]\n    (math/add m1 m2))\n  ;; clojure.lang.ExceptionInfo\n  ;; Currencies do not match\n  ;; {:currencies (:eur :gbp)}\n#+end_src\n*** Rounding\nAs previously mentioned, money amounts could be stored internally with more decimal places than the smallest unit of the currency. But some applications might require operating with amounts rounded to the smallest unit of currency. In such cases, you can use a monetary amount of type rounded, but you can also use the =round= function to adjust the monetary amount accordingly.\n\nBy default, the =round= function rounds amounts to the smallest unit of the currency, using the default rounding mode specified in the configuration file (if no rounding mode is configured, it defaults to =:half-even=):\n#+begin_src clojure\n  (require '[dinero.core :as dinero]\n           '[dinero.math :as math]\n           '[dinero.rounding :as rounding])\n\n  (let [m1 (dinero/money-of 1.555 :eur)\n        m2 (dinero/money-of 1.555 :eur)]\n    (math/add m1 m2))\n  ;; =\u003e {:amount 3.110M, :currency :eur}\n\n  (let [m1 (dinero/money-of 1.555 :eur)\n        m2 (dinero/money-of 1.555 :eur)\n        m1-rounded (rounding/round m1)\n        m2-rounded (rounding/round m2)]\n    (math/add m1-rounded m2-rounded))\n  ;; =\u003e {:amount 3.12M, :currency :eur}\n#+end_src\nBut you can also speficy the number of decimal places and the rounding mode you want to use when rounding. For example:\n#+begin_src clojure\n  (let [m1 (dinero/money-of 1.555 :eur)\n        m2 (dinero/money-of 1.555 :eur)\n        m1-rounded (rounding/round m1 0 :half-even)\n        m2-rounded (rounding/round m2 0 :half-even)]\n    (math/add m1-rounded m2-rounded))\n  ;; =\u003e {:amount 4M, :currency :eur}\n#+end_src\nIf necessary, you can also call =round= with two arguments, which are the monetary amount and a custom rounding funtion to use to round the monetary amount. This allows you to specify different rounding rules for certain cases.\n\nFor example, the Swiss Franc (=CHF=) uses unique rounding rules because the smallest unit of currency in Switzerland is the 5-centime (=0.05 CHF=) coin. To handle the specific rounding requirements for Swiss Francs, you can use the =chf-rounding-fn= function, which containins a rounding function tailored to =CHF=:\n#+begin_src clojure\n  (let [money (dinero/money-of 1.024 :chf)]\n    (rounding/round money rounding/chf-rounding-fn))\n  ;; =\u003e {:amount 1.00M, :currency :chf}\n\n  (let [money (dinero/money-of 1.025 :chf)]\n    (rounding/round money rounding/chf-rounding-fn))\n  ;; =\u003e {:amount 1.05M, :currency :chf}\n#+end_src\nThis approach is also useful when formatting currencies with special rounding requirements. For instance, when formatting Swiss Francs, you might want to round the amount before using the =format= function to ensure the displayed value matches the currency's rounding conventions:\n#+begin_src clojure\n  (let [money (dinero/money-of 1.025 :chf)]\n    (format/format-money money {:locale (java.util.Locale. \"de\" \"CH\")}))\n  ;; =\u003e \"CHF 1.02\"\n\n  (let [money (dinero/money-of 1.025 :chf)\n        rounded-money (rounding/round money rounding/chf-rounding-fn)]\n    (format/format-money rounded-money {:locale (java.util.Locale. \"de\" \"CH\")}))\n  ;; =\u003e \"CHF 1.05\"\n#+end_src\n*** Currency conversion\nThis library provides several functions to convert monetary amounts between currencies using various sources for exchange rates.\n\nThe simplest function is =convert-using-exchange-rate=, where you provide the exchange rate for the conversion:\n#+begin_src clojure\n  (require '[dinero.core :as dinero]\n           '[dinero.conversion.core :as conversion])\n\n  (let [money (dinero/money-of 1 :eur)]\n    (conversion/convert-using-exchange-rate money :gbp 0.8))\n  ;; =\u003e {:amount 0.8M, :currency :gbp}\n#+end_src\nIn addition to this, you can use other functions designed for specific use cases, whether you're retrieving exchange rates from external providers or custom databases.\n\nFor example, to perform currency conversion using a database, use =convert-using-db=. This function requires, besides the monetary amount and target currency for the conversion (and optionally, the date), a database connection along with schema details (such as the table name, fields for the base and target currencies, the exchange rate field, and the date field if needed):\n#+begin_src clojure\n  (require '[next.jdbc :as jdbc])\n\n  (defonce db (jdbc/get-datasource {:dbtype \"h2:mem\" :dbname \"readme-db\"}))\n  (jdbc/execute-one! db [\"CREATE TABLE exchange_rate (from_currency VARCHAR(3), to_currency VARCHAR(3), rate DOUBLE, date DATE)\"])\n  (jdbc/execute-one! db [\"INSERT INTO exchange_rate (from_currency, to_currency, rate, date) VALUES ('EUR', 'GBP', 0.80, '2024-09-08')\"])\n\n  (let [money (dinero/money-of 1 :eur)]\n      (conversion/convert-using-db money :gbp db \"exchange_rate\" \"from_currency\" \"to_currency\" \"rate\"))\n  ;; =\u003e {:amount 0.8M, :currency :gbp}\n\n  (let [money (dinero/money-of 1 :eur)\n        date (java.time.LocalDate/parse \"2024-09-08\")]\n      (conversion/convert-using-db money :gbp date db \"exchange_rate\" \"from_currency\" \"to_currency\" \"rate\" \"date\"))\n  ;; =\u003e {:amount 0.8M, :currency :gbp}\n#+end_src\nAdditionally, you can retrieve exchange rates from external providers. Currently, the library supports exchange rates from the European Central Bank (ECB) for both current and historical (up to 90 days) data, as well as from Coinbase for both current and historical Bitcoin exchange rates:\n#+begin_src clojure\n  (let [money (dinero/money-of 1 :eur)]\n    (conversion/convert-using-ecb money :gbp))\n  ;; =\u003e {:amount 0.84375M, :currency :gbp}\n\n  (let [money (dinero/money-of 1 :eur)\n        date (java.time.LocalDate/of 2024 9 11)]\n    (conversion/convert-using-ecb money :gbp date))\n  ;; =\u003e {:amount 0.84375M, :currency :gbp}\n\n  (let [money (dinero/money-of 1 :btc)]\n    (conversion/convert-using-coinbase money :eur))\n  ;; =\u003e {:amount 52394.05M, :currency :eur}\n\n  (let [money (dinero/money-of 1 :btc)\n        date (java.time.LocalDate/of 2024 9 11)]\n    (conversion/convert-using-coinbase money :eur date))\n  ;; =\u003e {:amount 52314.756527447545254192M, :currency :eur}\n#+end_src\n** License\nCopyright © 2025 Sergio Navarro\n\nDistributed under the [[https://www.mozilla.org/en-US/MPL/2.0/][Mozilla Public License, version 2.0]].\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsernamar%2Fdinero","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsernamar%2Fdinero","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsernamar%2Fdinero/lists"}