1
0
mirror of https://github.com/MontFerret/ferret.git synced 2025-01-16 03:21:03 +02:00

Feature/#8 datetime (#153)

This commit is contained in:
3timeslazy 2018-11-01 02:26:36 +03:00 committed by Tim Voronov
parent d8ae6cca8b
commit 612705ca3a
10 changed files with 297 additions and 36 deletions

View File

@ -7,7 +7,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
)
const defaultTimeLayout = time.RFC3339
const DefaultTimeLayout = time.RFC3339
type DateTime struct {
time.Time
@ -26,7 +26,7 @@ func NewDateTime(time time.Time) DateTime {
}
func ParseDateTime(input interface{}) (DateTime, error) {
return ParseDateTimeWith(input, defaultTimeLayout)
return ParseDateTimeWith(input, DefaultTimeLayout)
}
func ParseDateTimeWith(input interface{}, layout string) (DateTime, error) {

View File

@ -0,0 +1,33 @@
package datetime
import (
"context"
"time"
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
)
// Date convert RFC3339 date time string to DateTime object.
// @params timeString (String) - string in RFC3339 format.
// @return (DateTime) - new DateTime object derived from timeString.
func Date(_ context.Context, args ...core.Value) (core.Value, error) {
err := core.ValidateArgs(args, 1, 1)
if err != nil {
return values.None, err
}
err = core.ValidateType(args[0], core.StringType)
if err != nil {
return values.None, err
}
timeStrings := args[0].(values.String)
t, err := time.Parse(values.DefaultTimeLayout, timeStrings.String())
if err != nil {
return values.None, err
}
return values.NewDateTime(t), nil
}

View File

@ -0,0 +1,49 @@
package datetime_test
import (
"testing"
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/stdlib/datetime"
)
func TestDate(t *testing.T) {
tcs := []*testCase{
&testCase{
Name: "When more than 1 arguments",
Expected: values.None,
Args: []core.Value{
values.NewString("string"),
values.NewInt(0),
},
ShouldErr: true,
},
&testCase{
Name: "When 0 arguments",
Expected: values.None,
Args: []core.Value{},
ShouldErr: true,
},
&testCase{
Name: "When incorrect timeStrings",
Expected: values.None,
Args: []core.Value{
values.NewString("bla-bla"),
},
ShouldErr: true,
},
&testCase{
Name: "When correct timeString in RFC3339 format",
Expected: mustDefaultLayoutDt("1999-02-07T15:04:05Z"),
Args: []core.Value{
values.NewString("1999-02-07T15:04:05Z"),
},
},
}
for _, tc := range tcs {
tc.Do(t, datetime.Date)
}
}

View File

@ -0,0 +1,28 @@
package datetime
import (
"context"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/core"
)
// DateDayOfWeek returns number of the weekday from the date. Sunday is the 0th day of week.
// @params date (DateTime) - source DateTime.
// @return (Int) - return number of the weekday.
func DateDayOfWeek(_ context.Context, args ...core.Value) (core.Value, error) {
err := core.ValidateArgs(args, 1, 1)
if err != nil {
return values.None, err
}
err = core.ValidateType(args[0], core.DateTimeType)
if err != nil {
return values.None, err
}
wday := args[0].(values.DateTime).Weekday()
return values.NewInt(int(wday)), nil
}

View File

@ -0,0 +1,43 @@
package datetime_test
import (
"testing"
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/stdlib/datetime"
)
func TestDateDayOfWeek(t *testing.T) {
tcs := []*testCase{
&testCase{
Name: "When more than 1 arguments",
Expected: values.None,
Args: []core.Value{
values.NewString("string"),
values.NewInt(0),
},
ShouldErr: true,
},
&testCase{
Name: "When 0 arguments",
Expected: values.None,
Args: []core.Value{},
ShouldErr: true,
},
&testCase{
Name: "When Sunday (0th day)",
Expected: values.NewInt(0),
Args: []core.Value{mustDefaultLayoutDt("1999-02-07T15:04:05Z")},
},
&testCase{
Name: "When Monday (1th day)",
Expected: values.NewInt(1),
Args: []core.Value{mustDefaultLayoutDt("1999-02-08T15:04:05Z")},
},
}
for _, tc := range tcs {
tc.Do(t, datetime.DateDayOfWeek)
}
}

View File

@ -0,0 +1,65 @@
package datetime_test
import (
"context"
"testing"
"time"
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
. "github.com/smartystreets/goconvey/convey"
)
type testCase struct {
Name string
Expected core.Value
TimeArg time.Time
Args []core.Value
ShouldErr bool
}
func (tc *testCase) Do(t *testing.T, fn core.Function) {
Convey(tc.Name, t, func() {
expected := tc.Expected
actual, err := fn(context.Background(), tc.Args...)
if tc.ShouldErr {
So(err, ShouldBeError)
expected = values.None
} else {
So(err, ShouldBeNil)
}
So(actual.Compare(expected), ShouldEqual, 0)
})
}
func mustDefaultLayoutDt(timeString string) values.DateTime {
dt, err := defaultLayoutDt(timeString)
if err != nil {
panic(err)
}
return dt
}
func mustLayoutDt(layout, value string) values.DateTime {
dt, err := layoutDt(layout, value)
if err != nil {
panic(err)
}
return dt
}
func defaultLayoutDt(timeString string) (values.DateTime, error) {
return layoutDt(values.DefaultTimeLayout, timeString)
}
func layoutDt(layout, value string) (values.DateTime, error) {
t, err := time.Parse(layout, value)
if err != nil {
return values.DateTime{}, err
}
return values.NewDateTime(t), nil
}

View File

@ -4,6 +4,9 @@ import "github.com/MontFerret/ferret/pkg/runtime/core"
func NewLib() map[string]core.Function {
return map[string]core.Function{
"NOW": Now,
"NOW": Now,
"DATE": Date,
"DATE_DAYOFWEEK": DateDayOfWeek,
"DATE_YEAR": DateYear,
}
}

View File

@ -1,25 +1,14 @@
package datetime_test
import (
"context"
"testing"
"time"
"github.com/MontFerret/ferret/pkg/stdlib/datetime"
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/stdlib/datetime"
. "github.com/smartystreets/goconvey/convey"
)
type testCase struct {
Name string
Expected core.Value
TimeArg time.Time
Args []core.Value
ShouldErr bool
}
func TestNow(t *testing.T) {
tcs := []*testCase{
&testCase{
@ -33,25 +22,6 @@ func TestNow(t *testing.T) {
}
for _, tc := range tcs {
tc.Do(t)
tc.Do(t, datetime.Now)
}
}
func (tc *testCase) Do(t *testing.T) {
Convey(tc.Name, t, func() {
var expected core.Value
expected = values.NewDateTime(tc.TimeArg)
dt, err := datetime.Now(context.Background(), tc.Args...)
if tc.ShouldErr {
So(err, ShouldBeError)
expected = values.None
} else {
So(err, ShouldBeNil)
}
So(dt, ShouldEqual, expected)
})
}

View File

@ -0,0 +1,27 @@
package datetime
import (
"context"
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
)
// DateYear returns the year extracted from the given date.
// @params date (DateTime) - source DateTime.
// @return (Int) - a year number.
func DateYear(_ context.Context, args ...core.Value) (core.Value, error) {
err := core.ValidateArgs(args, 1, 1)
if err != nil {
return values.None, err
}
err = core.ValidateType(args[0], core.DateTimeType)
if err != nil {
return values.None, err
}
year := args[0].(values.DateTime).Year()
return values.NewInt(year), nil
}

View File

@ -0,0 +1,43 @@
package datetime_test
import (
"testing"
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/stdlib/datetime"
)
func TestDateYear(t *testing.T) {
tcs := []*testCase{
&testCase{
Name: "When more than 1 arguments",
Expected: values.None,
Args: []core.Value{
values.NewString("string"),
values.NewInt(0),
},
ShouldErr: true,
},
&testCase{
Name: "When 0 arguments",
Expected: values.None,
Args: []core.Value{},
ShouldErr: true,
},
&testCase{
Name: "When 1999th year",
Expected: values.NewInt(1999),
Args: []core.Value{mustDefaultLayoutDt("1999-02-07T15:04:05Z")},
},
&testCase{
Name: "When 1629th year",
Expected: values.NewInt(1629),
Args: []core.Value{mustDefaultLayoutDt("1629-02-08T15:04:05Z")},
},
}
for _, tc := range tcs {
tc.Do(t, datetime.DateYear)
}
}