Provides methods for converting numbers into formatted strings. Methods are provided for phone numbers, currency, percentage, precision, positional notation, file size and pretty printing.

Most methods expect a number argument, and will return it unchanged if can’t be converted into a valid number.

Methods
N
Classes and Modules
Constants
DEFAULT_CURRENCY_VALUES = { :format => "%u%n", :negative_format => "-%u%n", :unit => "$", :separator => ".", :delimiter => ",", :precision => 2, :significant => false, :strip_insignificant_zeros => false }
STORAGE_UNITS = [:byte, :kb, :mb, :gb, :tb].freeze
DECIMAL_UNITS = {0 => :unit, 1 => :ten, 2 => :hundred, 3 => :thousand, 6 => :million, 9 => :billion, 12 => :trillion, 15 => :quadrillion, -1 => :deci, -2 => :centi, -3 => :mili, -6 => :micro, -9 => :nano, -12 => :pico, -15 => :femto}.freeze
Instance Public methods
number_to_currency(number, options = {})

Formats a number into a currency string (e.g., $13.65). You can customize the format in the options hash.

Options

  • :locale - Sets the locale to be used for formatting (defaults to current locale).
  • :precision - Sets the level of precision (defaults to 2).
  • :unit - Sets the denomination of the currency (defaults to “$”).
  • :separator - Sets the separator between the units (defaults to “.”).
  • :delimiter - Sets the thousands delimiter (defaults to “,”).
  • :format - Sets the format for non-negative numbers (defaults to “%u%n”).
                                 Fields are <tt>%u</tt> for the currency, and <tt>%n</tt>
                                 for the number.
    
  • :negative_format - Sets the format for negative numbers (defaults to prepending
                                 an hyphen to the formatted number given by <tt>:format</tt>).
                                 Accepts the same fields than <tt>:format</tt>, except
                                 <tt>%n</tt> is here the absolute value of the number.
    
  • :raise - If true, raises InvalidNumberError when the argument is invalid.

Examples

 number_to_currency(1234567890.50)                    # => $1,234,567,890.50
 number_to_currency(1234567890.506)                   # => $1,234,567,890.51
 number_to_currency(1234567890.506, :precision => 3)  # => $1,234,567,890.506
 number_to_currency(1234567890.506, :locale => :fr)   # => 1 234 567 890,51 €
 number_to_currency("123a456")                        # => $123a456

 number_to_currency("123a456", :raise => true)        # => InvalidNumberError

 number_to_currency(-1234567890.50, :negative_format => "(%u%n)")
 # => ($1,234,567,890.50)
 number_to_currency(1234567890.50, :unit => "&pound;", :separator => ",", :delimiter => "")
 # => &pound;1234567890,50
 number_to_currency(1234567890.50, :unit => "&pound;", :separator => ",", :delimiter => "", :format => "%n %u")
 # => 1234567890,50 &pound;
     # File actionpack/lib/action_view/helpers/number_helper.rb, line 124
124:       def number_to_currency(number, options = {})
125:         return unless number
126: 
127:         options.symbolize_keys!
128: 
129:         defaults  = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
130:         currency  = I18n.translate(:'number.currency.format', :locale => options[:locale], :default => {})
131:         currency[:negative_format] ||= "-" + currency[:format] if currency[:format]
132: 
133:         defaults  = DEFAULT_CURRENCY_VALUES.merge(defaults).merge!(currency)
134:         defaults[:negative_format] = "-" + options[:format] if options[:format]
135:         options   = defaults.merge!(options)
136: 
137:         unit      = options.delete(:unit)
138:         format    = options.delete(:format)
139: 
140:         if number.to_f < 0
141:           format = options.delete(:negative_format)
142:           number = number.respond_to?("abs") ? number.abs : number.sub(/^-/, '')
143:         end
144: 
145:         begin
146:           value = number_with_precision(number, options.merge(:raise => true))
147:           format.gsub(/%n/, value).gsub(/%u/, unit).html_safe
148:         rescue InvalidNumberError => e
149:           if options[:raise]
150:             raise
151:           else
152:             formatted_number = format.gsub(/%n/, e.number).gsub(/%u/, unit)
153:             e.number.to_s.html_safe? ? formatted_number.html_safe : formatted_number
154:           end
155:         end
156: 
157:       end
number_to_human(number, options = {})

