Better support for TZ locations in the times module (#397)

* Handle panics by deferring recover as an error

* Check for type in recover handler

* Added support for times.in_location

* Added support for location (TZ) to times.date

* Updated documentation
This commit is contained in:
Mikael Ganehag Brorsson 2023-01-31 10:51:04 +01:00 committed by GitHub
parent ecc3d9181e
commit 82b543fd98
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 79 additions and 5 deletions

View file

@ -62,9 +62,10 @@ times := import("times")
duration.
- `month_string(month int) => string`: returns the English name of the month
("January", "February", ...).
- `date(year int, month int, day int, hour int, min int, sec int, nsec int) => time`:
returns the Time corresponding to "yyyy-mm-dd hh:mm:ss + nsec nanoseconds".
Current location is used.
- `date(year int, month int, day int, hour int, min int, sec int, nsec int, loc string) => time`:
returns the Time corresponding to "yyyy-mm-dd hh:mm:ss + nsec nanoseconds" in
the appropriate zone for that Time in the given (optional) location.
The Local time zone will be used if executed without specifying a location.
- `now() => time`: returns the current local time.
- `parse(format string, s string) => time`: parses a formatted string and
returns the time value it represents. The layout defines the format by
@ -116,5 +117,8 @@ times := import("times")
string "2006-01-02 15:04:05.999999999 -0700 MST".
- `is_zero(t time) => bool`: reports whether t represents the zero time
instant, January 1, year 1, 00:00:00 UTC.
- `in_location(t time, l string) => time`: returns a copy of t representing
the same time instant, but with the copy's location information set to l for
display purposes.
- `to_local(t time) => time`: returns t with the location set to local time.
- `to_utc(t time) => time`: returns t with the location set to UTC.

View file

@ -180,6 +180,10 @@ var timesModule = map[string]tengo.Object{
Name: "to_utc",
Value: timesToUTC,
}, // to_utc(time) => time
"in_location": &tengo.UserFunction{
Name: "in_location",
Value: timesInLocation,
}, // in_location(time, location) => time
}
func timesSleep(args ...tengo.Object) (ret tengo.Object, err error) {
@ -430,7 +434,7 @@ func timesDate(args ...tengo.Object) (
ret tengo.Object,
err error,
) {
if len(args) != 7 {
if len(args) < 7 || len(args) > 8 {
err = tengo.ErrWrongNumArguments
return
}
@ -499,9 +503,29 @@ func timesDate(args ...tengo.Object) (
return
}
var loc *time.Location
if len(args) == 8 {
i8, ok := tengo.ToString(args[7])
if !ok {
err = tengo.ErrInvalidArgumentType{
Name: "eighth",
Expected: "string(compatible)",
Found: args[7].TypeName(),
}
return
}
loc, err = time.LoadLocation(i8)
if err != nil {
ret = wrapError(err)
return
}
} else {
loc = time.Now().Location()
}
ret = &tengo.Time{
Value: time.Date(i1,
time.Month(i2), i3, i4, i5, i6, i7, time.Now().Location()),
time.Month(i2), i3, i4, i5, i6, i7, loc),
}
return
@ -1113,6 +1137,46 @@ func timesTimeLocation(args ...tengo.Object) (
return
}
func timesInLocation(args ...tengo.Object) (
ret tengo.Object,
err error,
) {
if len(args) != 2 {
err = tengo.ErrWrongNumArguments
return
}
t1, ok := tengo.ToTime(args[0])
if !ok {
err = tengo.ErrInvalidArgumentType{
Name: "first",
Expected: "time(compatible)",
Found: args[0].TypeName(),
}
return
}
s2, ok := tengo.ToString(args[1])
if !ok {
err = tengo.ErrInvalidArgumentType{
Name: "second",
Expected: "string(compatible)",
Found: args[1].TypeName(),
}
return
}
location, err := time.LoadLocation(s2)
if err != nil {
ret = wrapError(err)
return
}
ret = &tengo.Time{Value: t1.In(location)}
return
}
func timesTimeString(args ...tengo.Object) (ret tengo.Object, err error) {
if len(args) != 1 {
err = tengo.ErrWrongNumArguments

View file

@ -11,6 +11,8 @@ import (
func TestTimes(t *testing.T) {
time1 := time.Date(1982, 9, 28, 19, 21, 44, 999, time.Now().Location())
time2 := time.Now()
location, _ := time.LoadLocation("Pacific/Auckland")
time3 := time.Date(1982, 9, 28, 19, 21, 44, 999, location)
module(t, "times").call("sleep", 1).expect(tengo.UndefinedValue)
@ -35,6 +37,9 @@ func TestTimes(t *testing.T) {
module(t, "times").call("date", 1982, 9, 28, 19, 21, 44, 999).
expect(time1)
module(t, "times").call("date", 1982, 9, 28, 19, 21, 44, 999, "Pacific/Auckland").
expect(time3)
nowD := time.Until(module(t, "times").call("now").
o.(*tengo.Time).Value).Nanoseconds()
require.True(t, 0 > nowD && nowD > -100000000) // within 100ms
@ -80,4 +85,5 @@ func TestTimes(t *testing.T) {
module(t, "times").call("time_location", time1).
expect(time1.Location().String())
module(t, "times").call("time_string", time1).expect(time1.String())
module(t, "times").call("in_location", time1, location.String()).expect(time1.In(location))
}