]> git.maquefel.me Git - brevno-suite/hugo/commitdiff
resources/page: Allow full datetime prefix in filenames
authorJoe Mooring <joe.mooring@veriphor.com>
Fri, 4 Jul 2025 18:29:35 +0000 (11:29 -0700)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Sat, 5 Jul 2025 09:26:35 +0000 (11:26 +0200)
Allow YYYY-MM-DD-HH-MM-SS prefix when extracting date from file names.
This is in addition to the YYYY-MM-DD prefix that is already supported.

Closes #13830

resources/page/pagemeta/page_frontmatter.go
resources/page/pagemeta/pagemeta_test.go

index fd4f7759b86eef15d7f6d1141b189598e6dbc150..9018acb713cb91a35ef91b448133f9b105b9efdf 100644 (file)
@@ -457,26 +457,43 @@ func (f FrontMatterHandler) IsDateKey(key string) bool {
        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)
index f205c74f806dfcec9dec784c88058669e7fa36bd..80c19d07f8312503d8ff6dfd7362349693b1a2b8 100644 (file)
@@ -102,27 +102,46 @@ func TestDateAndSlugFromBaseFilename(t *testing.T) {
                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)
 
        }