Pretty prints (formats and approximates) a number in a way it is more readable by humans (eg.: 1200000000 becomes “1.2 Billion”). This is useful for numbers that can get very large (and too hard to read).

See number_to_human_size if you want to print a file size.

You can also define you own unit-quantifier names if you want to use other decimal units (eg.: 1500 becomes “1.5 kilometers”, 0.150 becomes “150 milliliters”, etc). You may define a wide range of unit quantifiers, even fractional ones (centi, deci, mili, etc).

Options

  • :locale - Sets the locale to be used for formatting (defaults to current locale).
  • :precision - Sets the precision of the number (defaults to 3).
  • :significant - If true, precision will be the # of significant_digits. If false, the # of fractional digits (defaults to true)
  • :separator - Sets the separator between the fractional and integer digits (defaults to “.”).
  • :delimiter - Sets the thousands delimiter (defaults to “”).
  • :strip_insignificant_zeros - If true removes insignificant zeros after the decimal separator (defaults to true)
  • :units - A Hash of unit quantifier names. Or a string containing an i18n scope where to find this hash. It might have the following keys:
    • integers: :unit, :ten, :hundred, :thousand, :million, :billion, :trillion, :quadrillion
    • fractionals: :deci, :centi, :mili, :micro, :nano, :pico, :femto
  • :format - Sets the format of the output string (defaults to “%n %u”). The field types are:
      %u  The quantifier (ex.: 'thousand')
      %n  The number
    
  • :raise - If true, raises InvalidNumberError when the argument is invalid.

Examples

 number_to_human(123)                                          # => "123"
 number_to_human(1234)                                         # => "1.23 Thousand"
 number_to_human(12345)                                        # => "12.3 Thousand"
 number_to_human(1234567)                                      # => "1.23 Million"
 number_to_human(1234567890)                                   # => "1.23 Billion"
 number_to_human(1234567890123)                                # => "1.23 Trillion"
 number_to_human(1234567890123456)                             # => "1.23 Quadrillion"
 number_to_human(1234567890123456789)                          # => "1230 Quadrillion"
 number_to_human(489939, :precision => 2)                      # => "490 Thousand"
 number_to_human(489939, :precision => 4)                      # => "489.9 Thousand"
 number_to_human(1234567, :precision => 4,
                          :significant => false)               # => "1.2346 Million"
 number_to_human(1234567, :precision => 1,
                          :separator => ',',
                          :significant => false)               # => "1,2 Million"

Unsignificant zeros after the decimal separator are stripped out by default (set :strip_insignificant_zeros to false to change that):

 number_to_human(12345012345, :significant_digits => 6)       # => "12.345 Billion"
 number_to_human(500000000, :precision => 5)                  # => "500 Million"

Custom Unit Quantifiers

You can also use your own custom unit quantifiers:

 number_to_human(500000, :units => {:unit => "ml", :thousand => "lt"})  # => "500 lt"

If in your I18n locale you have:

  distance:
    centi:
      one: "centimeter"
      other: "centimeters"
    unit:
      one: "meter"
      other: "meters"
    thousand:
      one: "kilometer"
      other: "kilometers"
    billion: "gazillion-distance"

Then you could do:

 number_to_human(543934, :units => :distance)                              # => "544 kilometers"
 number_to_human(54393498, :units => :distance)                            # => "54400 kilometers"
 number_to_human(54393498000, :units => :distance)                         # => "54.4 gazillion-distance"
 number_to_human(343, :units => :distance, :precision => 1)                # => "300 meters"
 number_to_human(1, :units => :distance)                                   # => "1 meter"
 number_to_human(0.34, :units => :distance)                                # => "34 centimeters"
     # File actionpack/lib/action_view/helpers/number_helper.rb, line 484
