The Format Function
Master every way VB 2026 formats numbers, dates, and strings — standard format specifiers (C, F, N, P, E, G), custom numeric and date patterns, String.Format, interpolated strings with specifiers, and the legacy Format() function.
value.ToString("format"), String.Format("{0:format}", value), and interpolated strings $"{value:format}". All three use the same format specifiers. The legacy VB6-style Format(value, "pattern") function still works but the modern approaches are preferred. For numbers, memorise: C = Currency, F = Fixed decimal, N = Number with thousands separator, P = Percentage, E = Scientific, G = General (shortest). For dates, d = short date, D = long date, t = short time, T = long time, f = full, s = sortable.
20.1 Three Ways to Format in VB 2026
' All three produce the same result: "RM 1,234.57" ' 1. ToString with format specifier (most concise) Dim price = 1234.567 lblA.Text = price.ToString("C2") ' "RM 1,234.57" (culture-dependent) ' 2. String.Format -- good for building composite strings lblB.Text = String.Format("Total: {0:C2}", price) ' "Total: RM 1,234.57" ' 3. Interpolated string $ -- most readable, VB 2026 preferred lblC.Text = $"Total: {price:C2}" ' "Total: RM 1,234.57" ' Multiple values in one interpolated string Dim qty = 3, unitPrice = 29.99, total = qty * unitPrice lblReceipt.Text = $"{qty} x {unitPrice:C2} = {total:C2}" ' "3 x RM29.99 = RM89.97" ' Legacy VB6 Format() function -- still works in VB 2026 lblD.Text = Format(price, "Currency") ' "RM 1,234.57" lblE.Text = Format(price, "Fixed") ' "1234.57" lblF.Text = Format(price, "Standard") ' "1,234.57" lblG.Text = Format(price, "Percent") ' "123,456.70%"
20.2 Standard Number Format Specifiers
A format specifier is a single letter optionally followed by a precision digit. The letter sets the style; the digit sets the number of decimal places (or significant digits for G and E).
| Specifier | Name | Example (1234.5678) | Notes |
|---|---|---|---|
| C or C2 | Currency | RM 1,234.57 | Uses culture's currency symbol & separator. C2 = 2 decimal places. |
| F or F4 | Fixed-point | 1234.5678 | F = 2 decimal places by default. F4 = 4. No thousands separator. |
| N or N2 | Number | 1,234.57 | Like F but adds thousands separator. N0 = no decimals. |
| P or P1 | Percent | 123,456.78% | Multiplies by 100 then adds %. Use 0.1234 to get "12.34%". |
| E or E3 | Scientific | 1.235E+003 | E3 = 3 decimal places in mantissa. E = 6 by default. |
| G or G4 | General | 1234.6 | Shortest of fixed or scientific. G4 = 4 significant digits. |
| D or D5 | Decimal (integers) | 01235 | Zero-pads integers to minimum width. D5 of 42 = "00042". |
| X or X8 | Hexadecimal | 4D2 | X = uppercase, x = lowercase. X8 zero-pads to 8 chars. |
| R | Round-trip | 1234.5678 | Guarantees parse(format(x)) = x. Use for serialising doubles. |
Dim n = 1234.5678 ' Currency n.ToString("C") ' "RM 1,234.57" (2 dp, culture symbol) n.ToString("C0") ' "RM 1,235" (0 dp, rounded) n.ToString("C4") ' "RM 1,234.5678" (4 dp) ' Fixed-point n.ToString("F") ' "1234.57" n.ToString("F0") ' "1235" n.ToString("F4") ' "1234.5678" ' Number (with thousands separator) n.ToString("N") ' "1,234.57" n.ToString("N0") ' "1,235" ' Percent -- value is multiplied by 100 first (0.1234).ToString("P") ' "12.34%" (0.1234).ToString("P1") ' "12.3%" (0.1234).ToString("P0") ' "12%" ' Scientific n.ToString("E") ' "1.234568E+003" n.ToString("E2") ' "1.23E+003" n.ToString("e4") ' "1.2346e+003" (lowercase e) ' General n.ToString("G") ' "1234.5678" (shortest representation) n.ToString("G4") ' "1235" (4 significant digits) (0.000012345).ToString("G3") ' "1.23E-05" (switches to scientific) ' Integer formats (42).ToString("D5") ' "00042" (zero-padded to 5 digits) (255).ToString("X") ' "FF" (hexadecimal) (255).ToString("X8") ' "000000FF" (8-char hex, zero-padded)
Enter any number and choose a format specifier. See the VB call, the result, and a side-by-side comparison of all standard formats for the same value.
20.3 Custom Numeric Format Patterns
When the standard specifiers don't give enough control, use a custom pattern with special characters: 0 (digit or zero), # (digit or nothing), . (decimal point), , (thousands separator or scale), % (multiply by 100), E+0 (scientific), and ; (positive;negative;zero sections).
| Pattern char | Meaning | Example | Input 1234.5 |
|---|---|---|---|
| 0 | Digit placeholder — always shows a digit (zero if absent) | "00000.00" | "01234.50" |
| # | Optional digit — nothing if absent | "#,###.##" | "1,234.5" |
| . | Decimal point | "0.###" | "1234.5" |
| , | Thousands separator (when between digits) | "#,##0.00" | "1,234.50" |
| ,, (after digits) | Scale divisor by 1,000 per comma | "0,,M" | "0M" (millionths) |
| % | Multiply by 100 and append % | "0.0%" | "123456.8%" (if input 1234.5) |
| ; sections | pos;neg;zero patterns | "#,##0.00;(#,##0.00);Zero" | Pos / (Neg) / Zero |
Dim n = 1234.5 ' 0 vs # placeholder n.ToString("00000.00") ' "01234.50" -- 0 always shows digit n.ToString("#,###.##") ' "1,234.5" -- # omits trailing zeros n.ToString("#,##0.00") ' "1,234.50" -- standard accounting format ' Currency with RM prefix (no culture dependency) n.ToString("'RM' #,##0.00") ' "RM 1,234.50" ' Positive / negative / zero sections (separated by ;) (1234.5).ToString("#,##0.00;(#,##0.00);-") ' "1,234.50" (positive) (-1234.5).ToString("#,##0.00;(#,##0.00);-") ' "(1,234.50)" (negative in parens) (0).ToString("#,##0.00;(#,##0.00);-") ' "-" (zero as dash) ' Scale / k / M shorthand (1500000).ToString("#,##0,K") ' "1,500K" (divide by 1,000) (1500000).ToString("0,,M") ' "2M" (divide by 1,000,000) ' Phone number formatting (custom string logic) Private Function FormatPhone(digits As String) As String Dim d = New String(digits.Where(Function(c) Char.IsDigit(c)).ToArray()) If d.Length = 10 Then Return $"({d.Substring(0,3)}) {d.Substring(3,3)}-{d.Substring(6)}" If d.Length = 11 Then Return $"+{d(0)} ({d.Substring(1,3)}) {d.Substring(4,3)}-{d.Substring(7)}" Return digits ' return as-is if unrecognised length End Function FormatPhone("0123456789") ' "(012) 345-6789" FormatPhone("60123456789") ' "+6 (012) 345-6789"
20.4 Date and Time Formatting
Date formatting follows the same three-method pattern. Standard specifiers are single letters; custom patterns use tokens like dd, MM, yyyy, HH, mm, ss. Note that month is M/MM (capital) while minute is m/mm (lowercase).
| Specifier | Name | Example output |
|---|---|---|
| d | Short date | 23/2/2026 |
| D | Long date | Monday, 23 February 2026 |
| t | Short time | 3:45 PM |
| T | Long time | 3:45:22 PM |
| f | Full (short time) | Monday, 23 February 2026 3:45 PM |
| F | Full (long time) | Monday, 23 February 2026 3:45:22 PM |
| g | General (short) | 23/2/2026 3:45 PM |
| G | General (long) | 23/2/2026 3:45:22 PM |
| M | Month day | 23 February |
| Y | Year month | February 2026 |
| s | Sortable (ISO 8601) | 2026-02-23T15:45:22 |
| u | Universal sortable | 2026-02-23 15:45:22Z |
| R | RFC 1123 | Mon, 23 Feb 2026 15:45:22 GMT |
Dim dt = New DateTime(2026, 2, 23, 15, 45, 22) ' 23 Feb 2026 15:45:22 ' Standard specifiers dt.ToString("d") ' "23/02/2026" short date dt.ToString("D") ' "Monday, 23 February 2026" long date dt.ToString("t") ' "3:45 PM" short time dt.ToString("T") ' "3:45:22 PM" long time dt.ToString("s") ' "2026-02-23T15:45:22" ISO 8601 (sortable) dt.ToString("g") ' "23/02/2026 3:45 PM" general short ' Custom patterns -- build exactly what you need dt.ToString("dd/MM/yyyy") ' "23/02/2026" dt.ToString("dd-MMM-yyyy") ' "23-Feb-2026" dt.ToString("dddd, d MMMM yyyy") ' "Monday, 23 February 2026" dt.ToString("HH:mm:ss") ' "15:45:22" (24-hour) dt.ToString("hh:mm tt") ' "03:45 PM" (12-hour) dt.ToString("yyyy-MM-dd HH:mm") ' "2026-02-23 15:45" (database-friendly) dt.ToString("d MMM yyyy 'at' h:mmtt") ' "23 Feb 2026 at 3:45PM" ' In interpolated strings Dim now = DateTime.Now lblTimestamp.Text = $"Saved at {now:HH:mm:ss} on {now:dd MMM yyyy}" lblLog.Text = $"[{now:yyyy-MM-dd HH:mm:ss.fff}] Application started" ' DateTime components -- use properties for individual parts lblYear.Text = now.Year.ToString() lblMonth.Text = now.ToString("MMMM") ' "February" lblDay.Text = now.ToString("dddd") ' "Monday" lblWeek.Text = now.DayOfYear.ToString() ' day number in year
Enter a date or use today. Choose a format specifier or type a custom pattern. See the VB code and output side by side, plus a comparison of every standard specifier.
20.5 String.Format — Alignment and Padding
String.Format supports an optional alignment component: {index,width:format}. A positive width right-aligns; a negative width left-aligns. This is essential for building aligned columns of text output.
' {index,alignment:format} ' Positive alignment = right-align; Negative = left-align ' Right-align in a 10-character field String.Format("{0,10}", "Name") ' " Name" (6 spaces then "Name") String.Format("{0,10:N2}", 1234.5) ' " 1,234.50" (right-aligned, 10 wide) ' Left-align String.Format("{0,-15}", "Name") ' "Name " (padded right) ' Building a formatted table Dim header = String.Format("{0,-20}{1,10}{2,10}{3,10}", "Item", "Qty", "Price", "Total") lstReport.Items.Add(header) lstReport.Items.Add(New String("-"c, 50)) Dim items() = {("Widget A", 5, 12.99), ("Gadget B", 2, 79.50), ("Donut C", 12, 2.50)} For Each (name, qty, price) In items Dim total = qty * price lstReport.Items.Add(String.Format("{0,-20}{1,10}{2,10:C2}{3,10:C2}", name, qty, price, total)) Next ' Equivalent with interpolated strings ($ supports alignment too) Dim name2 = "Widget A" : Dim qty2 = 5 : Dim price2 = 12.99 lstReport.Items.Add($"{name2,-20}{qty2,10}{price2,10:C2}{qty2*price2,10:C2}") ' PadLeft / PadRight on strings (simpler for basic padding) "Name".PadLeft(10) ' " Name" "Name".PadRight(10, "."c) ' "Name......" (42).ToString().PadLeft(5, "0"c) ' "00042"
Add items to a shopping cart. The receipt is formatted entirely using String.Format with alignment, :C2 currency, and :N0 quantity columns.
20.6 Interpolated Strings In Depth
' Basic: $ prefix, {expression:format,alignment} Dim name = "Alice" : Dim score = 92.5 $"Student: {name}, Score: {score:F1}" ' "Student: Alice, Score: 92.5" $"Score: {score,8:F2}" ' "Score: 92.50" (right-aligned, 8 wide) ' Expressions inside braces -- any valid VB expression Dim items = 5 : Dim unitPrice = 12.99 $"Total: {items * unitPrice:C2}" ' "Total: RM64.95" $"Tax (6%): {items * unitPrice * 0.06:C2}" ' "Tax (6%): RM3.90" ' Ternary (If) inside interpolation Dim balance = -250.0 $"Balance: {If(balance < 0, "(Overdrawn)", "")} {Math.Abs(balance):C2}" ' Calling methods inside braces $"Hello, {name.ToUpper()}!" ' "Hello, ALICE!" $"Today is {DateTime.Now:dddd, d MMMM yyyy}" ' "Today is Monday, 23 February 2026" $"Pi = {Math.PI:F6}" ' "Pi = 3.141593" ' Multi-line interpolated string (VB 2026 / C# 11 style) Dim email = $"Dear {name}, Thank you for your order of {items} item(s). Total charged: {items * unitPrice:C2} Order date: {DateTime.Now:dd MMM yyyy}" ' Escape braces with {{ and }} $"Format: {{0:C2}} produces {score:C2}" ' "Format: {0:C2} produces RM92.50" ' Verbatim + interpolated: $@ or @$ $@"C:\Users\{name}\Documents" ' "C:\Users\Alice\Documents" (no \\ needed)
20.7 Practical: Invoice Generator
' Invoice number: INV-2026-0042 Private Function FormatInvoiceNum(year As Integer, seq As Integer) As String Return $"INV-{year}-{seq:D4}" ' D4 zero-pads to 4 digits End Function FormatInvoiceNum(2026, 42) ' "INV-2026-0042" FormatInvoiceNum(2026, 1) ' "INV-2026-0001" ' Build complete invoice as a formatted string Private Function BuildInvoice(customer As String, subtotal As Decimal, sstRate As Double) As String Dim sst = Math.Round(subtotal * CDec(sstRate), 2) Dim total = subtotal + sst Dim now = DateTime.Now Return $"{'─',-44} INVOICE {FormatInvoiceNum(now.Year, 42),30} {'─',-44} Date : {now:dd MMM yyyy} Bill To: {customer} {'─',-44} Subtotal {subtotal,26:C2} SST {sstRate:P0,-5} {sst,26:C2} {'═',-44} TOTAL {total,26:C2} {'─',-44}" End Function
Experiment with custom numeric patterns. Type any pattern using 0, #, ,, ., %, and ; sections. See the result and the VB interpolated string call.
Build a formatted invoice using String.Format alignment, interpolated strings, C2/P0/D4 format specifiers, and custom date patterns. Every piece of formatting is shown in the trace.
20.8 GitHub Copilot — Formatting Patterns
' Generate a formatted sales summary report to a ListBox. Include headers with String.Format alignment, currency totals with C2, date with "dd MMM yyyy", and a percentage change column.'' Formatted sales report using String.Format alignment and number specifiers. Private Sub GenerateSalesReport() lstReport.Items.Clear() Dim header = String.Format("{0,-20}{1,12}{2,12}{3,10}", "Product", "Sales", "Target", "Change") lstReport.Items.Add(header) lstReport.Items.Add(New String("-"c, 55)) Dim rows = New List(Of (name As String, sales As Decimal, target As Decimal)) From { ("Widget A", 48200, 45000), ("Gadget B", 31500, 35000), ("Module C", 62000, 60000) } Dim grandTotal = 0D For Each row In rows Dim pct = CDbl(row.sales - row.target) / CDbl(row.target) Dim pctStr = $"{pct:+0.0%;-0.0%;0.0%}" lstReport.Items.Add(String.Format("{0,-20}{1,12:C0}{2,12:C0}{3,10}", row.name, row.sales, row.target, pctStr)) grandTotal += row.sales Next lstReport.Items.Add(New String("="c, 55)) lstReport.Items.Add(String.Format("{0,-20}{1,12:C0}", "TOTAL", grandTotal)) lblDate.Text = $"Report generated: {DateTime.Now:dd MMM yyyy HH:mm}" End Sub
' Write a log formatter Sub that writes timestamped entries to a ListBox. Format: [yyyy-MM-dd HH:mm:ss.fff] [LEVEL] Message. Levels: INFO, WARN, ERROR.'' Timestamped log formatter using interpolated string with date specifier. Enum LogLevel INFO WARN ERROR End Enum Private Sub Log(message As String, Optional level As LogLevel = LogLevel.INFO) Dim ts = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") Dim entry = $"[{ts}] [{level,-5}] {message}" lstLog.Items.Add(entry) lstLog.SelectedIndex = lstLog.Items.Count - 1 ' auto-scroll ' Colour-code errors in red If level = LogLevel.ERROR Then lstLog.Items(lstLog.Items.Count - 1) = $"!!! {entry}" End If End Sub ' Usage: Log("Application started") Log("Connection timeout, retrying", LogLevel.WARN) Log("Database error: timeout after 30s", LogLevel.ERROR)
Try these in the Copilot Chat panel while working with formatting:
- "Write a Function FormatFileSize(bytes As Long) As String that returns '1.23 MB', '456 KB' etc using String.Format with F2 and If..ElseIf thresholds"
- "Create a table formatter Sub that takes a two-dimensional String array and formats it with String.Format alignment so columns line up in a ListBox"
- "Build a Function FormatDuration(seconds As Integer) As String that returns '2h 15m 30s' or '45m 10s' or '30s' using interpolated strings"
- "Generate a data export Sub that formats a List(Of Customer) as CSV using $\"{c.Name},{c.Total:F2},{c.Date:yyyy-MM-dd}\""
Lesson Summary
- Three modern formatting approaches all use the same specifiers:
value.ToString("C2"),String.Format("{0:C2}", value), and$"{value:C2}". Interpolated strings ($"...") are preferred in VB 2026 for readability. - Standard number specifiers: C currency, F fixed, N number with separator, P percent (×100 first!), E scientific, G general (shortest), D integer zero-pad, X hex. The digit after the letter controls decimal places or significant figures.
- Custom numeric patterns use
0(force digit),#(optional digit),,(thousands separator),.(decimal),%(×100), and three;-separated sections for positive/negative/zero. - Date specifiers: d short, D long, t short time, T long time, s sortable ISO 8601. Custom patterns use
dd/MM/yyyy(day/month/year) andHH:mm:ss(24-hour). Capital M = month; lowercase m = minute. String.Format("{0,-20}{1,10:C2}", name, price)aligns columns: negative width = left-align, positive = right-align. Essential for building readable reports in ListBoxes.- Interpolated strings support full expressions
{items * price:C2}, method calls{name.ToUpper()}, ternary expressions{If(x < 0, "(neg)", "")}, and verbatim paths$@"C:\Users\{name}".
Exercises
Exercise 20.1 — Number Format Dashboard
- Build a form with a NumericUpDown for a value and radio buttons for format type
- Display the same value in all 9 standard formats simultaneously using a ListBox
- Add a TextBox for a custom pattern and show the result live on TextChanged
- Include a negative/zero toggle to demonstrate the 3-section
pos;neg;zeropattern - Copilot challenge: Ask Copilot to "add a culture selector (en-US, my-MY, de-DE) and reformat with the selected CultureInfo"
Exercise 20.2 — Date and Time Formatter
- Build a form with a DateTimePicker and a ListBox showing all 13 standard date specifiers
- Add a custom pattern TextBox — results update as you type
- Show a countdown: days/hours/minutes until a user-selected future date using TimeSpan formatting
- Display a table comparing the same date in 5 different format styles
- Copilot challenge: Ask Copilot to "format the date in 10 different world locales using CultureInfo.GetCultureInfo()"
Exercise 20.3 — Sales Report Generator
- Create a DataGridView with columns: Product, Units, Unit Price, Total, % of Grand Total
- Format Unit Price and Total with
C2, Units withN0, % withP1 - Add a summary row: Grand Total formatted with
C2and bold - Export to a ListBox as aligned text using
String.Formatwith column widths - Copilot challenge: Ask Copilot to "add a Print button that builds the report as a multiline string and sends it to a RichTextBox with monospace font"
Related Resources
← Lesson 19
Trigonometric Functions — Sin, Cos, Tan and more.
Lesson 21 →
CheckBox Control — multi-select options.
MS Docs — Numeric Formats
Complete reference for standard and custom numeric format specifiers.
MS Docs — Date Formats
Standard and custom date/time format specifier reference.
Featured Books
Visual Basic 2022 Made Easy
Formatting functions applied throughout real-world examples including invoice, receipt, and report builders.
View on Amazon →
VB Programming With Code Examples
48 programs demonstrating currency, date, and table formatting in complete applications.
View on Amazon →