No description
  • TypeScript 76.4%
  • JavaScript 17.4%
  • Shell 6.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Andy Turner fd900d8445
All checks were successful
git-ci/decimal-format/pipeline/head This commit looks good
Merge branch 'main' of https://git.andyjturner.com/ci/decimal-format
2026-09-16 11:42:35 +01:00
.jenkins Added typescript dev dependency 2026-09-16 08:48:09 +01:00
.gitignore Added typescript dev dependency 2026-09-16 08:43:30 +01:00
decimal-format.test.mjs Initial Commit 2026-09-16 08:36:57 +01:00
decimal-format.ts Initial Commit 2026-09-16 08:36:57 +01:00
java-reference.tsv Initial Commit 2026-09-16 08:36:57 +01:00
Jenkinsfile Initial Commit 2026-09-16 08:36:57 +01:00
package-lock.json Added typescript dev dependency 2026-09-16 08:43:30 +01:00
package.json Export types 2026-09-16 11:40:25 +01:00
README.md Initial Commit 2026-09-16 08:36:57 +01:00
tsconfig.json Initial Commit 2026-09-16 08:36:57 +01:00

DecimalFormat for TypeScript

A dependency-free module implementing Java-style number patterns. Copy decimal-format.ts into your project. Requires an ES2022-compatible runtime (BigInt, DataView and Unicode property escapes).

import { DecimalFormat, formatNumber, parseNumber } from './decimal-format';

const amount = new DecimalFormat('#,##0.00;(#,##0.00)');
amount.format(-1234.5);             // '(1,234.50)'
amount.parse('(1,234.50)');         // -1234.5
formatNumber(0.125, '0.0%');        // '12.5%'
parseNumber('12.5%', '0.0%');       // 0.125
new DecimalFormat('0.###E0').format(1234); // '1.234E3'
amount.parsePrefix('1,234.50 remaining'); // { value: 1234.5, index: 8 }

Supported features include 0 and # digit placeholders, decimal and grouping separators, positive/negative subpatterns, quoted affixes and doubled apostrophes, percent/per-mille scaling, currency signs (¤ and ¤¤), scientific/engineering notation, half-even rounding, negative zero, NaN, infinity and customizable output symbols. The final grouping interval repeats, as in Java. Negative subpatterns supply affixes; the positive subpattern controls numeric formatting.

const european = new DecimalFormat('#,##0.00', {
  decimalSeparator: ',',
  groupingSeparator: '.',
});
european.format(1234.5); // '1.234,50'
european.parse('1.234,50'); // 1234.5

Patterns always use the non-localized Java syntax, regardless of symbol overrides. For currency patterns, set monetaryDecimalSeparator and monetaryGroupingSeparator separately. Currency defaults are $ / USD; no currency conversion or automatic locale selection occurs. zeroDigit configures ten consecutive output digits; parsing additionally recognizes Unicode decimal digits.

parse requires a complete match and throws SyntaxError on failure. parsePrefix(text, start?) returns { value, index } or null, with JavaScript UTF-16 indexes. It does not skip whitespace unless the pattern includes it. Grouping is permissive, and pattern digit counts do not restrict parsing. Invalid patterns throw during construction.

Compatibility scope

This is a practical pattern implementation, not a complete port of Java's DecimalFormat API. It accepts and returns JavaScript number, so it does not preserve arbitrary-precision integers or decimals. It has no BigDecimal/BigInteger overloads, localized-pattern API, mutable Java setters, parse-integer-only mode, or selectable rounding modes. Patterns require a numeric section and are limited to 1,000 digit placeholders. Ambiguous or overlapping custom symbols/affixes should be avoided. Java's less common pattern acceptance and ambiguous parsing behavior are not guaranteed to match. IEEE-754 rounding edge cases can vary across Java versions.

The implementation uses the exact binary value for half-even rounding after applying percentage/per-mille multiplication. Thus decimal-looking inputs such as 2.675 can format to 2.67, reflecting the stored binary number.

Syntax reference: Oracle DecimalFormat documentation.

Validation

Run npm test with Node 22.18+ (native TypeScript stripping). The suite includes feature tests and 80 formatting fixtures captured from OpenJDK 11 using US symbols. These fixtures are regression coverage, not proof of complete Java equivalence. A strict tsconfig.json is included for projects with TypeScript installed; run tsc to emit JavaScript and declarations. The delivered tests were executed with Node 25; a standalone TypeScript compiler was unavailable in the creation environment.