484:       def number_to_human(number, options = {})
485:         options.symbolize_keys!
486: 
487:         number = begin
488:           Float(number)
489:         rescue ArgumentError, TypeError
490:           if options[:raise]
491:             raise InvalidNumberError, number
492:           else
493:             return number
494:           end
495:         end
496: 
497:         defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
498:         human    = I18n.translate(:'number.human.format', :locale => options[:locale], :default => {})
499:         defaults = defaults.merge(human)
500: 
501:         options = options.reverse_merge(defaults)
502:         #for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files
503:         options[:strip_insignificant_zeros] = true if not options.key?(:strip_insignificant_zeros)
504: 
505:         inverted_du = DECIMAL_UNITS.invert
506: 
507:         units = options.delete :units
508:         unit_exponents = case units
509:         when Hash
510:           units
511:         when String, Symbol
512:           I18n.translate(:"#{units}", :locale => options[:locale], :raise => true)
513:         when nil
514:           I18n.translate(:"number.human.decimal_units.units", :locale => options[:locale], :raise => true)
515:         else
516:           raise ArgumentError, ":units must be a Hash or String translation scope."
517:         end.keys.map{|e_name| inverted_du[e_name] }.sort_by{|e| -e}
518: 
519:         number_exponent = number != 0 ? Math.log10(number.abs).floor : 0
520:         display_exponent = unit_exponents.find{ |e| number_exponent >= e } || 0
521:         number  /= 10 ** display_exponent
522: 
523:         unit = case units
524:         when Hash
525:           units[DECIMAL_UNITS[display_exponent]]
526:         when String, Symbol
527:           I18n.translate(:"#{units}.#{DECIMAL_UNITS[display_exponent]}", :locale => options[:locale], :count => number.to_i)
528:         else
529:           I18n.translate(:"number.human.decimal_units.units.#{DECIMAL_UNITS[display_exponent]}", :locale => options[:locale], :count => number.to_i)
530:         end
531: 
532:         decimal_format = options[:format] || I18n.translate(:'number.human.decimal_units.format', :locale => options[:locale], :default => "%n %u")
533:         formatted_number = number_with_precision(number, options)
534:         decimal_format.gsub(/%n/, formatted_number).gsub(/%u/, unit).strip.html_safe
535:       end
number_to_human_size(number, options = {})

Formats the bytes in number into a more understandable representation (e.g., giving it 1500 yields 1.5 KB). This method is useful for reporting file sizes to users. You can customize the format in the options hash.

See number_to_human if you want to pretty-print a generic number.

Options

  • :locale - Sets the locale to be used for formatting (defaults to current locale).
  • :precision - Sets the precision of the number (defaults to 3).
  • :significant - If true, precision will be the # of significant_digits. If false, the # of fractional digits (defaults to true)
  • :separator - Sets the separator between the fractional and integer digits (defaults to “.”).
  • :delimiter - Sets the thousands delimiter (defaults to “”).
  • :strip_insignificant_zeros - If true removes insignificant zeros after the decimal separator (defaults to true)
  • :prefix - If :si formats the number using the SI prefix (defaults to :binary)
  • :raise - If true, raises InvalidNumberError when the argument is invalid.

Examples

 number_to_human_size(123)                                          # => 123 Bytes
 number_to_human_size(1234)                                         # => 1.21 KB
 number_to_human_size(12345)                                        # => 12.1 KB
 number_to_human_size(1234567)                                      # => 1.18 MB
 number_to_human_size(1234567890)                                   # => 1.15 GB
 number_to_human_size(1234567890123)                                # => 1.12 TB
 number_to_human_size(1234567, :precision => 2)                     # => 1.2 MB
 number_to_human_size(483989, :precision => 2)                      # => 470 KB
 number_to_human_size(1234567, :precision => 2, :separator => ',')  # => 1,2 MB

Non-significant zeros after the fractional separator are stripped out by default (set :strip_insignificant_zeros to false to change that):

 number_to_human_size(1234567890123, :precision => 5)        # => "1.1229 TB"
 number_to_human_size(524288000, :precision => 5)            # => "500 MB"
     # File actionpack/lib/action_view/helpers/number_helper.rb, line 364
