github.com/nuvolaris/goja@v0.0.0-20230825100449-967811910c6d/date.go (about) 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 }