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