364:       def number_to_human_size(number, options = {})
365:         options.symbolize_keys!
366: 
367:         number = begin
368:           Float(number)
369:         rescue ArgumentError, TypeError
370:           if options[:raise]
371:             raise InvalidNumberError, number
372:           else
373:             return number
374:           end
375:         end
376: 
377:         defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
378:         human    = I18n.translate(:'number.human.format', :locale => options[:locale], :default => {})
379:         defaults = defaults.merge(human)
380: 
381:         options = options.reverse_merge(defaults)
382:         #for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files
383:         options[:strip_insignificant_zeros] = true if not options.key?(:strip_insignificant_zeros)
384: 
385:         storage_units_format = I18n.translate(:'number.human.storage_units.format', :locale => options[:locale], :raise => true)
386: 
387:         base = options[:prefix] == :si ? 1000 : 1024
388: 
389:         if number.to_i < base
390:           unit = I18n.translate(:'number.human.storage_units.units.byte', :locale => options[:locale], :count => number.to_i, :raise => true)
391:           storage_units_format.gsub(/%n/, number.to_i.to_s).gsub(/%u/, unit).html_safe
392:         else
393:           max_exp  = STORAGE_UNITS.size - 1
394:           exponent = (Math.log(number) / Math.log(base)).to_i # Convert to base
395:           exponent = max_exp if exponent > max_exp # we need this to avoid overflow for the highest unit
396:           number  /= base ** exponent
397: 
398:           unit_key = STORAGE_UNITS[exponent]
399:           unit = I18n.translate(:"number.human.storage_units.units.#{unit_key}", :locale => options[:locale], :count => number, :raise => true)
400: 
401:           formatted_number = number_with_precision(number, options)
402:           storage_units_format.gsub(/%n/, formatted_number).gsub(/%u/, unit).html_safe
403:         end
404:       end
number_to_percentage(number, options = {})

Formats a number as a percentage string (e.g., 65%). You can customize the format in the options hash.

Options

  • :locale - Sets the locale to be used for formatting (defaults to current
                                            locale).
    
  • :precision - Sets the precision of the number (defaults to 3).
  • :significant - If true, precision will be the # of significant_digits. If false,
                                            the # of fractional digits (defaults to +false+).
    
  • :separator - Sets the separator between the fractional and integer digits (defaults
                                            to ".").
    
  • :delimiter - Sets the thousands delimiter (defaults to “”).
  • :strip_insignificant_zeros - If true removes insignificant zeros after the decimal separator
                                            (defaults to +false+).
    
  • :raise - If true, raises InvalidNumberError when the argument is invalid.

Examples

 number_to_percentage(100)                                        # => 100.000%
 number_to_percentage("98")                                       # => 98.000%
 number_to_percentage(100, :precision => 0)                       # => 100%
 number_to_percentage(1000, :delimiter => '.', :separator => ',') # => 1.000,000%
 number_to_percentage(302.24398923423, :precision => 5)           # => 302.24399%
 number_to_percentage(1000, :locale => :fr)                       # => 1 000,000%
 number_to_percentage("98a")                                      # => 98a%

 number_to_percentage("98a", :raise => true)                      # => InvalidNumberError
     # File actionpack/lib/action_view/helpers/number_helper.rb, line 186
186:       def number_to_percentage(number, options = {})
187:         return unless number
188: 
189:         options.symbolize_keys!
190: 
191:         defaults   = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
192:         percentage = I18n.translate(:'number.percentage.format', :locale => options[:locale], :default => {})
193:         defaults  = defaults.merge(percentage)
194: 
195:         options = options.reverse_merge(defaults)
196: 
197:         begin
198:           "#{number_with_precision(number, options.merge(:raise => true))}%".html_safe
199:         rescue InvalidNumberError => e
200:           if options[:raise]
201:             raise
202:           else
203:             e.number.to_s.html_safe? ? "#{e.number}%".html_safe : "#{e.number}%"
204:           end
205:         end
206:       end
number_to_phone(number, options = {})

