The Complete Guide to String Formatting in C#

String formatting is one of the most essential skills in C#. Whether you’re building APIs, reports, UI output, logs, or debugging tools, formatting text correctly makes your code clearer, faster to write, and easier to maintain.

This ultimate guide explains every major formatting technique, how it works, why it exists, and includes over 50 practical examples you can use immediately.


πŸ”₯ The Four Main Ways to Format Strings in C#

C# gives you several tools for formatting text. Each serves a different purpose:

  1. String Concatenation (+)
    Quick but messy – useful only for tiny one-offs.
  2. Composite Formatting (string.Format, Console.WriteLine("{0}", ...))
    Uses numbered placeholders {0}, {1} – older but still used in logging and localisation.
  3. String Interpolation ($"Hello {name}")
    The modern standard – readable, powerful, uses braces {} to embed expressions.
  4. Formatted Interpolation ({value:format})
    Interpolation with built-in format specifiers for numbers, dates, alignment, etc.

⭐ 1. String Concatenation (+)

What it does

  • Joins strings using the + operator
  • The compiler converts the expression into calls to string.Concat
  • Not recommended for long or dynamic output because of performance

Example

string name = "James";
string msg = "Hello " + name + ", welcome!";

Why use it

  • Minimal syntax
  • OK for small pieces of code or quick debugging

⭐ 2. Composite Formatting (string.Format)

What it does

  • Uses positional placeholders like {0}, {1}
  • Supports full format specifiers ({0:C}, {0:dd/MM/yyyy})
  • Great for localisation because string layout can move positions without code changes

Example

string result = string.Format("Name: {0}, Age: {1}", "James", 58);

Why use it

  • Useful in logging frameworks
  • Good for apps needing localisation (UI strings from resources)

⭐ 3. String Interpolation ($"...")

What it does

  • Treats anything inside {} as a C# expression
  • Replaces it with the resulting string
  • Cleaner, safer, faster – preferred modern approach

Example

string msg = $"Hello {name}, you are {age} years old.";

Why use it

  • Best readability
  • Fewer mistakes
  • Allows expressions directly inside {}

⭐ 4. Interpolated Format Strings ({value:format})

What it does

  • Applies a format specifier to values inside an interpolated string
  • Works for numbers, dates, currency, alignment, hex, percentages, and custom formats

Example

double price = 9.99;
string txt = $"Price: {price:C}";

Why use it

  • Clean, powerful formatting
  • Preferred for all production-quality output

πŸ”₯ Standard Numeric Format Strings

C# numeric formats are extremely powerful. You can control decimal places, currency, percentage, padding, hex, and more.

Here’s what each specifier does:


N – Number format

Adds commas and thousands separators, applies decimal formatting.

double n = 12345.678;
$"{n:N}"      // "12,345.68"
$"{n:N3}"     // "12,345.678"

F – Fixed-point

Shows a fixed number of decimals (default = 2).

$"{n:F0}"     // "12346"
$"{n:F3}"     // "12345.678"

C – Currency

Uses your system’s culture (Β£ for UK, $ for US, etc.).

double price = 19.5;
$"{price:C}"   // Β£19.50 (UK)

E – Exponential/scientific notation

Useful for scientific programming.

double value = 1234;
$"{value:E2}"   // "1.23E+003"

P – Percent

Multiplies by 100 and adds a percent sign.

double ratio = 0.125;
$"{ratio:P}"      // "12.50 %"
$"{ratio:P0}"     // "13%"

D – Decimal (integers only)

Pads numbers with zeros.

int id = 42;
$"{id:D6}"      // "000042"

X – Hexadecimal

Useful in hardware programming, hashing, or bitwork.

int number = 255;
$"{number:X}"  // "FF"

πŸ”₯ Custom Numeric Format Strings

0 – Zero placeholder

Shows digits; inserts zeros if missing.

double v = 5.2;
$"{v:000.00}"   // "005.20"

# – Digit placeholder

Shows digits only if they exist.

double v = 5.2;
$"{v:###.##}"   // "5.2"

, – Thousands separator

$"{1234567:#,##0}" // "1,234,567"

. – Decimal point

$"{123.456:#.00}" // "123.46"

% – Percentage

$"{0.75:#0%}"  // "75%"

πŸ”₯ DateTime Formatting

C# supports both standard and custom date formats.


Standard formats

d – Short Date

DateTime dt = DateTime.Now;
$"{dt:d}"  // "23/11/2025"

D – Long Date

$"{dt:D}"  // "Sunday, 23 November 2025"

T – Long Time

$"{dt:T}"  // "14:52:30"

o – Round-trip ISO 8601

Perfect for APIs and JSON.

$"{dt:o}"  // "2025-11-23T14:52:30.0000000Z"

Custom formats

FormatMeaningExample
yyyy4-digit year2025
MMMonth with leading zero03
ddDay with leading zero07
HH24-hour16
mmMinutes09
ssSeconds42

Example:

$"{dt:yyyy-MM-dd HH:mm:ss}"

πŸ”₯ Alignment and Padding

Alignment in interpolation uses a comma:

$"{value,10}"  // right-aligned in 10 chars
$"{value,-10}" // left-aligned

This is commonly used in console tables.


πŸ”₯ Escaping Braces {}

Because {} are formatting markers, escape them with double braces:

$"This prints a brace: {{ and }}"

πŸ”₯ Formatting Using IFormatProvider

You can force a different culture:

var fr = new CultureInfo("fr-FR");
$"{1234.56.ToString("N", fr)}"   // "1 234,56"

πŸ”₯ Building Complex Strings (Advanced Techniques)

