Repository: gohugoio/hugo (language: go)

Issue:
Date comparison fails with unqualified date values
This worked as expected in v0.122.0, fails in v0.123.x.

site config

```text
timeZone = "Europe/London"
```

content/p1.md

```text
---
title: p1
date: 2024-03-13T06:00:00
---
````

layouts/_default/single.html

```text
{{ .Date | warnf "date = %#v" }}
{{ .Lastmod | warnf "lastmod = %#v" }}
{{ eq .Date .Lastmod | warnf "%#v" }}
```

expected (v0.122.0)

```text
WARN  date = time.Date(2024, time.March, 13, 6, 0, 0, 0, time.Location("Europe/London"))
WARN  lastmod = time.Date(2024, time.March, 13, 6, 0, 0, 0, time.Location("Europe/London"))
WARN  true
```

actual (v0.123.x)

```text
WARN  date = time.Date(2024, time.March, 13, 6, 0, 0, 0, time.Location("Europe/London"))
WARN  lastmod = time.Date(2024, time.March, 13, 6, 0, 0, 0, time.UTC)
WARN  false
```

Both are correct (they point to the same moment in time), but the two values are not equal.

Reference: <https://discourse.gohugo.io/t/if-eq-date-lastmod-0-123-8/48798>








Discussion / hints:
Your Hugo versions, are they built with the same Go version?

```text
hugo v0.123.8-5fed9c591b694f314e5939548e11cc3dcb79a79c+extended linux/amd64 BuildDate=2024-03-07T13:14:42Z VendorInfo=gohugoio
GOOS="linux"
GOARCH="amd64"
GOVERSION="go1.22.0"
github.com/sass/libsass="3.6.5"
github.com/webmproject/libwebp="v1.3.2"
github.com/sass/dart-sass/protocol="2.5.0"
github.com/sass/dart-sass/compiler="1.71.0"
github.com/sass/dart-sass/implementation="1.71.0"

hugo v0.122.0-b9a03bd59d5f71a529acb3e33f995e0ef332b3aa+extended linux/amd64 BuildDate=2024-01-26T15:54:24Z VendorInfo=gohugoio
GOOS="linux"
GOARCH="amd64"
GOVERSION="go1.21.6"
github.com/sass/libsass="3.6.5"
github.com/webmproject/libwebp="v1.3.2"
github.com/sass/dart-sass/protocol="2.5.0"
github.com/sass/dart-sass/compiler="1.71.0"
github.com/sass/dart-sass/implementation="1.71.0"
```
OK, I think I remember seeing something about time equality in go1.22.0 release notes, but it wasn't a "red flag" for me, but I may have been mistaken.
I know I've used this in templates: https://pkg.go.dev/time#Time.Equal 

> Equal reports whether t and u represent the same time instant. Two times can be equal even if they are in different locations. For example, 6:00 +0200 and 4:00 UTC are Equal. See the documentation on the Time type for the pitfalls of using == with Time values; most code should use Equal instead.

Not sure what we're using internally.
The template workaround is to do this:

```
{{ if .Date.Equal .Lastmod  }}
```

instead of this:

```text
{{ if eq .Date .Lastmod  }}
```
>Not sure what we're using internally.

We use `reflect.DeepEqual`; I have checked now, and that func falls back to `==` for dates.

This means that we can easily fix the above failing case, but it would still fail on:

```
{{ $d1 := dict "date" .Lastmod }}
{{ $d2 := dict "date" .Date }}
{{ eq $d1 $d2 | warnf "%#v" }}
```

I suggest that we:

1. Fix the common case by checking if both sides are `time.Time` and use `Equal`.
2. Dig up the Go 1.22 issue that made this fail and make an argument for updating `reflect.DeepEqual` in Go's repo.
But they're not equal...

It seems to me that the comparison provided the expected result (from a user's standpoint) because of how we set the fallback values in v0.122.0. It seems like  _that_ is what changed.


Yea, right ... OK, now I see it.

Fix patch:
diff --git a/resources/page/pagemeta/page_frontmatter.go b/resources/page/pagemeta/page_frontmatter.go
index 8abd3807fe4..4e412c666d4 100644
--- a/resources/page/pagemeta/page_frontmatter.go
+++ b/resources/page/pagemeta/page_frontmatter.go
@@ -421,18 +421,22 @@ func (f *frontmatterFieldHandlers) newDateFieldHandler(key string, setter func(d
 			return false, nil
 		}
 
-		date, err := htime.ToTimeInDefaultLocationE(v, d.Location)
-		if err != nil {
-			return false, nil
+		var date time.Time
+		if vt, ok := v.(time.Time); ok && vt.Location() == d.Location {
+			date = vt
+		} else {
+			var err error
+			date, err = htime.ToTimeInDefaultLocationE(v, d.Location)
+			if err != nil {
+				return false, nil
+			}
+			d.PageConfig.Params[key] = date
 		}
 
 		// We map several date keys to one, so, for example,
 		// "expirydate", "unpublishdate" will all set .ExpiryDate (first found).
 		setter(d, date)
 
-		// This is the params key as set in front matter.
-		d.PageConfig.Params[key] = date
-
 		return true, nil
 	}
 }


Test patch:
diff --git a/resources/page/pagemeta/pagemeta_integration_test.go b/resources/page/pagemeta/pagemeta_integration_test.go
new file mode 100644
index 00000000000..4d195b7f06b
--- /dev/null
+++ b/resources/page/pagemeta/pagemeta_integration_test.go
@@ -0,0 +1,45 @@
+// Copyright 2024 The Hugo Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package pagemeta_test
+
+import (
+	"testing"
+
+	"github.com/gohugoio/hugo/hugolib"
+)
+
+func TestLastModEq(t *testing.T) {
+	files := `
+-- hugo.toml --
+timeZone = "Europe/London"
+-- content/p1.md --
+---
+title: p1
+date: 2024-03-13T06:00:00
+---
+-- layouts/_default/single.html --
+Date: {{ .Date }}
+Lastmod: {{ .Lastmod }}
+Eq: {{ eq .Date .Lastmod }}
+
+`
+
+	b := hugolib.Test(t, files)
+
+	b.AssertFileContent("public/p1/index.html", `
+Date: 2024-03-13 06:00:00 &#43;0000 GMT
+Lastmod: 2024-03-13 06:00:00 &#43;0000 GMT
+Eq: true
+`)
+}