Formats a number into a US phone number (e.g., (555) 123-9876). You can customize the format in the options hash.

Options

  • :area_code - Adds parentheses around the area code.
  • :delimiter - Specifies the delimiter to use (defaults to “-”).
  • :extension - Specifies an extension to add to the end of the
                              generated number.
    
  • :country_code - Sets the country code for the phone number.
  • :raise - If true, raises InvalidNumberError when the argument is invalid.

Examples

 number_to_phone(5551234)                                           # => 555-1234
 number_to_phone("5551234")                                         # => 555-1234
 number_to_phone(1235551234)                                        # => 123-555-1234
 number_to_phone(1235551234, :area_code => true)                    # => (123) 555-1234
 number_to_phone(1235551234, :delimiter => " ")                     # => 123 555 1234
 number_to_phone(1235551234, :area_code => true, :extension => 555) # => (123) 555-1234 x 555
 number_to_phone(1235551234, :country_code => 1)                    # => +1-123-555-1234
 number_to_phone("123a456")                                         # => 123a456

 number_to_phone("1234a567", :raise => true)                        # => InvalidNumberError

 number_to_phone(1235551234, :country_code => 1, :extension => 1343, :delimiter => ".")
 # => +1.123.555.1234 x 1343
    # File actionpack/lib/action_view/helpers/number_helper.rb, line 59
59:       def number_to_phone(number, options = {})
60:         return unless number
61: 
62:         begin
63:           Float(number)
64:         rescue ArgumentError, TypeError
65:           raise InvalidNumberError, number
66:         end if options[:raise]
67: 
68:         number       = number.to_s.strip
69:         options      = options.symbolize_keys
70:         area_code    = options[:area_code]
71:         delimiter    = options[:delimiter] || "-"
72:         extension    = options[:extension]
73:         country_code = options[:country_code]
74: 
75:         if area_code
76:           number.gsub!(/(\d{1,3})(\d{3})(\d{4}$)/,"(\\1) \\2#{delimiter}\\3")
77:         else
78:           number.gsub!(/(\d{0,3})(\d{3})(\d{4})$/,"\\1#{delimiter}\\2#{delimiter}\\3")
79:           number.slice!(0, 1) if number.starts_with?(delimiter) && !delimiter.blank?
80:         end
81: 
82:         str = []
83:         str << "+#{country_code}#{delimiter}" unless country_code.blank?
84:         str << number
85:         str << " x #{extension}" unless extension.blank?
86:         ERB::Util.html_escape(str.join)
87:       end
number_with_delimiter(number, options = {})

Formats a number with grouped thousands using delimiter (e.g., 12,324). You can customize the format in the options hash.

Options

  • :locale - Sets the locale to be used for formatting (defaults to current locale).
  • :delimiter - Sets the thousands delimiter (defaults to “,”).
  • :separator - Sets the separator between the fractional and integer digits (defaults to “.”).
  • :raise - If true, raises InvalidNumberError when the argument is invalid.

Examples

 number_with_delimiter(12345678)                        # => 12,345,678
 number_with_delimiter("123456")                        # => 123,456
 number_with_delimiter(12345678.05)                     # => 12,345,678.05
 number_with_delimiter(12345678, :delimiter => ".")     # => 12.345.678
 number_with_delimiter(12345678, :delimiter => ",")     # => 12,345,678
 number_with_delimiter(12345678.05, :separator => " ")  # => 12,345,678 05
 number_with_delimiter(12345678.05, :locale => :fr)     # => 12 345 678,05
 number_with_delimiter("112a")                          # => 112a
 number_with_delimiter(98765432.98, :delimiter => " ", :separator => ",")
 # => 98 765 432,98

 number_with_delimiter("112a", :raise => true)          # => raise InvalidNumberError
     # File actionpack/lib/action_view/helpers/number_helper.rb, line 232
