Runtime verified Differs from official docs Test scripts included

Syntax

Format(value, formatString[, dataFormat, cultureCode])  →  string
2–4 arguments

Parameters

Name Type Required Description
value string | number | date Yes Number, numeric string, date value or parseable date string
formatString string Yes Standard or custom .NET pattern
dataFormat string No Only Date, in any capitalisation, or the empty string
cultureCode string No Locale for separators, symbols and month and day names

Example

For a number, leave the third parameter out entirely:

%%=Format(1234.555, "C2")=%%

That renders $1,234.56. To localise a number, pass the empty string in the third slot so the fourth remains reachable:

%%=Format(1234.555, "C2", "", "de-DE")=%%

That renders 1.234,56 €.

For a date, Date in the third slot unlocks the date patterns:

%%[
  VAR @orderDate
  SET @orderDate = AttributeValue("OrderDate")
]%%
Ordered on %%=Format(@orderDate, "D", "Date", "fr-FR")=%%

Do not write "Number" in the third slot — see the warning below.

Return value

string — the formatted value.

The domain is open, so there is no set of literals to test for. When the pattern does not suit the input, the input or the pattern comes back unformatted rather than raising anything.

Behaviour

The documented value `Number` takes the page down

The official reference names Date and Number as the two values of the third parameter. Passing the literal Number aborts the page with HTTP 422 and discards every byte of output, with or without a locale after it — an invented value produced exactly the same abort. Use the empty string, or omit the parameter.

For numbers, this behaves as FormatNumber does. Same patterns, same half-up rounding, same bracketed negative under a currency pattern: -1234.555 under C2 gave ($1,234.56).

A numeric string is accepted and formats identically to the number.

The third parameter is optional for dates too. A date-shaped string with a custom date pattern rendered correctly with the parameter omitted.

An unusable pattern is echoed rather than rejected. A digit-group pattern applied to a plain digit string rendered without any separators being inserted, at HTTP 200.

The same pattern means different things

The pattern is read against the input, not on its own:

Pattern Input Result
E 1234.555 1.234555E+003
d 2026-03-04 13:52:07 3/4/2026
D 2026-03-04 13:52:07 Wednesday, March 4, 2026
dddd 2026-03-04 13:52:07 Wednesday

A single letter is a numeric pattern for a number and a date pattern for a date, so moving a pattern string between call sites can silently change what it means.

Format and FormatDate disagree

Both calls below were made in one render, on the identical input 2026-03-04 13:52:07 and the identical pattern yyyy-MM-dd HH:mm:ss:

Function Result
Format 2026-03-04 13:52:07
FormatDate 2026-03-04 13:03:07

FormatDate rendered the minutes wrong. For a minute-precise pattern this function is the safer of the two.

Localised dates

The fourth parameter changes month and day names, not just the separators: D with fr-FR gave mercredi 4 mars 2026, and dddd with de-DE gave Mittwoch. Date may be written in any capitalisation.

Show test script
%%[
  VAR @b, @n, @ns, @neg, @d
  SET @b = RequestParameter("b")
  SET @n = 1234.555
  SET @ns = "1234.555"
  SET @neg = -1234.555
  SET @d = "2026-03-04 13:52:07"

  /* known-good control: renders on every request, so a run of HTTP 422s
     can be told apart from a broken deploy */
  OutputLine(Concat("CTRL=[", Uppercase("ok"), "]"))

  /* numbers, with no third argument, plus the empty-string route to a
     localised number */
  IF @b == "s6" THEN
    OutputLine("--- s6 start ---")
    OutputLine(Concat("C2=[", Format(@n, "C2"), "]"))
    OutputLine(Concat("N2=[", Format(@n, "N2"), "]"))
    OutputLine(Concat("P=[", Format(@n, "P"), "]"))
    OutputLine(Concat("E=[", Format(@n, "E"), "]"))
    OutputLine(Concat("cust=[", Format(@n, "#,##0.00"), "]"))
    OutputLine(Concat("neg=[", Format(@neg, "C2"), "]"))
    OutputLine(Concat("numstr=[", Format(@ns, "C2"), "]"))
    OutputLine(Concat("a4empt=[", Format(@n, "C2", "", "de-DE"), "]"))
    OutputLine("--- s6 done ---")
  ENDIF

  /* dates - and the comparison that matters, both calls on the identical
     input and pattern so the difference cannot be blamed on anything else */
  IF @b == "s7" THEN
    OutputLine("--- s7 start ---")
    OutputLine(Concat("dD=[", Format(@d, "D", "Date"), "]"))
    OutputLine(Concat("dd=[", Format(@d, "d", "Date"), "]"))
    OutputLine(Concat("dpat=[", Format(@d, "yyyy-MM-dd HH:mm:ss", "Date"), "]"))
    OutputLine(Concat("dnoflag=[", Format(@d, "yyyy-MM-dd HH:mm:ss"), "]"))
    OutputLine(Concat("fdcmp=[", FormatDate(@d, "yyyy-MM-dd HH:mm:ss"), "]"))
    OutputLine(Concat("dddd=[", Format(@d, "dddd", "Date"), "]"))
    OutputLine(Concat("dlow=[", Format(@d, "D", "date"), "]"))
    OutputLine(Concat("dfr=[", Format(@d, "D", "Date", "fr-FR"), "]"))
    OutputLine(Concat("dde=[", Format(@d, "dddd", "Date", "de-DE"), "]"))
    OutputLine("--- s7 done ---")
  ENDIF

  /* the documented value that does not work. Fetch this branch LAST and
     expect HTTP 422 with no markers at all */
  IF @b == "s8" THEN
    OutputLine("--- s8 start ---")
    OutputLine(Concat("numflag=[", Format(@n, "C2", "Number"), "]"))
    OutputLine("--- s8 done ---")
  ENDIF
]%%

Availability

Platform Available
Marketing Cloud Engagement Yes
Marketing Cloud Next Yes (since 67)

See also