diff --git a/builtin.go b/builtin.go index 8fd425c..d9a2e03 100644 --- a/builtin.go +++ b/builtin.go @@ -1222,6 +1222,26 @@ func builtinDate_setTime(call FunctionCall) Value { return date.Value() } +func _builtinDate_set(call FunctionCall, argumentCap int, dateLocal bool) (*_dateObject, *_ecmaTime) { + date := dateObjectOf(call.thisObject()) + if date.isNaN { + return nil, nil + } + for index := 0; index < len(call.ArgumentList) && index < argumentCap; index++ { + value := call.Argument(index) + if value.IsNaN() { + date.SetNaN() + return date, nil + } + } + baseTime := date.Time() + if dateLocal { + baseTime = baseTime.Local() + } + ecmaTime := ecmaTime(baseTime) + return date, &ecmaTime +} + // Error func builtinError(call FunctionCall) Value { diff --git a/global.go b/global.go index 7f8054e..f531eb4 100644 --- a/global.go +++ b/global.go @@ -444,51 +444,21 @@ func newContext() *_runtime { // setTime, ... "setTime", 1, builtinDate_setTime, "setMilliseconds", 1, func(call FunctionCall) Value { - date := dateObjectOf(call.thisObject()) - if date.isNaN { + date, ecmaTime := _builtinDate_set(call, 1, true) + if ecmaTime == nil { return NaNValue() } - value := call.Argument(0) - if value.IsNaN() { - date.SetNaN() - return NaNValue() - } - baseTime := date.Time().Local() - setTime := time_.Date( - baseTime.Year(), - baseTime.Month(), - baseTime.Day(), - baseTime.Hour(), - baseTime.Minute(), - baseTime.Second(), - int(toInteger(value)) * 100 * 100 * 100, - baseTime.Location(), - ) - date.SetTime(setTime) + ecmaTime.millisecond = int(toInteger(call.Argument(0))) + date.SetTime(ecmaTime.goTime()) return date.Value() }, "setUTCMilliseconds", 1, func(call FunctionCall) Value { - date := dateObjectOf(call.thisObject()) - if date.isNaN { + date, ecmaTime := _builtinDate_set(call, 1, false) + if ecmaTime == nil { return NaNValue() } - value := call.Argument(0) - if value.IsNaN() { - date.SetNaN() - return NaNValue() - } - baseTime := date.Time().UTC() - setTime := time_.Date( - baseTime.Year(), - baseTime.Month(), - baseTime.Day(), - baseTime.Hour(), - baseTime.Minute(), - baseTime.Second(), - int(toInteger(value)) * 100 * 100 * 100, - baseTime.Location(), - ) - date.SetTime(setTime) + ecmaTime.millisecond = int(toInteger(call.Argument(0))) + date.SetTime(ecmaTime.goTime()) return date.Value() }, // setSeconds @@ -500,99 +470,39 @@ func newContext() *_runtime { // setDate // setUTCDate "setMonth", 1, func(call FunctionCall) Value { - date := dateObjectOf(call.thisObject()) - if date.isNaN { + date, ecmaTime := _builtinDate_set(call, 1, true) + if ecmaTime == nil { return NaNValue() } - value := call.Argument(0) - if value.IsNaN() { - date.SetNaN() - return NaNValue() - } - baseTime := date.Time().Local() - setTime := time_.Date( - baseTime.Year(), - dateToGoMonth(int(toInteger(value))), - baseTime.Day(), - baseTime.Hour(), - baseTime.Minute(), - baseTime.Second(), - baseTime.Nanosecond(), - baseTime.Location(), - ) - date.SetTime(setTime) + ecmaTime.month = int(toInteger(call.Argument(0))) + date.SetTime(ecmaTime.goTime()) return date.Value() }, "setUTCMonth", 1, func(call FunctionCall) Value { - date := dateObjectOf(call.thisObject()) - if date.isNaN { + date, ecmaTime := _builtinDate_set(call, 1, false) + if ecmaTime == nil { return NaNValue() } - value := call.Argument(0) - if value.IsNaN() { - date.SetNaN() - return NaNValue() - } - baseTime := date.Time().UTC() - setTime := time_.Date( - baseTime.Year(), - dateToGoMonth(int(toInteger(value))), - baseTime.Day(), - baseTime.Hour(), - baseTime.Minute(), - baseTime.Second(), - baseTime.Nanosecond(), - baseTime.Location(), - ) - date.SetTime(setTime) + ecmaTime.month = int(toInteger(call.Argument(0))) + date.SetTime(ecmaTime.goTime()) return date.Value() }, "setFullYear", 1, func(call FunctionCall) Value { - date := dateObjectOf(call.thisObject()) - if date.isNaN { + date, ecmaTime := _builtinDate_set(call, 1, true) + if ecmaTime == nil { return NaNValue() } - value := call.Argument(0) - if value.IsNaN() { - date.SetNaN() - return NaNValue() - } - baseTime := date.Time().Local() - setTime := time_.Date( - int(toInteger(value)), - baseTime.Month(), - baseTime.Day(), - baseTime.Hour(), - baseTime.Minute(), - baseTime.Second(), - baseTime.Nanosecond(), - baseTime.Location(), - ) - date.SetTime(setTime) + ecmaTime.year = int(toInteger(call.Argument(0))) + date.SetTime(ecmaTime.goTime()) return date.Value() }, "setUTCFullYear", 1, func(call FunctionCall) Value { - date := dateObjectOf(call.thisObject()) - if date.isNaN { + date, ecmaTime := _builtinDate_set(call, 1, false) + if ecmaTime == nil { return NaNValue() } - value := call.Argument(0) - if value.IsNaN() { - date.SetNaN() - return NaNValue() - } - baseTime := date.Time().UTC() - setTime := time_.Date( - int(toInteger(value)), - baseTime.Month(), - baseTime.Day(), - baseTime.Hour(), - baseTime.Minute(), - baseTime.Second(), - baseTime.Nanosecond(), - baseTime.Location(), - ) - date.SetTime(setTime) + ecmaTime.year = int(toInteger(call.Argument(0))) + date.SetTime(ecmaTime.goTime()) return date.Value() }, // toUTCString diff --git a/otto_test.go b/otto_test.go index 93d63c4..7698481 100644 --- a/otto_test.go +++ b/otto_test.go @@ -579,6 +579,7 @@ func TestDate(t *testing.T) { test(`new Date(2009, 9, 25).toString()`, "Sun, 25 Oct 2009 00:00:00 UTC") test(`+(new Date(2009, 9, 25))`, "1.2564288e+12") + test(`abc = new Date(12564504e5); abc.setMilliseconds(2001); abc.toString()`, "Sun, 25 Oct 2009 06:00:02 UTC") test(`abc = new Date(12564504e5); abc.setMonth(9); abc.toString()`, "Sun, 25 Oct 2009 06:00:00 UTC") test(`abc = new Date(12564504e5); abc.setMonth("09"); abc.toString()`, "Sun, 25 Oct 2009 06:00:00 UTC") test(`abc = new Date(12564504e5); abc.setMonth("10"); abc.toString()`, "Wed, 25 Nov 2009 07:00:00 UTC") diff --git a/type_date.go b/type_date.go index 68ed4a4..0c997ae 100644 --- a/type_date.go +++ b/type_date.go @@ -13,6 +13,43 @@ type _dateObject struct { isNaN bool } +type _ecmaTime struct { + year int + month int + day int + hour int + minute int + second int + millisecond int + location *tme.Location // Basically, either local or UTC +} + +func ecmaTime(goTime tme.Time) _ecmaTime { + return _ecmaTime{ + goTime.Year(), + dateFromGoMonth(goTime.Month()), + goTime.Day(), + goTime.Hour(), + goTime.Minute(), + goTime.Second(), + goTime.Nanosecond() / (100 * 100 * 100), + goTime.Location(), + } +} + +func (self *_ecmaTime) goTime() tme.Time { + return tme.Date( + self.year, + dateToGoMonth(self.month), + self.day, + self.hour, + self.minute, + self.second, + self.millisecond * (100 * 100 * 100), + self.location, + ) +} + func (self *_dateObject) Time() tme.Time { return self.time }