⌕ Test & Debug

.NET Format String Tester (C# ToString)

Test C# DateTime, DateTimeOffset and number format strings — standard and custom — in five cultures, with output verified against real .NET 8 and a table of common formats.

Matches real .NET 8 Standard & custom formats 5 cultures incl. en-IN Midpoint rounding explained

Loading .NET Format Tester…

What this page sends

  • Your input: Processed in this tab and not sent to a server.
  • Page load: Loading the page requests HTML, scripts and images from ByteKiln, fonts from Google Fonts, and sends Google Analytics page views, tool-usage events and catalog interactions (tool/category IDs, result status and whether a click followed search — never your input, output or search terms). Privacy & sharing

How the .NET Format String Tester (C# ToString) Works

Format strings are one of those things you look up every time: is it MM or mm for months, what does "N" do in German, why does F2 round 2.675 down, how do I show millions with #,##0,,? This tester answers by running the format. Choose int, long, double, decimal, DateTime or DateTimeOffset, enter a value and a format string, pick one of five cultures, and see the result — plus a table of the common standard and custom formats for the same value, and a copyable C# snippet. The formatting engine is a line-by-line re-implementation of .NET 8's Number.Formatting and DateTimeFormat logic, with NumberFormatInfo and DateTimeFormatInfo data exported from .NET for InvariantCulture, en-US, en-GB, en-IN and de-DE. Because a formatter that is almost right is worse than none, it is tested against 24,540 values formatted by real .NET 8 — every numeric standard specifier with precision, custom patterns with sections, literals, scaling and exponents, and every date standard and custom specifier — and all of them match. Edge cases are explained where they bite: midpoint rounding differences between double and decimal, negative zero, two's-complement hex, Indian digit grouping, and time zone handling.

Numbers

Standard formats (C, D, E, F, G, N, P, R, X) and custom patterns (0, #, ., ,, %, ‰, E+0, sections with ;, quoted literals and \ escapes) are supported for int, long, double and decimal. Doubles use the exact binary value for standard formats with ties to even, and 15 significant digits for custom formats; decimals round half away from zero and keep trailing zeros in "G".

Dates

Standard formats (d D f F g G M O R s t T u U Y) expand to the culture's patterns; custom specifiers (yyyy, MMMM, dddd, HH, hh, tt, fff, FFF, K, zzz, quotes, %, \) are applied like .NET, including genitive month names (de-DE: "5. März") and the rule that "F" removes a preceding dot when the fraction is zero. R and u convert DateTimeOffset values to UTC.

Accuracy

The reference cases are generated by a small .NET console program included in the repository (tools-fixtures/dotnet-format), which also exports the culture data. The .NET and ICU versions are pinned and shown on this page; culture details such as default decimals and the space before AM/PM can differ with other ICU versions or with Windows NLS mode.

Time zones

DateTimeOffset carries its own offset. DateTime with Kind=Utc prints "Z" for K and +00:00 for zzz. DateTime with Kind=Unspecified is treated by .NET as local time for zzz and U, so the tool asks for the server's offset instead of guessing.

Limitations

  • It is a re-implementation checked against 24,540 results from real .NET 8, not .NET itself; combinations outside that test set can still differ.
  • Five cultures only (invariant, en-US, en-GB, en-IN, de-DE), with .NET 8 ICU data — Windows NLS data and other versions can differ in details such as month abbreviations.
  • Formatting only: no DateTime.Parse/ParseExact, composite format strings ({0:N2}), custom IFormatProvider or TimeSpan formats.

FAQ

Short answers for the things developers usually ask before trusting a tool.

Is this real .NET?

No — .NET doesn't run in the page. It's a TypeScript re-implementation of .NET 8's number and date formatting, using culture data exported from .NET itself. It is tested against 24,540 values formatted by real .NET 8 (with ICU on Linux) across all five cultures, and every one matches. The exact .NET and ICU versions are shown on the page.

Which cultures are supported?

InvariantCulture, en-US, en-GB, en-IN (Indian grouping, 12,34,567.89) and de-DE (comma decimal, period grouping). Other cultures aren't guessed.

Why does 2.675.ToString("F2") give 2.67?

Because 2.675 can't be stored exactly as a double — it's really 2.67499999999999982236431605997495353221893310546875 — and .NET Core 3.0+ formats standard specifiers from the exact value, rounding exact ties to even. Custom formats like "0.00" first round to 15 significant digits, giving 2.67500000000000 and then 2.68. decimal stores 2.675 exactly and rounds away from zero: 2.68.

Why does "N" show three decimals?

The default number of decimals comes from the culture. With ICU (which .NET uses on Linux and macOS, and on Windows 10 version 1903 and later by default since .NET 5), NumberDecimalDigits is 3 for en-US, en-GB, en-IN and de-DE, so N without a precision gives three decimals. Specify it — "N2" — whenever the number of decimals matters.

Why is there a strange space before AM/PM?

Newer ICU versions (CLDR 42+) put a narrow no-break space (U+202F) between the time and AM/PM for en-US. It looks like a space but isn't, so string comparisons in tests fail. Use InvariantCulture or a custom format like "h:mm tt" with an explicit space when you need a stable format.

What do K and zzz do?

For DateTimeOffset both give the offset (+05:30). For DateTime, K gives "Z" for Kind=Utc and nothing for Unspecified, while zzz on an Unspecified DateTime uses the server's local time zone — a common source of bugs. Prefer DateTimeOffset, or "O" for round-trip output.

Related tools

Useful follow-ups when one conversion usually turns into three more.

Related guides