It turns out there’s nothing wrong with Hugo’s time.Format, just that I forgot to guard against attempting to read json files which don’t have the “startDate” key.
Adding this guard fixed it:
{{ if isset $json_map "startDate" }}
{{ time.Format "Monday, Jan 2, 2006" (substr $json_map.startDate 0 10) }}
{{ end }}