shithub: hugo

Download patch

ref: 807db97af83ff61b022cbc8af80b9dc9cdb8dd43
parent: 26eeb2914720929d2d778f14d6a4bf737014e9e3
author: Cameron Moore <moorereason@gmail.com>
date: Tue Oct 20 16:07:11 EDT 2020

tpl: Refactor time.AsTime location implementation

--- a/docs/content/en/functions/time.md
+++ b/docs/content/en/functions/time.md
@@ -13,13 +13,13 @@
 keywords: [dates,time,location]
 signature: ["time INPUT [LOCATION]"]
 workson: []
-hugoversion:
+hugoversion: "v0.77.0"
 relatedfuncs: []
 deprecated: false
 aliases: []
 ---
 
-`time` converts a timestamp string with an optional timezone into a [`time.Time`](https://godoc.org/time#Time) structure so you can access its fields:
+`time` converts a timestamp string with an optional default location into a [`time.Time`](https://godoc.org/time#Time) structure so you can access its fields:
 
 ```
 {{ time "2016-05-28" }} → "2016-05-28T00:00:00Z"
@@ -27,17 +27,17 @@
 {{ mul 1000 (time "2016-05-28T10:30:00.00+10:00").Unix }} → 1464395400000, or Unix time in milliseconds
 ```
 
-## Using Timezone
+## Using Locations
 
-The optional 2nd parameter [LOCATION] argument is a string that references a timezone that is associated with the specified time value. If the time value has an explicit timezone or offset specified, it will take precedence over an explicit [LOCATION].
+The optional `LOCATION` parameter is a string that sets a default location that is associated with the specified time value. If the time value has an explicit timezone or offset specified, it will take precedence over the `LOCATION` parameter.
 
+The list of valid locations may be system dependent, but should include `UTC`, `Local`, or any location in the [IANA Time Zone database](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones).
+
 ```
 {{ time "2020-10-20" }} → 2020-10-20 00:00:00 +0000 UTC
 {{ time "2020-10-20" "America/Los_Angeles" }} → 2020-10-20 00:00:00 -0700 PDT
 {{ time "2020-01-20" "America/Los_Angeles" }} → 2020-01-20 00:00:00 -0800 PST
 ```
-
-> **Note**: Timezone support via the [LOCATION] parameter is included with Hugo `0.77`.
 
 ## Example: Using `time` to get Month Index
 
--- a/tpl/time/time.go
+++ b/tpl/time/time.go
@@ -21,6 +21,33 @@
 	"github.com/spf13/cast"
 )
 
+var timeFormats = []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,
+}
+
 // New returns a new instance of the time-namespaced template functions.
 func New() *Namespace {
 	return &Namespace{}
@@ -32,30 +59,26 @@
 // AsTime converts the textual representation of the datetime string into
 // a time.Time interface.
 func (ns *Namespace) AsTime(v interface{}, args ...interface{}) (interface{}, error) {
-	t, err := cast.ToTimeE(v)
-	if err != nil {
-		return nil, err
-	}
-
 	if len(args) == 0 {
+		t, err := cast.ToTimeE(v)
+		if err != nil {
+			return nil, err
+		}
+
 		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.
+	timeStr, err := cast.ToStringE(v)
+	if err != nil {
+		return nil, err
+	}
 
-	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)
+	locStr, err := cast.ToStringE(args[0])
+	if err != nil {
+		return nil, err
 	}
 
-	location, err := _time.LoadLocation(args[0].(string))
+	loc, err := _time.LoadLocation(locStr)
 	if err != nil {
 		return nil, err
 	}
@@ -63,41 +86,14 @@
 	// 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 {
+	for _, dateType := range timeFormats {
+		t, err2 := _time.ParseInLocation(dateType, timeStr, loc)
+		if err2 == nil {
 			return t, nil
 		}
 	}
 
-	return nil, fmt.Errorf("Unable to ParseInLocation using date \"%s\" with timezone \"%s\"", v, location)
+	return nil, fmt.Errorf("Unable to ParseInLocation using date %q with timezone %q", v, loc)
 }
 
 // Format converts the textual representation of the datetime string into