1111// See the License for the specific language governing permissions and
1212// limitations under the License.
1313
14- package time
14+ package time_test
1515
1616import (
1717 "strings"
1818 "testing"
19- "time"
19+ gtime "time"
2020
2121 qt "github.com/frankban/quicktest"
2222
2323 "github.com/gohugoio/hugo/common/htime"
24+ "github.com/gohugoio/hugo/hugolib"
25+ "github.com/gohugoio/hugo/tpl/time"
26+
2427 translators "github.com/gohugoio/localescompressed"
2528)
2629
2730func TestTimeLocation (t * testing.T ) {
2831 t .Parallel ()
2932
30- loc , _ := time .LoadLocation ("America/Antigua" )
31- ns := New (htime .NewTimeFormatter (translators .GetTranslator ("en" )), loc )
33+ b := hugolib .NewIntegrationTestBuilder (
34+ hugolib.IntegrationTestConfig {T : t },
35+ ).Build ()
36+
37+ loc , _ := gtime .LoadLocation ("America/Antigua" )
38+ ns := time .New (htime .NewTimeFormatter (translators .GetTranslator ("en" )), loc , b .H .Deps )
3239
3340 for i , test := range []struct {
3441 name string
@@ -72,7 +79,7 @@ func TestTimeLocation(t *testing.T) {
7279 // See https://github.com/gohugoio/hugo/issues/8843#issuecomment-891551447
7380 // Drop the location string (last element) when comparing,
7481 // as that may change depending on the local locale.
75- timeStr := result .(time .Time ).String ()
82+ timeStr := result .(gtime .Time ).String ()
7683 timeStr = timeStr [:strings .LastIndex (timeStr , " " )]
7784 if ! strings .HasPrefix (test .expect .(string ), timeStr ) {
7885 t .Errorf ("[%d] AsTime got %v but expected %v" , i , timeStr , test .expect )
@@ -85,25 +92,30 @@ func TestTimeLocation(t *testing.T) {
8592func TestFormat (t * testing.T ) {
8693 c := qt .New (t )
8794
95+ b := hugolib .NewIntegrationTestBuilder (
96+ hugolib.IntegrationTestConfig {T : t },
97+ ).Build ()
98+
8899 c .Run ("UTC" , func (c * qt.C ) {
89100 c .Parallel ()
90- ns := New (htime .NewTimeFormatter (translators .GetTranslator ("en" )), time .UTC )
101+
102+ ns := time .New (htime .NewTimeFormatter (translators .GetTranslator ("en" )), gtime .UTC , b .H .Deps )
91103
92104 for i , test := range []struct {
93105 layout string
94106 value any
95107 expect any
96108 }{
97109 {"Monday, Jan 2, 2006" , "2015-01-21" , "Wednesday, Jan 21, 2015" },
98- {"Monday, Jan 2, 2006" , time .Date (2015 , time .January , 21 , 0 , 0 , 0 , 0 , time .UTC ), "Wednesday, Jan 21, 2015" },
110+ {"Monday, Jan 2, 2006" , gtime .Date (2015 , gtime .January , 21 , 0 , 0 , 0 , 0 , gtime .UTC ), "Wednesday, Jan 21, 2015" },
99111 {"This isn't a date layout string" , "2015-01-21" , "This isn't a date layout string" },
100112 // The following test case gives either "Tuesday, Jan 20, 2015" or "Monday, Jan 19, 2015" depending on the local time zone
101- {"Monday, Jan 2, 2006" , 1421733600 , time .Unix (1421733600 , 0 ).Format ("Monday, Jan 2, 2006" )},
113+ {"Monday, Jan 2, 2006" , 1421733600 , gtime .Unix (1421733600 , 0 ).Format ("Monday, Jan 2, 2006" )},
102114 {"Monday, Jan 2, 2006" , 1421733600.123 , false },
103- {time .RFC3339 , time .Date (2016 , time .March , 3 , 4 , 5 , 0 , 0 , time .UTC ), "2016-03-03T04:05:00Z" },
104- {time .RFC1123 , time .Date (2016 , time .March , 3 , 4 , 5 , 0 , 0 , time .UTC ), "Thu, 03 Mar 2016 04:05:00 UTC" },
105- {time .RFC3339 , "Thu, 03 Mar 2016 04:05:00 UTC" , "2016-03-03T04:05:00Z" },
106- {time .RFC1123 , "2016-03-03T04:05:00Z" , "Thu, 03 Mar 2016 04:05:00 UTC" },
115+ {gtime .RFC3339 , gtime .Date (2016 , gtime .March , 3 , 4 , 5 , 0 , 0 , gtime .UTC ), "2016-03-03T04:05:00Z" },
116+ {gtime .RFC1123 , gtime .Date (2016 , gtime .March , 3 , 4 , 5 , 0 , 0 , gtime .UTC ), "Thu, 03 Mar 2016 04:05:00 UTC" },
117+ {gtime .RFC3339 , "Thu, 03 Mar 2016 04:05:00 UTC" , "2016-03-03T04:05:00Z" },
118+ {gtime .RFC1123 , "2016-03-03T04:05:00Z" , "Thu, 03 Mar 2016 04:05:00 UTC" },
107119 // Custom layouts, as introduced in Hugo 0.87.
108120 {":date_medium" , "2015-01-21" , "Jan 21, 2015" },
109121 } {
@@ -128,9 +140,9 @@ func TestFormat(t *testing.T) {
128140 c .Run ("TZ America/Los_Angeles" , func (c * qt.C ) {
129141 c .Parallel ()
130142
131- loc , err := time .LoadLocation ("America/Los_Angeles" )
143+ loc , err := gtime .LoadLocation ("America/Los_Angeles" )
132144 c .Assert (err , qt .IsNil )
133- ns := New (htime .NewTimeFormatter (translators .GetTranslator ("en" )), loc )
145+ ns := time . New (htime .NewTimeFormatter (translators .GetTranslator ("en" )), loc , b . H . Deps )
134146
135147 d , err := ns .Format (":time_full" , "2020-03-09T11:00:00" )
136148
@@ -142,28 +154,32 @@ func TestFormat(t *testing.T) {
142154func TestDuration (t * testing.T ) {
143155 t .Parallel ()
144156
145- ns := New (htime .NewTimeFormatter (translators .GetTranslator ("en" )), time .UTC )
157+ b := hugolib .NewIntegrationTestBuilder (
158+ hugolib.IntegrationTestConfig {T : t },
159+ ).Build ()
160+
161+ ns := time .New (htime .NewTimeFormatter (translators .GetTranslator ("en" )), gtime .UTC , b .H .Deps )
146162
147163 for i , test := range []struct {
148164 unit any
149165 num any
150166 expect any
151167 }{
152- {"nanosecond" , 10 , 10 * time .Nanosecond },
153- {"ns" , 10 , 10 * time .Nanosecond },
154- {"microsecond" , 20 , 20 * time .Microsecond },
155- {"us" , 20 , 20 * time .Microsecond },
156- {"µs" , 20 , 20 * time .Microsecond },
157- {"millisecond" , 20 , 20 * time .Millisecond },
158- {"ms" , 20 , 20 * time .Millisecond },
159- {"second" , 30 , 30 * time .Second },
160- {"s" , 30 , 30 * time .Second },
161- {"minute" , 20 , 20 * time .Minute },
162- {"m" , 20 , 20 * time .Minute },
163- {"hour" , 20 , 20 * time .Hour },
164- {"h" , 20 , 20 * time .Hour },
168+ {"nanosecond" , 10 , 10 * gtime .Nanosecond },
169+ {"ns" , 10 , 10 * gtime .Nanosecond },
170+ {"microsecond" , 20 , 20 * gtime .Microsecond },
171+ {"us" , 20 , 20 * gtime .Microsecond },
172+ {"µs" , 20 , 20 * gtime .Microsecond },
173+ {"millisecond" , 20 , 20 * gtime .Millisecond },
174+ {"ms" , 20 , 20 * gtime .Millisecond },
175+ {"second" , 30 , 30 * gtime .Second },
176+ {"s" , 30 , 30 * gtime .Second },
177+ {"minute" , 20 , 20 * gtime .Minute },
178+ {"m" , 20 , 20 * gtime .Minute },
179+ {"hour" , 20 , 20 * gtime .Hour },
180+ {"h" , 20 , 20 * gtime .Hour },
165181 {"hours" , 20 , false },
166- {"hour" , "30" , 30 * time .Hour },
182+ {"hour" , "30" , 30 * gtime .Hour },
167183 } {
168184 result , err := ns .Duration (test .unit , test .num )
169185 if b , ok := test .expect .(bool ); ok && ! b {
@@ -181,3 +197,74 @@ func TestDuration(t *testing.T) {
181197 }
182198 }
183199}
200+
201+ func TestIn (t * testing.T ) {
202+ t .Parallel ()
203+
204+ b := hugolib .NewIntegrationTestBuilder (
205+ hugolib.IntegrationTestConfig {T : t },
206+ ).Build ()
207+
208+ ns := time .New (htime .NewTimeFormatter (translators .GetTranslator ("en" )), gtime .UTC , b .H .Deps )
209+
210+ in := gtime .Date (2025 , gtime .March , 31 , 15 , 0 , 0 , 0 , gtime .UTC )
211+
212+ tests := []struct {
213+ name string
214+ tzn string // time zone name
215+ want string
216+ wantErr bool
217+ }{
218+ {name : "A" , tzn : "America/Denver" , want : "2025-03-31T09:00:00-06:00" , wantErr : false },
219+ {name : "B" , tzn : "Australia/Adelaide" , want : "2025-04-01T01:30:00+10:30" , wantErr : false },
220+ {name : "C" , tzn : "Europe/Oslo" , want : "2025-03-31T17:00:00+02:00" , wantErr : false },
221+ {name : "D" , tzn : "UTC" , want : "2025-03-31T15:00:00+00:00" , wantErr : false },
222+ {name : "E" , tzn : "" , want : "2025-03-31T15:00:00+00:00" , wantErr : false },
223+ {name : "F" , tzn : "InvalidTimeZoneName" , want : "0001-01-01T00:00:00+00:00" , wantErr : true },
224+ }
225+
226+ for _ , tt := range tests {
227+ t .Run (tt .name , func (t * testing.T ) {
228+ result , err := ns .In (tt .tzn , in )
229+ if (err != nil ) != tt .wantErr {
230+ t .Errorf ("time.In() error = %v, wantErr %v" , err , tt .wantErr )
231+ return
232+ }
233+ got := result .Format ("2006-01-02T15:04:05-07:00" )
234+ if got != tt .want {
235+ t .Errorf ("time.In() = %v, want %v" , got , tt .want )
236+ }
237+ })
238+ }
239+ }
240+
241+ // For benchmark tests below.
242+ var timeZoneNames []string = []string {"America/New_York" , "Europe/Oslo" , "Australia/Sydney" , "UTC" , "Local" }
243+
244+ func BenchmarkInWithCaching (b * testing.B ) {
245+ bb := hugolib .NewIntegrationTestBuilder (
246+ hugolib.IntegrationTestConfig {T : b },
247+ ).Build ()
248+
249+ ns := time .New (htime .NewTimeFormatter (translators .GetTranslator ("en" )), gtime .UTC , bb .H .Deps )
250+
251+ for i := 0 ; i < b .N ; i ++ {
252+ timeZoneName := timeZoneNames [i % len (timeZoneNames )]
253+ _ , err := ns .In (timeZoneName , gtime .Now ())
254+ if err != nil {
255+ b .Fatalf ("Error during benchmark: %v" , err )
256+ }
257+ }
258+ }
259+
260+ func BenchmarkInWithoutCaching (b * testing.B ) {
261+ for i := 0 ; i < b .N ; i ++ {
262+ timeZoneName := timeZoneNames [i % len (timeZoneNames )]
263+ location , err := gtime .LoadLocation (timeZoneName )
264+ if err != nil {
265+ b .Fatalf ("Error during benchmark: %v" , err )
266+ }
267+
268+ _ = gtime .Now ().In (location )
269+ }
270+ }
0 commit comments