larksuite/cli · error
datetime %q must be ISO: %w
Error message
datetime %q must be ISO: %w
What it means
When the value contains a 'T', isoDateToSerial parses the full datetime with RFC3339Nano (if a timezone marker Z/z/+/- is present) or the local-style layout 2006-01-02T15:04:05.999999999. If that full parse fails, this error wraps the cause; the base date already parsed OK, so the clock portion is malformed. Callers add row/column context.
Source
Thrown at shortcuts/sheets/lark_sheet_table_io.go:791
// clash with the column-wide dtype declaration; name the three ways
// out so the caller does not have to guess what "bad format" means.
return 0, fmt.Errorf("date column has an empty cell — drop the empty rows, fill real yyyy-mm-dd dates, or declare the column dtype as object (text)") //nolint:forbidigo // intermediate error; callers wrap it into a typed --sheets/--values validation error with row/column context
}
if i := strings.Index(s, "T"); i > 0 {
base := s[:i]
date, err := time.Parse("2006-01-02", base)
if err != nil {
return 0, fmt.Errorf("date %q must be ISO yyyy-mm-dd: %w", base, err) //nolint:forbidigo // intermediate parse error; caller wraps it with typed validation context
}
var parsed time.Time
clock := s[i:]
if strings.ContainsAny(clock, "Zz+-") {
parsed, err = time.Parse(time.RFC3339Nano, s)
} else {
parsed, err = time.Parse("2006-01-02T15:04:05.999999999", s)
}
if err != nil {
return 0, fmt.Errorf("datetime %q must be ISO: %w", s, err) //nolint:forbidigo // intermediate parse error; caller wraps it with typed validation context
}
if parsed.Location() != time.UTC {
// Keep the wall-clock time supplied by the caller; Excel serials do
// not carry a timezone and table-put historically treated the ISO
// date/time as the sheet-local value.
return date.Sub(excelEpoch).Hours()/24 + float64(parsed.Hour()*3600+parsed.Minute()*60+parsed.Second())/86400 + float64(parsed.Nanosecond())/(86400*1e9), nil
}
return date.Sub(excelEpoch).Hours()/24 + float64(parsed.Hour()*3600+parsed.Minute()*60+parsed.Second())/86400 + float64(parsed.Nanosecond())/(86400*1e9), nil
}
t, err := time.Parse("2006-01-02", s)
if err != nil {
return 0, fmt.Errorf("date %q must be ISO yyyy-mm-dd: %w", s, err) //nolint:forbidigo // intermediate error; callers wrap it into a typed --sheets/--values validation error with row/column context
}
return float64(int(math.Round(t.Sub(excelEpoch).Hours() / 24))), nil
}
// ─── range helpers ────────────────────────────────────────────────────
View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Use a valid RFC3339 timestamp with colon in the offset, e.g. "2026-01-31T10:00:00+08:00" or "2026-01-31T10:00:00Z"
- Drop the timezone entirely and use "2026-01-31T10:00:00" for sheet-local wall-clock time
- Fix the clock fields (hour ≤ 23, minute/second ≤ 59) and remove stray spaces
Example fix
// before
{"name":"Due","type":"date","data":["2026-01-31T10:00+0800"]}
// after
{"name":"Due","type":"date","data":["2026-01-31T10:00:00+08:00"]} Defensive patterns
Strategy: validation
Validate before calling
function assertRFC3339Datetime(v) {
if (v.includes('T') && !isNaN(Date.parse(v)) === false)
throw new Error(`'${v}' is not a valid ISO datetime; use e.g. 2026-01-31T10:00:00+08:00`);
if (/[+-]\d{4}$/.test(v)) throw new Error(`offset '${v.slice(-5)}' must include a colon (+08:00)`);
}
Type guard
function isValidISODatetime(v) { return /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(:\d{2}(\.\d+)?)?(Z|[+-]\d{2}:\d{2})?$/.test(v) && !isNaN(Date.parse(v)); } Try / catch
try {
await run(['lark','sheet','table-put','--sheets',payload]);
} catch (e) {
if (/datetime .* must be ISO/.test(e.message)) {
// normalize the timestamp to RFC3339 (colon in offset, no stray spaces) and retry
}
throw e;
} Prevention
- Use RFC3339 formatting from your language's standard library (e.g. new Date().toISOString()) instead of hand-formatting
- Never hand-write timezone offsets; emit Z or ±hh:mm with a colon
- Validate timestamps with Date.parse / strict regex before payload build
When it happens
Trigger: Values like "2026-01-31T25:00:00" (invalid hour), "2026-01-31T10:00 Z" (space before offset), "2026-01-31T10:00+0800" (offset without colon, not RFC3339).
Common situations: Offsets written as +0800 instead of +08:00; timezone name abbreviations (CET) instead of Z or ±hh:mm; stray spaces inside the timestamp.
Related errors
- date %q must be ISO yyyy-mm-dd: %w
- date expects an ISO yyyy-mm-dd string, got %s
- date column has an empty cell — drop the empty rows, fill re
- please select at least one domain
- %s must contain at most %d characters
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/72e66c3dcd96280d.
Report an issue: GitHub.