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  }