StringBuilder

Best for performance when generating large text.

var sb = new StringBuilder();
sb.AppendLine($"Name: {name}");
sb.AppendLine($"Age: {age}");

πŸ”₯ ToString Overloads on Custom Types

You can override ToString:

public override string ToString() => $"{FirstName} {LastName}";

Or support formatting:

πŸ”₯ String Formatting – Example Code:

πŸ”΅ Basic String Interpolation

String interpolation ($"...") is the cleanest and most modern way to build formatted strings.

1. Insert a variable

string name = "James";
$"Hello {name}";

➑ Inserts the value directly into the string.

2. Insert expressions

$"2 + 2 = {2 + 2}";

➑ Expressions are evaluated before formatting.

3. Call methods inline

$"Upper: {name.ToUpper()}";

➑ Any valid C# expression can be used.

4. Inline conditional

$"Status: {(isActive ? "Active" : "Inactive")}";

➑ Great for status messages.

5. Escape braces

$"Braces: {{hello}}";

➑ Use {{ or }} to output { or }.


πŸ”΅ Numeric Standard Format Strings

These are built-in formats for numbers.

6. Number with commas

$"{12345.678:N}"

➑ Adds thousands separators and 2 decimals.

7. Number with 3 decimals

$"{12345.678:N3}"

8. Fixed point

$"{123.456:F}"

➑ Always shows 2 decimals.

9. No decimals

$"{123.456:F0}"

10. Currency

$"{9.99:C}"

➑ Uses system locale.

11. Currency with US format

9.99.ToString("C", new CultureInfo("en-US"));

12. Percent

$"{0.123:P}"

➑ Shows 12.30%.

13. Percent whole number

$"{0.123:P0}" // "12%"

14. Hex

$"{255:X}";

15. Decimal padded

$"{42:D5}"   // "00042"

πŸ”΅ Custom Numeric Formats

These allow incredibly fine control.

16. Zero placeholder

$"{5.2:000.00}";

➑ Pads missing digits with zeros.

17. Digit placeholder

$"{5.2:###.##}";

➑ Only prints real digits.

18. Thousands separator

$"{1234567:#,##0}";

19. Force sign

$"{42:+#;-#;0}";

➑ Output like +42 / -42.

20. Custom percent

$"{0.75:#0%}";

21. Custom suffix

$"{1000:#,##0 coins}";

22. Phone number formatting

$"{1234567890:(###) ###-####}";

πŸ”΅ Date and Time Formatting

23. Short date

$"{DateTime.Now:d}";

24. Long date

$"{DateTime.Now:D}";

25. Full date/time

$"{DateTime.Now:F}";

26. ISO 8601

$"{DateTime.Now:o}";

27. yyyy-MM-dd

$"{DateTime.Now:yyyy-MM-dd}";

28. HH:mm:ss

$"{DateTime.Now:HH:mm:ss}";

29. Combined custom

$"{DateTime.Now:ddd, dd MMM yyyy HH:mm}";

30. Month name

$"{DateTime.Now:MMMM}";

πŸ”΅ Alignment & Padding

Useful for console tables and formatted reports.

31. Right-align in 10 characters

$"{42,10}";

32. Left-align

$"{42,-10}";

33. Alignment with format

$"{1234,10:N0}";

34. Table header

$"{ "Name",-15 } { "Score",10 }";

35. Table row

$"{player,-15} {score,10}";

πŸ”΅ StringBuilder Formatting

36. AppendLine with interpolation

sb.AppendLine($"User: {name}");

37. Build a report

sb.AppendLine($"Total: {total:C}");
sb.AppendLine($"Date: {DateTime.Now:yyyy-MM-dd}");

πŸ”΅ Formatting Custom Types (ToString)

38. Override ToString

public override string ToString() => $"{First} {Last}";

39. Support custom formats

public string ToString(string format) =>
    format switch
    {
        "L" => $"{Last}, {First}",
        "F" => $"{First} {Last}",
        _ => ToString()
    };

40. Using the custom format

$"{person:F}";

πŸ”΅ 8. Culture-Specific Formatting

41. French

$"{1234.56.ToString("N", new CultureInfo("fr-FR"))}";

➑ "1 234,56"

42. German

$"{1234.56.ToString("C", new CultureInfo("de-DE"))}";

➑ "1.234,56 €"


πŸ”΅ Interpolated Verbatim Strings ($@"...")

Great for JSON, SQL, multi-line literals.

43. Multi-line JSON

string json = $@"
{{
    ""name"": ""{name}"",
    ""age"": {age}
}}";

44. Paths

string path = $@"C:\Users\{username}\Documents";

πŸ”΅ Logging & Diagnostics Formatting

45. Timestamp log

$"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] INFO: {msg}";

46. Warning log

$"[{DateTime.Now:T}] WARNING: {warning}";

47. Error log

$"[{DateTime.Now:o}] ERROR: {ex.Message}";

πŸ”΅ Miscellaneous Useful Formatting

48. Format booleans

$"{isReady ? "READY" : "WAIT"}";

49. Enum name

$"{status:G}";

50. Byte array β†’ hex

BitConverter.ToString(bytes).Replace("-", "");

51. Ordinal suffix

$"{day}{(day % 10 == 1 ? "st" : day % 10 == 2 ? "nd" : day % 10 == 3 ? "rd" : "th")}";

52. Pad with characters

"Hello".PadLeft(10, '*');

53. Accounting negatives

$"{-1234:#,##0;(#,##0);0}";

54. File size formatter

$"{bytes / 1024.0:N2} KB";

55. TimeSpan

$"{ts:hh\\:mm\\:ss}";