return f.allDateKeys[key]
}
-// A Zero date is a signal that the name can not be parsed.
-// This follows the format as outlined in Jekyll, https://jekyllrb.com/docs/posts/:
-// "Where YEAR is a four-digit number, MONTH and DAY are both two-digit numbers"
-func dateAndSlugFromBaseFilename(location *time.Location, name string) (time.Time, string) {
- withoutExt, _ := paths.FileAndExt(name)
-
- if len(withoutExt) < 10 {
- // This can not be a date.
+// dateAndSlugFromBaseFilename returns a time.Time value (resolved to the
+// default system location) and a slug, extracted by parsing the provided path.
+// Parsing supports YYYY-MM-DD-HH-MM-SS and YYYY-MM-DD date/time formats.
+// Within the YYYY-MM-DD-HH-MM-SS format, the date and time values may be
+// separated by any character including a space (e.g., YYYY-MM-DD HH-MM-SS).
+func dateAndSlugFromBaseFilename(location *time.Location, path string) (time.Time, string) {
+ base, _ := paths.FileAndExt(path)
+
+ if len(base) < 10 {
+ // Not long enough to start with a YYYY-MM-DD date.
return time.Time{}, ""
}
- d, err := htime.ToTimeInDefaultLocationE(withoutExt[:10], location)
- if err != nil {
- return time.Time{}, ""
+ // Delimiters allowed between the date and the slug.
+ delimiters := " -_"
+
+ if len(base) >= 19 {
+ // Attempt to parse a YYYY-MM-DD-HH-MM-SS date-time prefix.
+ ds := base[:10]
+ ts := strings.ReplaceAll(base[11:19], "-", ":")
+
+ d, err := htime.ToTimeInDefaultLocationE(ds+"T"+ts, location)
+ if err == nil {
+ return d, strings.Trim(base[19:], delimiters)
+ }
}
- // Be a little lenient with the format here.
- slug := strings.Trim(withoutExt[10:], " -_")
+ // Attempt to parse a YYYY-MM-DD date prefix.
+ ds := base[:10]
+
+ d, err := htime.ToTimeInDefaultLocationE(ds, location)
+ if err == nil {
+ return d, strings.Trim(base[10:], delimiters)
+ }
- return d, slug
+ // If no date is defined, return the zero time instant.
+ return time.Time{}, ""
}
type frontMatterFieldHandler func(d *FrontMatterDescriptor) (bool, error)
date string
slug string
}{
- {"page.md", "0001-01-01", ""},
- {"2012-09-12-page.md", "2012-09-12", "page"},
- {"2018-02-28-page.md", "2018-02-28", "page"},
- {"2018-02-28_page.md", "2018-02-28", "page"},
- {"2018-02-28 page.md", "2018-02-28", "page"},
- {"2018-02-28page.md", "2018-02-28", "page"},
- {"2018-02-28-.md", "2018-02-28", ""},
- {"2018-02-28-.md", "2018-02-28", ""},
- {"2018-02-28.md", "2018-02-28", ""},
- {"2018-02-28-page", "2018-02-28", "page"},
- {"2012-9-12-page.md", "0001-01-01", ""},
- {"asdfasdf.md", "0001-01-01", ""},
+ // date
+ {"2025-07-04 page.md", "2025-07-04T00:00:00+02:00", "page"},
+ {"2025-07-04-page.md", "2025-07-04T00:00:00+02:00", "page"},
+ {"2025-07-04_page.md", "2025-07-04T00:00:00+02:00", "page"},
+ {"2025-07-04page.md", "2025-07-04T00:00:00+02:00", "page"},
+ {"2025-07-04", "2025-07-04T00:00:00+02:00", ""},
+ {"2025-07-04-.md", "2025-07-04T00:00:00+02:00", ""},
+ {"2025-07-04.md", "2025-07-04T00:00:00+02:00", ""},
+ // date and time
+ {"2025-07-04-22-17-13 page.md", "2025-07-04T22:17:13+02:00", "page"},
+ {"2025-07-04-22-17-13-page.md", "2025-07-04T22:17:13+02:00", "page"},
+ {"2025-07-04-22-17-13_page.md", "2025-07-04T22:17:13+02:00", "page"},
+ {"2025-07-04-22-17-13page.md", "2025-07-04T22:17:13+02:00", "page"},
+ {"2025-07-04-22-17-13", "2025-07-04T22:17:13+02:00", ""},
+ {"2025-07-04-22-17-13-.md", "2025-07-04T22:17:13+02:00", ""},
+ {"2025-07-04-22-17-13.md", "2025-07-04T22:17:13+02:00", ""},
+ // date and time with other separators between the two
+ {"2025-07-04T22-17-13.md", "2025-07-04T22:17:13+02:00", ""},
+ {"2025-07-04 22-17-13.md", "2025-07-04T22:17:13+02:00", ""},
+ // no date or time
+ {"something.md", "0001-01-01T00:00:00+00:00", ""}, // 9 chars
+ {"some-thing-.md", "0001-01-01T00:00:00+00:00", ""}, // 10 chars
+ {"somethingsomething.md", "0001-01-01T00:00:00+00:00", ""}, // 18 chars
+ {"something-something.md", "0001-01-01T00:00:00+00:00", ""}, // 19 chars
+ {"something-something-else.md", "0001-01-01T00:00:00+00:00", ""}, // 27 chars
+ // invalid
+ {"2025-07-4-page.md", "0001-01-01T00:00:00+00:00", ""},
+ {"2025-07-4-22-17-13-page.md", "0001-01-01T00:00:00+00:00", ""},
+ {"asdfasdf.md", "0001-01-01T00:00:00+00:00", ""},
}
+ location, err := time.LoadLocation("Europe/Oslo")
+ if err != nil {
+ t.Error("Unable to determine location from given time zone")
+ }
for _, test := range tests {
- expecteFDate, err := time.Parse("2006-01-02", test.date)
- c.Assert(err, qt.IsNil)
- gotDate, gotSlug := dateAndSlugFromBaseFilename(time.UTC, test.name)
+ gotDate, gotSlug := dateAndSlugFromBaseFilename(location, test.name)
- c.Assert(gotDate, qt.Equals, expecteFDate)
+ c.Assert(gotDate.Format("2006-01-02T15:04:05-07:00"), qt.Equals, test.date)
c.Assert(gotSlug, qt.Equals, test.slug)
}