Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/gohugoio/hugo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/tpl
diff options
context:
space:
mode:
authorMark Johnson <739719+virgofx@users.noreply.github.com>2020-10-20 01:58:05 +0300
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2020-10-21 10:49:25 +0300
commit26eeb2914720929d2d778f14d6a4bf737014e9e3 (patch)
tree04dbbfcd3b347ff4ba24dda205c72e3a5d775811 /tpl
parentb886fa46bb92916152476cfac45c7a5ee5e5820a (diff)
tpl: Update Hugo time to support optional [LOCATION] parameter
Diffstat (limited to 'tpl')
-rw-r--r--tpl/time/init.go23
-rw-r--r--tpl/time/time.go64
-rw-r--r--tpl/time/time_test.go38
3 files changed, 117 insertions, 8 deletions
diff --git a/tpl/time/init.go b/tpl/time/init.go
index 3112999e4..7abb36637 100644
--- a/tpl/time/init.go
+++ b/tpl/time/init.go
@@ -34,15 +34,26 @@ func init() {
//
// If args are passed, call AsTime().
- if len(args) == 0 {
+ switch len(args) {
+ case 0:
return ctx
- }
+ case 1:
+ t, err := ctx.AsTime(args[0])
+ if err != nil {
+ return err
+ }
+ return t
+ case 2:
+ t, err := ctx.AsTime(args[0], args[1])
+ if err != nil {
+ return err
+ }
+ return t
- t, err := ctx.AsTime(args[0])
- if err != nil {
- return err
+ // 3 or more arguments. Currently not supported.
+ default:
+ return "Invalid arguments supplied to `time`. Refer to time documentation: https://gohugo.io/functions/time/"
}
- return t
},
}
diff --git a/tpl/time/time.go b/tpl/time/time.go
index 598124648..c3a01003a 100644
--- a/tpl/time/time.go
+++ b/tpl/time/time.go
@@ -31,13 +31,73 @@ type Namespace struct{}
// AsTime converts the textual representation of the datetime string into
// a time.Time interface.
-func (ns *Namespace) AsTime(v interface{}) (interface{}, error) {
+func (ns *Namespace) AsTime(v interface{}, args ...interface{}) (interface{}, error) {
t, err := cast.ToTimeE(v)
if err != nil {
return nil, err
}
- return t, nil
+ if len(args) == 0 {
+ return t, nil
+ }
+
+ // Otherwise, if a location is specified, attempt to parse the time using the location specified.
+ // Note: In this case, we require the input variable to be a string for proper parsing.
+ // Note: We can't convert an existing parsed time by using the `Time.In()` as this CONVERTS/MODIFIES
+ // the resulting time.
+
+ switch givenType := v.(type) {
+ case string:
+ // Good, we only support strings
+ break
+
+ default:
+ return nil, fmt.Errorf("Creating a time instance with location requires a value of type String. Given type: %s", givenType)
+ }
+
+ location, err := _time.LoadLocation(args[0].(string))
+ if err != nil {
+ return nil, err
+ }
+
+ // Note: Cast currently doesn't support time with non-default locations. For now, just inlining this.
+ // Reference: https://github.com/spf13/cast/pull/80
+
+ fmts := []string{
+ _time.RFC3339,
+ "2006-01-02T15:04:05", // iso8601 without timezone
+ _time.RFC1123Z,
+ _time.RFC1123,
+ _time.RFC822Z,
+ _time.RFC822,
+ _time.RFC850,
+ _time.ANSIC,
+ _time.UnixDate,
+ _time.RubyDate,
+ "2006-01-02 15:04:05.999999999 -0700 MST", // Time.String()
+ "2006-01-02",
+ "02 Jan 2006",
+ "2006-01-02T15:04:05-0700", // RFC3339 without timezone hh:mm colon
+ "2006-01-02 15:04:05 -07:00",
+ "2006-01-02 15:04:05 -0700",
+ "2006-01-02 15:04:05Z07:00", // RFC3339 without T
+ "2006-01-02 15:04:05Z0700", // RFC3339 without T or timezone hh:mm colon
+ "2006-01-02 15:04:05",
+ _time.Kitchen,
+ _time.Stamp,
+ _time.StampMilli,
+ _time.StampMicro,
+ _time.StampNano,
+ }
+
+ for _, dateType := range fmts {
+ t, err := _time.ParseInLocation(dateType, v.(string), location)
+ if err == nil {
+ return t, nil
+ }
+ }
+
+ return nil, fmt.Errorf("Unable to ParseInLocation using date \"%s\" with timezone \"%s\"", v, location)
}
// Format converts the textual representation of the datetime string into
diff --git a/tpl/time/time_test.go b/tpl/time/time_test.go
index 01cf4e03b..d9e112878 100644
--- a/tpl/time/time_test.go
+++ b/tpl/time/time_test.go
@@ -18,6 +18,44 @@ import (
"time"
)
+func TestTimeLocation(t *testing.T) {
+ t.Parallel()
+
+ ns := New()
+
+ for i, test := range []struct {
+ value string
+ location string
+ expect interface{}
+ }{
+ {"2020-10-20", "", "2020-10-20 00:00:00 +0000 UTC"},
+ {"2020-10-20", "America/New_York", "2020-10-20 00:00:00 -0400 EDT"},
+ {"2020-01-20", "America/New_York", "2020-01-20 00:00:00 -0500 EST"},
+ {"2020-10-20 20:33:59", "", "2020-10-20 20:33:59 +0000 UTC"},
+ {"2020-10-20 20:33:59", "America/New_York", "2020-10-20 20:33:59 -0400 EDT"},
+ // The following have an explicit offset specified. In this case, it overrides timezone
+ {"2020-09-23T20:33:44-0700", "", "2020-09-23 20:33:44 -0700 -0700"},
+ {"2020-09-23T20:33:44-0700", "America/New_York", "2020-09-23 20:33:44 -0700 -0700"},
+ {"2020-01-20", "invalid-timezone", false}, // unknown time zone invalid-timezone
+ {"invalid-value", "", false},
+ } {
+ result, err := ns.AsTime(test.value, test.location)
+ if b, ok := test.expect.(bool); ok && !b {
+ if err == nil {
+ t.Errorf("[%d] AsTime didn't return an expected error, got %v", i, result)
+ }
+ } else {
+ if err != nil {
+ t.Errorf("[%d] AsTime failed: %s", i, err)
+ continue
+ }
+ if result.(time.Time).String() != test.expect {
+ t.Errorf("[%d] AsTime got %v but expected %v", i, result, test.expect)
+ }
+ }
+ }
+}
+
func TestFormat(t *testing.T) {
t.Parallel()