1
0
mirror of https://github.com/robertkrimen/otto synced 2025-09-28 18:45:22 +08:00
otto/type_date.go
2012-10-07 22:54:39 -07:00

209 lines
4.2 KiB
Go

package otto
import (
tme "time"
"math"
"fmt"
)
type _dateObject struct {
time tme.Time // Time from the "time" package, a cached version of time
epoch float64
value Value
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
}
func (self *_dateObject) Epoch() float64 {
return self.epoch
}
func (self *_dateObject) Value() Value {
return self.value
}
func (self *_dateObject) SetNaN() {
self.time = tme.Time{}
self.epoch = math.NaN()
self.value = NaNValue()
self.isNaN = true
}
func (self *_dateObject) SetTime(time tme.Time) {
self.Set(timeToEpoch(time))
}
func (self *_dateObject) Set(epoch float64) {
// epoch
self.epoch = epoch
// time
time, err := epochToTime(epoch)
self.time = time // Is either a valid time, or the zero-value for time.Time
// value & isNaN
if err != nil {
self.isNaN = true
self.value = NaNValue()
} else {
self.value = toValue(epoch)
}
}
func epochToTime(value float64) (time tme.Time, err error) {
epochWithMilli := value
if math.IsNaN(epochWithMilli) || math.IsInf(epochWithMilli, 0) {
err = fmt.Errorf("Invalid time %v", value)
return
}
epoch := int64(epochWithMilli / 1000)
milli := int64(epochWithMilli) % 1000
time = tme.Unix(int64(epoch), milli * 1000000).UTC()
return
}
func timeToEpoch(time tme.Time) float64 {
return float64(time.Unix() * 1000 + int64(time.Nanosecond() / 1000000))
}
func (runtime *_runtime) newDateObject(epoch float64) *_object {
self := runtime.newObject()
self.Class = "Date"
// TODO Fix this, redundant arguments, etc.
self.Date = &_dateObject{}
self.Date.Set(epoch)
return self
}
func dateObjectOf(_dateObject *_object) *_dateObject {
if _dateObject == nil || _dateObject.Class != "Date" {
panic(newTypeError())
}
return _dateObject.Date
}
// JavaScript is 0-based, Go is 1-based (15.9.1.4)
func dateToGoMonth(month int) tme.Month {
return tme.Month(month + 1)
}
func dateFromGoMonth(month tme.Month) int {
return int(month) - 1
}
// Both JavaScript & Go are 0-based (Sunday == 0)
func dateToGoDay(day int) tme.Weekday {
return tme.Weekday(day)
}
func dateFromGoDay(day tme.Weekday) int {
return int(day)
}
func newDateTime(argumentList []Value) (epoch float64) {
pick := func(index int, default_ float64) (float64, bool) {
if index >= len(argumentList) {
return default_, false
}
value := toFloat(argumentList[index])
if math.IsNaN(value) || math.IsInf(value, 0) {
return 0, true
}
return value, false
}
if len(argumentList) >= 2 { // 2-argument, 3-argument, ...
var year, month, day, hours, minutes, seconds, ms float64
var invalid bool
if year, invalid = pick(0, 1900.0); invalid {
goto INVALID
}
if month, invalid = pick(1, 0.0); invalid {
goto INVALID
}
if day, invalid = pick(2, 1.0); invalid {
goto INVALID
}
if hours, invalid = pick(3, 0.0); invalid {
goto INVALID
}
if minutes, invalid = pick(4, 0.0); invalid {
goto INVALID
}
if seconds, invalid = pick(5, 0.0); invalid {
goto INVALID
}
if ms, invalid = pick(6, 0.0); invalid {
goto INVALID
}
if year >= 0 && year <= 99 {
year += 1900
}
time := tme.Date(int(year), dateToGoMonth(int(month)), int(day), int(hours), int(minutes), int(seconds), int(ms) * 1000000, tme.UTC)
return timeToEpoch(time)
} else if len(argumentList) == 0 { // 0-argument
time := tme.Now().UTC()
return timeToEpoch(time)
} else { // 1-argument
value := valueOfArrayIndex(argumentList, 0)
value = toPrimitive(value)
if value.IsString() {
// TODO Implement this
goto INVALID
}
return toFloat(value)
}
INVALID:
epoch = math.NaN()
return
}