232:       def number_with_delimiter(number, options = {})
233:         options.symbolize_keys!
234: 
235:         begin
236:           Float(number)
237:         rescue ArgumentError, TypeError
238:           if options[:raise]
239:             raise InvalidNumberError, number
240:           else
241:             return number
242:           end
243:         end
244: 
245:         defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
246:         options = options.reverse_merge(defaults)
247: 
248:         parts = number.to_s.to_str.split('.')
249:         parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{options[:delimiter]}")
250:         parts.join(options[:separator]).html_safe
251: 
252:       end
number_with_precision(number, options = {})

Formats a number with the specified level of :precision (e.g., 112.32 has a precision of 2 if :significant is false, and 5 if :significant is true). You can customize the format in the options hash.

Options

  • :locale - Sets the locale to be used for formatting (defaults to current locale).
  • :precision - Sets the precision of the number (defaults to 3).
  • :significant - If true, precision will be the # of significant_digits. If false,
                                           the # of fractional digits (defaults to +false+).
    
  • :separator - Sets the separator between the fractional and integer digits (defaults
                                           to ".").
    
  • :delimiter - Sets the thousands delimiter (defaults to “”).
  • :strip_insignificant_zeros - If true removes insignificant zeros after the decimal separator
                                           (defaults to +false+).
    
  • :raise - If true, raises InvalidNumberError when the argument is invalid.

Examples

 number_with_precision(111.2345)                                            # => 111.235
 number_with_precision(111.2345, :precision => 2)                           # => 111.23
 number_with_precision(13, :precision => 5)                                 # => 13.00000
 number_with_precision(389.32314, :precision => 0)                          # => 389
 number_with_precision(111.2345, :significant => true)                      # => 111
 number_with_precision(111.2345, :precision => 1, :significant => true)     # => 100
 number_with_precision(13, :precision => 5, :significant => true)           # => 13.000
 number_with_precision(111.234, :locale => :fr)                             # => 111,234

 number_with_precision(13, :precision => 5, :significant => true, :strip_insignificant_zeros => true)
 # => 13

 number_with_precision(389.32314, :precision => 4, :significant => true)    # => 389.3
 number_with_precision(1111.2345, :precision => 2, :separator => ',', :delimiter => '.')
 # => 1.111,23
     # File actionpack/lib/action_view/helpers/number_helper.rb, line 286
286:       def number_with_precision(number, options = {})
287:         options.symbolize_keys!
288: 
289:         number = begin
290:           Float(number)
291:         rescue ArgumentError, TypeError
292:           if options[:raise]
293:             raise InvalidNumberError, number
294:           else
295:             return number
296:           end
297:         end
298: 
299:         defaults           = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
300:         precision_defaults = I18n.translate(:'number.precision.format', :locale => options[:locale], :default => {})
301:         defaults           = defaults.merge(precision_defaults)
302: 
303:         options = options.reverse_merge(defaults)  # Allow the user to unset default values: Eg.: :significant => false
304:         precision = options.delete :precision
305:         significant = options.delete :significant
306:         strip_insignificant_zeros = options.delete :strip_insignificant_zeros
307: 
308:         if significant and precision > 0
309:           if number == 0
310:             digits, rounded_number = 1, 0
311:           else
312:             digits = (Math.log10(number.abs) + 1).floor
313:             rounded_number = (BigDecimal.new(number.to_s) / BigDecimal.new((10 ** (digits - precision)).to_f.to_s)).round.to_f * 10 ** (digits - precision)
314:             digits = (Math.log10(rounded_number.abs) + 1).floor # After rounding, the number of digits may have changed
315:           end
316:           precision -= digits
317:           precision = precision > 0 ? precision : 0  #don't let it be negative
318:         else
319:           rounded_number = BigDecimal.new(number.to_s).round(precision).to_f
320:         end
321:         formatted_number = number_with_delimiter("%01.#{precision}f" % rounded_number, options)
322:         if strip_insignificant_zeros
323:           escaped_separator = Regexp.escape(options[:separator])
324:           formatted_number.sub(/(#{escaped_separator})(\d*[1-9])?0+\z/, '\1\2').sub(/#{escaped_separator}\z/, '').html_safe
325:         else
326:           formatted_number
327:         end
328: 
329:       end