1 package goja
2
3 import (
4 "math"
5 "reflect"
6 "time"
7 )
8
9 const (
10 dateTimeLayout = "Mon Jan 02 2006 15:04:05 GMT-0700 (MST)"
11 utcDateTimeLayout = "Mon, 02 Jan 2006 15:04:05 GMT"
12 isoDateTimeLayout = "2006-01-02T15:04:05.000Z"
13 dateLayout = "Mon Jan 02 2006"
14 timeLayout = "15:04:05 GMT-0700 (MST)"
15 datetimeLayout_en_GB = "01/02/2006, 15:04:05"
16 dateLayout_en_GB = "01/02/2006"
17 timeLayout_en_GB = "15:04:05"
18
19 maxTime = 8.64e15
20 timeUnset = math.MinInt64
21 )
22
23 type dateObject struct {
24 baseObject
25 msec int64
26 }
27
28 type dateLayoutDesc struct {
29 layout string
30 dateOnly bool
31 }
32
33 var (
34 dateLayoutsNumeric = []dateLayoutDesc{
35 {layout: "2006-01-02T15:04:05Z0700"},
36 {layout: "2006-01-02T15:04:05"},
37 {layout: "2006-01-02", dateOnly: true},
38 {layout: "2006-01-02 15:04:05"},
39
40 {layout: "2006", dateOnly: true},
41 {layout: "2006-01", dateOnly: true},
42
43 {layout: "2006T15:04"},
44 {layout: "2006-01T15:04"},
45 {layout: "2006-01-02T15:04"},
46
47 {layout: "2006T15:04:05"},
48 {layout: "2006-01T15:04:05"},
49
50 {layout: "2006T15:04Z0700"},
51 {layout: "2006-01T15:04Z0700"},
52 {layout: "2006-01-02T15:04Z0700"},
53
54 {layout: "2006T15:04:05Z0700"},
55 {layout: "2006-01T15:04:05Z0700"},
56 }
57
58 dateLayoutsAlpha = []dateLayoutDesc{
59 {layout: time.RFC1123},
60 {layout: time.RFC1123Z},
61 {layout: dateTimeLayout},
62 {layout: time.UnixDate},
63 {layout: time.ANSIC},
64 {layout: time.RubyDate},
65 {layout: "Mon, _2 Jan 2006 15:04:05 GMT-0700 (MST)"},
66 {layout: "Mon, _2 Jan 2006 15:04:05 -0700 (MST)"},
67 {layout: "Jan _2, 2006", dateOnly: true},
68 }
69 )
70
71 func dateParse(date string) (time.Time, bool) {
72 var t time.Time
73 var err error
74 var layouts []dateLayoutDesc
75 if len(date) > 0 {
76 first := date[0]
77 if first <= '9' && (first >= '0' || first == '-' || first == '+') {
78 layouts = dateLayoutsNumeric
79 } else {
80 layouts = dateLayoutsAlpha
81 }
82 } else {
83 return time.Time{}, false
84 }
85 for _, desc := range layouts {
86 var defLoc *time.Location
87 if desc.dateOnly {
88 defLoc = time.UTC
89 } else {
90 defLoc = time.Local
91 }
92 t, err = parseDate(desc.layout, date, defLoc)
93 if err == nil {
94 break
95 }
96 }
97 if err != nil {
98 return time.Time{}, false
99 }
100 unix := timeToMsec(t)
101 return t, unix >= -maxTime && unix <= maxTime
102 }
103
104 func (r *Runtime) newDateObject(t time.Time, isSet bool, proto *Object) *Object {
105 v := &Object{runtime: r}
106 d := &dateObject{}
107 v.self = d
108 d.val = v
109 d.class = classDate
110 d.prototype = proto
111 d.extensible = true
112 d.init()
113 if isSet {
114 d.msec = timeToMsec(t)
115 } else {
116 d.msec = timeUnset
117 }
118 return v
119 }
120
121 func dateFormat(t time.Time) string {
122 return t.Local().Format(dateTimeLayout)
123 }
124
125 func timeFromMsec(msec int64) time.Time {
126 sec := msec / 1000
127 nsec := (msec % 1000) * 1e6
128 return time.Unix(sec, nsec)
129 }
130
131 func timeToMsec(t time.Time) int64 {
132 return t.Unix()*1000 + int64(t.Nanosecond())/1e6
133 }
134
135 func (d *dateObject) exportType() reflect.Type {
136 return typeTime
137 }
138
139 func (d *dateObject) export(*objectExportCtx) interface{} {
140 if d.isSet() {
141 return d.time()
142 }
143 return nil
144 }
145
146 func (d *dateObject) setTimeMs(ms int64) Value {
147 if ms >= 0 && ms <= maxTime || ms < 0 && ms >= -maxTime {
148 d.msec = ms
149 return intToValue(ms)
150 }
151
152 d.unset()
153 return _NaN
154 }
155
156 func (d *dateObject) isSet() bool {
157 return d.msec != timeUnset
158 }
159
160 func (d *dateObject) unset() {
161 d.msec = timeUnset
162 }
163
164 func (d *dateObject) time() time.Time {
165 return timeFromMsec(d.msec)
166 }
167
168 func (d *dateObject) timeUTC() time.Time {
169 return timeFromMsec(d.msec).In(time.UTC)
170 }
171
View as plain text