{"record":{"id":"f8d5963d41e4a4cb","repo":"n8n-io/n8n","slug":"unsupported-format-string-valueformat-todat","errorCode":null,"errorMessage":"Unsupported format '${String(valueFormat)}'. toDateTime() supports 'ms', 's', 'us' and 'excel'.","messagePattern":"Unsupported format '(.+?)'\\. toDateTime\\(\\) supports 'ms', 's', 'us' and 'excel'\\.","errorType":"exception","errorClass":"ExpressionExtensionError","httpStatus":null,"severity":"error","filePath":"packages/@n8n/expression-runtime/src/extensions/number-extensions.ts","lineNumber":75,"sourceCode":"\nfunction toBoolean(value: number) {\n\treturn value !== 0;\n}\n\nfunction toInt(value: number) {\n\treturn round(value, []);\n}\n\nfunction toFloat(value: number) {\n\treturn value;\n}\n\ntype DateTimeFormat = 'ms' | 's' | 'us' | 'excel';\nexport function toDateTime(value: number, extraArgs: [DateTimeFormat]) {\n\tconst [valueFormat = 'ms'] = extraArgs;\n\n\tif (!['ms', 's', 'us', 'excel'].includes(valueFormat)) {\n\t\tthrow new ExpressionExtensionError(\n\t\t\t`Unsupported format '${String(valueFormat)}'. toDateTime() supports 'ms', 's', 'us' and 'excel'.`,\n\t\t);\n\t}\n\n\tswitch (valueFormat) {\n\t\t// Excel format is days since 1900\n\t\t// There is a bug where 1900 is incorrectly treated as a leap year\n\t\tcase 'excel': {\n\t\t\tconst DAYS_BETWEEN_1900_1970 = 25567;\n\t\t\tconst DAYS_LEAP_YEAR_BUG_ADJUST = 2;\n\t\t\tconst SECONDS_IN_DAY = 86_400;\n\t\t\treturn DateTime.fromSeconds(\n\t\t\t\t(value - (DAYS_BETWEEN_1900_1970 + DAYS_LEAP_YEAR_BUG_ADJUST)) * SECONDS_IN_DAY,\n\t\t\t);\n\t\t}\n\t\tcase 's':\n\t\t\treturn DateTime.fromSeconds(value);\n\t\tcase 'us':","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/expression-runtime/src/extensions/number-extensions.ts#L57-L93","documentation":"The NUMBER variant of `.toDateTime(format)` accepts only `'ms'`, `'s'`, `'us'`, and `'excel'` (milliseconds, seconds, microseconds, and days-since-1900 respectively). Any other format string throws; the four valid tokens are listed in the message. (The STRING variant of `.toDateTime()` is a different function and accepts Luxon format tokens.)","triggerScenarios":"Calling `.toDateTime('nanos')`, `.toDateTime('iso')`, or passing a Luxon token like `'yyyy'` on a numeric value.","commonSituations":"Copy-pasting a format token from the string variant; assuming arbitrary units are supported; passing a unit the source system uses but n8n does not.","solutions":["Use one of `ms`, `s`, `us`, `excel` for numeric inputs.","If the source is an ISO/date string, use the string `.toDateTime()` variant (or `.toDate()`) instead.","Convert exotic epochs in a Code node (e.g. nanoseconds → milliseconds) before calling `.toDateTime('ms')`."],"exampleFix":"// before\n{{ $json.epochMicros.toDateTime('micros') }}\n// after\n{{ $json.epochMicros.toDateTime('us') }}","handlingStrategy":"validation","validationCode":"const FORMATS = new Set(['ms','s','us','excel']);\nconst fmt = $json.fmt;\nif (typeof $json.value === 'number' && !FORMATS.has(fmt)) {\n  throw new Error(`toDateTime(): unsupported numeric format '${fmt}'`);\n}\nreturn $json;","typeGuard":"const isNumericDateTimeFormat = (f: string): f is 'ms'|'s'|'us'|'excel' =>\n  ['ms','s','us','excel'].includes(f);","tryCatchPattern":null,"preventionTips":["For numeric epochs use only ms/s/us/excel.","For ISO/date strings use the string `.toDateTime()` variant instead.","Convert exotic epochs (e.g. nanos) to milliseconds in a Code node first."],"tags":["expression","number","date","format","validation"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}