years := [...]string{"2006", "06"} // year = 4*DIGIT / 2*DIGIT
seconds := [...]string{":05", ""} // second
// "-0700 (MST)" is not in RFC 5322, but is common.
- zones := [...]string{"-0700", "MST", "-0700 (MST)"} // zone = (("+" / "-") 4DIGIT) / "GMT" / ...
+ zones := [...]string{"-0700", "MST"} // zone = (("+" / "-") 4DIGIT) / "GMT" / ...
for _, dow := range dows {
for _, day := range days {
// ParseDate parses an RFC 5322 date string.
func ParseDate(date string) (time.Time, error) {
dateLayoutsBuildOnce.Do(buildDateLayouts)
+ // CR and LF must match and are tolerated anywhere in the date field.
+ date = strings.ReplaceAll(date, "\r\n", "")
+ if strings.Index(date, "\r") != -1 {
+ return time.Time{}, errors.New("mail: header has a CR without LF")
+ }
+ // Re-using some addrParser methods which support obsolete text, i.e. non-printable ASCII
+ p := addrParser{date, nil}
+ p.skipSpace()
+
+ // RFC 5322: zone = (FWS ( "+" / "-" ) 4DIGIT) / obs-zone
+ // zone length is always 5 chars unless obsolete (obs-zone)
+ if ind := strings.IndexAny(p.s, "+-"); ind != -1 && len(p.s) >= ind+5 {
+ date = p.s[:ind+5]
+ p.s = p.s[ind+5:]
+ } else if ind := strings.Index(p.s, "T"); ind != -1 && len(p.s) >= ind+1 {
+ // The last letter T of the obsolete time zone is checked when no standard time zone is found.
+ // If T is misplaced, the date to parse is garbage.
+ date = p.s[:ind+1]
+ p.s = p.s[ind+1:]
+ }
+ if !p.skipCFWS() {
+ return time.Time{}, errors.New("mail: misformatted parenthetical comment")
+ }
for _, layout := range dateLayouts {
t, err := time.Parse(layout, date)
if err == nil {