-
Notifications
You must be signed in to change notification settings - Fork 0
/
func.go
107 lines (96 loc) · 2.72 KB
/
func.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
package go_template
import (
"fmt"
"time"
"github.com/shopspring/decimal"
)
type IFn func(config *TemplateConfig, args []interface{}) (interface{}, error)
type FnMgr struct {
Funcs map[string]IFn
}
func tryParseTime(timeStr string, config *TemplateConfig) (time.Time, error) {
formats := []string{time.RFC3339Nano, time.RFC3339, time.RFC822, time.RFC822Z, time.RFC850, time.RFC1123Z, time.RFC1123, time.ANSIC, time.UnixDate, time.Layout, time.RubyDate}
formats = append(formats, config.TimeFormat)
for _, format := range formats {
t, err := time.Parse(format, timeStr)
if err == nil {
return t, nil
}
}
return time.Time{}, fmt.Errorf("unknown time format: %s", timeStr)
}
func withTimezone(config *TemplateConfig, args []interface{}) (interface{}, error) {
var timeOffset = config.TimeOffset
var timeFormat = config.TimeFormat
if len(args) >= 2 {
offset, ok := args[1].(decimal.Decimal)
if !ok {
return nil, ErrFMsg("format arg1 must be timezone: %v", args[1])
}
timeOffset = int(offset.IntPart())
}
if len(args) == 3 {
format, ok := args[2].(string)
if !ok {
return nil, ErrFMsg("format arg2 must be format string: %v", args[2])
}
timeFormat = format
}
var dt time.Time
var err error
dtStr, ok := args[0].(string)
if !ok {
// maybe timestamp int64
if ts, ok := args[0].(decimal.Decimal); ok {
if ts.GreaterThan(decimal.NewFromInt(10000000000)) {
dt = time.UnixMilli(ts.IntPart())
} else {
dt = time.Unix(ts.IntPart(), 0)
}
} else {
return nil, ErrFMsg("timezone arg0 must be string|int64|uint64: %v", dtStr)
}
} else {
dt, err = tryParseTime(dtStr, config)
if err != nil {
ts, err := decimal.NewFromString(dtStr)
if err != nil {
return nil, ErrFMsg("timezone arg0 must be rfc3339nano format or timestamp: %s", dtStr)
}
if ts.GreaterThan(decimal.NewFromInt(10000000000)) {
dt = time.UnixMilli(ts.IntPart())
} else {
dt = time.Unix(ts.IntPart(), 0)
}
}
}
return FormatTime(dt, timeOffset, timeFormat), nil
}
func NewFnMgr() *FnMgr {
return &FnMgr{
Funcs: map[string]IFn{
"round": func(config *TemplateConfig, args []interface{}) (interface{}, error) {
if len(args) != 2 {
return nil, ErrFMsg("round only accept 2 arg, got: %d", len(args))
}
n, ok := args[0].(decimal.Decimal)
if !ok {
return nil, ErrFMsg("round with NaN: %v", n)
}
place, ok := args[1].(decimal.Decimal)
if !ok {
return nil, ErrFMsg("round to NaN: %v", place)
}
return n.Round(int32(place.BigInt().Int64())), nil
},
"timezone": withTimezone,
"formatTime": withTimezone,
},
}
}
func (f *FnMgr) RegisterFunc(name string, fn IFn) {
f.Funcs[name] = fn
}
func (f *FnMgr) GetFunc(name string) IFn {
return f.Funcs[name]
}