StringToDate
Converts a date string to a date value. Runtime-proven on a live Marketing Cloud Engagement CloudPage — including the fact that it produced character-for-character identical output to DateParse for every input tried, while accepting no second argument at all.
Syntax
StringToDate(dateString) → date
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
dateString |
string | date | Yes | A date or timestamp string, or an existing date value |
Example
%%[
VAR @parsed
SET @parsed = StringToDate("2026-03-04T09:05:07")
]%%
%%=v(@parsed)=%%
Renders 3/4/2026 9:05:07 AM.
The value is a real date, so the point of parsing is usually to hand it straight to another date function:
%%[
VAR @raw, @due
SET @raw = "2026-03-04"
SET @due = FormatDate(DateAdd(StringToDate(@raw), 30, "D"), "yyyy-MM-dd")
]%%
<p>Payment due %%=v(@due)=%%</p>
If a UTC conversion might ever be needed, reach for DateParse instead — this name has no second argument to ask for one.
Return value
date — a real date value, not text. DatePart, FormatDate, DateAdd and DateDiff all accepted the result directly, and Length() over it returned 20.
There is no closed set of sentinel values to test for, and no failure value either. Every rejected input aborts the page with HTTP 422 rather than returning an error token, so a result that exists is always a real date.
Rendered on its own the value prints as a US short date followed by a 12-hour clock with an AM/PM suffix — 3/4/2026 12:00:00 AM for a date with no time part.
It behaves exactly like DateParse
Both functions were called on the same line of the same render, against the same fixed inputs. Every pair matched character for character.
| Call | StringToDate renders |
DateParse renders |
|---|---|---|
("2026-03-04") |
3/4/2026 12:00:00 AM |
3/4/2026 12:00:00 AM |
("2026-03-04 09:05:07") |
3/4/2026 9:05:07 AM |
3/4/2026 9:05:07 AM |
("2026-03-04T09:05:07") |
3/4/2026 9:05:07 AM |
3/4/2026 9:05:07 AM |
("2026-03-04T09:05:07+02:00") |
3/4/2026 1:05:07 AM |
3/4/2026 1:05:07 AM |
("2026-03-04T09:05:07Z") |
3/4/2026 3:05:07 AM |
3/4/2026 3:05:07 AM |
("3/4/2026 9:05 AM") |
3/4/2026 9:05:00 AM |
3/4/2026 9:05:00 AM |
("4 March 2026") |
3/4/2026 12:00:00 AM |
3/4/2026 12:00:00 AM |
("March 4, 2026") |
3/4/2026 12:00:00 AM |
3/4/2026 12:00:00 AM |
("Wed, 04 Mar 2026 09:05:07 GMT") |
3/4/2026 3:05:07 AM |
3/4/2026 3:05:07 AM |
Measured rather than eyeballed: a DateDiff in hours between the two results over the same input returned 0, and Length() over each returned 20.
The one real difference is arity. DateParse takes an optional second argument that returns the instant in UTC. StringToDate accepts exactly one argument — passing that same flag shape aborts the page, and so does the "UTF-8" encoding argument some community references still list for it. Neither is ignored; both are rejected. The relationship is written up in the differs-from-docs card.
Behaviour
The failure mode is shared too, and it is the harsh one. Free text, an empty string and a bare number such as 20260304 each abort the render with HTTP 422 and discard everything already written above them — under either name. There is no value to inspect afterwards, so validate the string before the call rather than checking the result.
A timezone offset in the input is honoured, not discarded. 2026-03-04T09:05:07+02:00 came back as 1:05:07 AM and a Z-suffixed Zulu timestamp as 3:05:07 AM, both correctly converted into the account zone. An RFC-style string ending in GMT converted the same way.
A time with no date borrows the day of the render. 1:41 PM parsed successfully and took today’s date, so it is the one accepted form whose result is not deterministic from the input alone.
An existing date value can be passed straight back in. StringToDate(Now()) returned the current instant unchanged, so the parameter accepts a date as well as a string.
A day-first date is misread, not refused
5/8/2026 meant as the 5th of August parsed cleanly and came back as 5/8/2026 12:00:00 AM — the 8th of May. Nothing aborts and nothing signals the problem, so a European-formatted feed produces plausible dates that are months wrong. Normalise to yyyy-MM-dd before parsing. The same input misreads identically under DateParse; full write-up in that function’s differs-from-docs card.
Show test script
%%[
VAR @b, @s, @iso, @isot
SET @b = RequestParameter("b")
SET @s = "2026-03-04 09:05:07"
SET @iso = "2026-03-04"
SET @isot = "2026-03-04T09:05:07"
/* the control - fetch this whenever a branch below renders nothing */
IF @b == "ctrl" THEN
OutputLine(Concat("--- ctrl start ---"))
OutputLine(Concat("CTRLSD=[", StringToDate(@iso), "]"))
OutputLine(Concat("CTRLDP=[", DateParse(@iso), "]"))
OutputLine(Concat("--- ctrl done ---"))
ENDIF
/* every accepted format, next to the DateParse result for the same input */
IF @b == "formats" THEN
OutputLine(Concat("--- formats start ---"))
OutputLine(Concat("ISO_S=[", StringToDate(@iso), "] ISO_D=[", DateParse(@iso), "]"))
OutputLine(Concat("DT_S=[", StringToDate(@s), "] DT_D=[", DateParse(@s), "]"))
OutputLine(Concat("ISOT_S=[", StringToDate(@isot), "] ISOT_D=[", DateParse(@isot), "]"))
OutputLine(Concat("US_S=[", StringToDate("3/4/2026 9:05 AM"), "] US_D=[", DateParse("3/4/2026 9:05 AM"), "]"))
OutputLine(Concat("WA_S=[", StringToDate("4 March 2026"), "] WA_D=[", DateParse("4 March 2026"), "]"))
OutputLine(Concat("WB_S=[", StringToDate("March 4, 2026"), "] WB_D=[", DateParse("March 4, 2026"), "]"))
OutputLine(Concat("TZ_S=[", StringToDate("2026-03-04T09:05:07+02:00"), "] TZ_D=[", DateParse("2026-03-04T09:05:07+02:00"), "]"))
OutputLine(Concat("Z_S=[", StringToDate("2026-03-04T09:05:07Z"), "] Z_D=[", DateParse("2026-03-04T09:05:07Z"), "]"))
OutputLine(Concat("RFC_S=[", StringToDate("Wed, 04 Mar 2026 09:05:07 GMT"), "] RFC_D=[", DateParse("Wed, 04 Mar 2026 09:05:07 GMT"), "]"))
OutputLine(Concat("LEN_S=[", Length(StringToDate(@iso)), "] LEN_D=[", Length(DateParse(@iso)), "]"))
OutputLine(Concat("--- formats done ---"))
ENDIF
/* the result is a real date value the other date functions consume */
IF @b == "chain" THEN
OutputLine(Concat("--- chain start ---"))
OutputLine(Concat("PY=[", DatePart(StringToDate(@isot), "Y"), "]"))
OutputLine(Concat("PMI=[", DatePart(StringToDate(@isot), "MI"), "]"))
OutputLine(Concat("FD=[", FormatDate(StringToDate(@isot), "yyyy-MM-dd"), "]"))
OutputLine(Concat("DA=[", DateAdd(StringToDate(@iso), 1, "D"), "]"))
OutputLine(Concat("DD=[", DateDiff(StringToDate(@iso), StringToDate("2026-03-06"), "D"), "]"))
OutputLine(Concat("XDIFF=[", DateDiff(StringToDate(@s), DateParse(@s), "H"), "]"))
OutputLine(Concat("--- chain done ---"))
ENDIF
/* a day-first date is misread rather than refused, under both names */
IF @b == "little" THEN
OutputLine(Concat("--- little start ---"))
OutputLine(Concat("MEANT_5_AUGUST_S=[", StringToDate("5/8/2026"), "]"))
OutputLine(Concat("MEANT_5_AUGUST_D=[", DateParse("5/8/2026"), "]"))
OutputLine(Concat("ISO_CONTROL=[", StringToDate("2026-08-05"), "]"))
OutputLine(Concat("--- little done ---"))
ENDIF
/* a time with no date borrows the day of the render */
IF @b == "timeonly" THEN
OutputLine(Concat("--- timeonly start ---"))
OutputLine(Concat("TO_S=[", StringToDate("1:41 PM"), "] TO_D=[", DateParse("1:41 PM"), "]"))
OutputLine(Concat("--- timeonly done ---"))
ENDIF
/* an existing date value is accepted, not just a string */
IF @b == "dateval" THEN
OutputLine(Concat("--- dateval start ---"))
OutputLine(Concat("DV=[", StringToDate(Now()), "]"))
OutputLine(Concat("--- dateval done ---"))
ENDIF
/* every branch below aborts the page - fetch them ONE at a time */
IF @b == "a0" THEN
OutputLine(Concat("--- a0 start ---"))
OutputLine(Concat("A0=[", StringToDate(), "]"))
ENDIF
/* the encoding argument some references list is rejected, not ignored */
IF @b == "a2enc" THEN
OutputLine(Concat("--- a2enc start ---"))
OutputLine(Concat("A2ENC=[", StringToDate(@s, "UTF-8"), "]"))
ENDIF
/* the DateParse UTC flag has no counterpart here */
IF @b == "a2flag" THEN
OutputLine(Concat("--- a2flag start ---"))
OutputLine(Concat("A2FLAG=[", StringToDate(@s, 1), "]"))
ENDIF
IF @b == "a3" THEN
OutputLine(Concat("--- a3 start ---"))
OutputLine(Concat("A3=[", StringToDate(@s, 1, "extra"), "]"))
ENDIF
IF @b == "bad" THEN
OutputLine(Concat("--- bad start ---"))
OutputLine(Concat("BAD=[", StringToDate("not a date at all"), "]"))
ENDIF
IF @b == "empty" THEN
OutputLine(Concat("--- empty start ---"))
OutputLine(Concat("EMPTY=[", StringToDate(""), "]"))
ENDIF
IF @b == "num" THEN
OutputLine(Concat("--- num start ---"))
OutputLine(Concat("NUM=[", StringToDate(20260304), "]"))
ENDIF
]%%
A bare string literal passed to OutputLine renders an empty line while the page still returns HTTP 200, so the marker silently vanishes and the block looks like a function that produced no output. Always wrap it — OutputLine(Concat("--- formats start ---")) — even for a single argument.
AMPscript has no try/catch, so an unreadable date string aborts the render and throws away everything already written above it. When testing, put each risky call behind its own RequestParameter branch and fetch them one at a time — otherwise a single failure hides every result on the page.
Availability
| Platform | Available |
|---|---|
| Marketing Cloud Engagement | Yes |
| Marketing Cloud Next | Yes, from API 67.0 |
Everything on this page was proven on an Engagement CloudPage. The official reference states that on Marketing Cloud Next the function returns a locale-formatted string rather than a date value, which would break the chaining shown above; that claim was not tested here.
See also
- DateParse — same behaviour on one argument, plus an optional UTC flag this function does not have
- FormatDate — the usual next call, and the recommended alternative on Marketing Cloud Next
- DateAdd · DateDiff · DatePart — the functions that consume the parsed value
- The differs-from-docs card — the duplication and the arity gap
- Official reference · ampscript.guide