You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
577 lines
16 KiB
577 lines
16 KiB
from ..base import *
|
|
from .time_helpers import *
|
|
|
|
TZ_OFFSET = (time.altzone // 3600)
|
|
ABS_OFFSET = abs(TZ_OFFSET)
|
|
TZ_NAME = time.tzname[1]
|
|
ISO_FORMAT = '%s-%s-%sT%s:%s:%s.%sZ'
|
|
|
|
|
|
@Js
|
|
def Date(year, month, date, hours, minutes, seconds, ms):
|
|
return now().to_string()
|
|
|
|
|
|
Date.Class = 'Date'
|
|
|
|
|
|
def now():
|
|
return PyJsDate(int(time.time() * 1000), prototype=DatePrototype)
|
|
|
|
|
|
@Js
|
|
def UTC(year, month, date, hours, minutes, seconds, ms): # todo complete this
|
|
args = arguments
|
|
y = args[0].to_number()
|
|
m = args[1].to_number()
|
|
l = len(args)
|
|
dt = args[2].to_number() if l > 2 else Js(1)
|
|
h = args[3].to_number() if l > 3 else Js(0)
|
|
mi = args[4].to_number() if l > 4 else Js(0)
|
|
sec = args[5].to_number() if l > 5 else Js(0)
|
|
mili = args[6].to_number() if l > 6 else Js(0)
|
|
if not y.is_nan() and 0 <= y.value <= 99:
|
|
y = y + Js(1900)
|
|
return TimeClip(MakeDate(MakeDay(y, m, dt), MakeTime(h, mi, sec, mili)))
|
|
|
|
|
|
@Js
|
|
def parse(string):
|
|
return PyJsDate(
|
|
TimeClip(parse_date(string.to_string().value)),
|
|
prototype=DatePrototype)
|
|
|
|
|
|
Date.define_own_property('now', {
|
|
'value': Js(now),
|
|
'enumerable': False,
|
|
'writable': True,
|
|
'configurable': True
|
|
})
|
|
|
|
Date.define_own_property('parse', {
|
|
'value': parse,
|
|
'enumerable': False,
|
|
'writable': True,
|
|
'configurable': True
|
|
})
|
|
|
|
Date.define_own_property('UTC', {
|
|
'value': UTC,
|
|
'enumerable': False,
|
|
'writable': True,
|
|
'configurable': True
|
|
})
|
|
|
|
|
|
class PyJsDate(PyJs):
|
|
Class = 'Date'
|
|
extensible = True
|
|
|
|
def __init__(self, value, prototype=None):
|
|
self.value = value
|
|
self.own = {}
|
|
self.prototype = prototype
|
|
|
|
# todo fix this problematic datetime part
|
|
def to_local_dt(self):
|
|
return datetime.datetime(1970, 1, 1) + datetime.timedelta(
|
|
seconds=UTCToLocal(self.value) // 1000)
|
|
|
|
def to_utc_dt(self):
|
|
return datetime.datetime(1970, 1, 1) + datetime.timedelta(
|
|
seconds=self.value // 1000)
|
|
|
|
def local_strftime(self, pattern):
|
|
if self.value is NaN:
|
|
return 'Invalid Date'
|
|
try:
|
|
dt = self.to_local_dt()
|
|
except:
|
|
raise MakeError(
|
|
'TypeError',
|
|
'unsupported date range. Will fix in future versions')
|
|
try:
|
|
return dt.strftime(pattern)
|
|
except:
|
|
raise MakeError(
|
|
'TypeError',
|
|
'Could not generate date string from this date (limitations of python.datetime)'
|
|
)
|
|
|
|
def utc_strftime(self, pattern):
|
|
if self.value is NaN:
|
|
return 'Invalid Date'
|
|
try:
|
|
dt = self.to_utc_dt()
|
|
except:
|
|
raise MakeError(
|
|
'TypeError',
|
|
'unsupported date range. Will fix in future versions')
|
|
try:
|
|
return dt.strftime(pattern)
|
|
except:
|
|
raise MakeError(
|
|
'TypeError',
|
|
'Could not generate date string from this date (limitations of python.datetime)'
|
|
)
|
|
|
|
|
|
def parse_date(py_string): # todo support all date string formats
|
|
date_formats = (
|
|
"%Y-%m-%d",
|
|
"%m/%d/%Y",
|
|
"%b %d %Y",
|
|
)
|
|
# Supports these hour formats and with or hour.
|
|
hour_formats = (
|
|
"T%H:%M:%S.%f",
|
|
"T%H:%M:%S",
|
|
) + ('',)
|
|
# Supports with or without Z indicator.
|
|
z_formats = ("Z",) + ('',)
|
|
supported_formats = [
|
|
d + t + z
|
|
for d in date_formats
|
|
for t in hour_formats
|
|
for z in z_formats
|
|
]
|
|
for date_format in supported_formats:
|
|
try:
|
|
dt = datetime.datetime.strptime(py_string, date_format)
|
|
except ValueError:
|
|
continue
|
|
else:
|
|
return MakeDate(
|
|
MakeDay(Js(dt.year), Js(dt.month - 1), Js(dt.day)),
|
|
MakeTime(
|
|
Js(dt.hour), Js(dt.minute), Js(dt.second),
|
|
Js(dt.microsecond // 1000)))
|
|
|
|
raise MakeError(
|
|
'TypeError',
|
|
'Could not parse date %s - unsupported date format. Currently only supported formats are RFC3339 utc, ISO Date, Short Date, and Long Date. Sorry!'
|
|
% py_string)
|
|
|
|
|
|
def date_constructor(*args):
|
|
if len(args) >= 2:
|
|
return date_constructor2(*args)
|
|
elif len(args) == 1:
|
|
return date_constructor1(args[0])
|
|
else:
|
|
return date_constructor0()
|
|
|
|
|
|
def date_constructor0():
|
|
return now()
|
|
|
|
|
|
def date_constructor1(value):
|
|
v = value.to_primitive()
|
|
if v._type() == 'String':
|
|
v = parse_date(v.value)
|
|
else:
|
|
v = v.to_int()
|
|
return PyJsDate(TimeClip(v), prototype=DatePrototype)
|
|
|
|
|
|
def date_constructor2(*args):
|
|
y = args[0].to_number()
|
|
m = args[1].to_number()
|
|
l = len(args)
|
|
dt = args[2].to_number() if l > 2 else Js(1)
|
|
h = args[3].to_number() if l > 3 else Js(0)
|
|
mi = args[4].to_number() if l > 4 else Js(0)
|
|
sec = args[5].to_number() if l > 5 else Js(0)
|
|
mili = args[6].to_number() if l > 6 else Js(0)
|
|
if not y.is_nan() and 0 <= y.value <= 99:
|
|
y = y + Js(1900)
|
|
t = TimeClip(
|
|
LocalToUTC(MakeDate(MakeDay(y, m, dt), MakeTime(h, mi, sec, mili))))
|
|
return PyJsDate(t, prototype=DatePrototype)
|
|
|
|
|
|
Date.create = date_constructor
|
|
|
|
DatePrototype = PyJsDate(float('nan'), prototype=ObjectPrototype)
|
|
|
|
|
|
def check_date(obj):
|
|
if obj.Class != 'Date':
|
|
raise MakeError('TypeError', 'this is not a Date object')
|
|
|
|
|
|
class DateProto:
|
|
def toString():
|
|
check_date(this)
|
|
if this.value is NaN:
|
|
return 'Invalid Date'
|
|
offset = (UTCToLocal(this.value) - this.value) // msPerHour
|
|
return this.local_strftime(
|
|
'%a %b %d %Y %H:%M:%S GMT') + '%s00 (%s)' % (pad(
|
|
offset, 2, True), GetTimeZoneName(this.value))
|
|
|
|
def toDateString():
|
|
check_date(this)
|
|
return this.local_strftime('%d %B %Y')
|
|
|
|
def toTimeString():
|
|
check_date(this)
|
|
return this.local_strftime('%H:%M:%S')
|
|
|
|
def toLocaleString():
|
|
check_date(this)
|
|
return this.local_strftime('%d %B %Y %H:%M:%S')
|
|
|
|
def toLocaleDateString():
|
|
check_date(this)
|
|
return this.local_strftime('%d %B %Y')
|
|
|
|
def toLocaleTimeString():
|
|
check_date(this)
|
|
return this.local_strftime('%H:%M:%S')
|
|
|
|
def valueOf():
|
|
check_date(this)
|
|
return this.value
|
|
|
|
def getTime():
|
|
check_date(this)
|
|
return this.value
|
|
|
|
def getFullYear():
|
|
check_date(this)
|
|
if this.value is NaN:
|
|
return NaN
|
|
return YearFromTime(UTCToLocal(this.value))
|
|
|
|
def getUTCFullYear():
|
|
check_date(this)
|
|
if this.value is NaN:
|
|
return NaN
|
|
return YearFromTime(this.value)
|
|
|
|
def getMonth():
|
|
check_date(this)
|
|
if this.value is NaN:
|
|
return NaN
|
|
return MonthFromTime(UTCToLocal(this.value))
|
|
|
|
def getDate():
|
|
check_date(this)
|
|
if this.value is NaN:
|
|
return NaN
|
|
return DateFromTime(UTCToLocal(this.value))
|
|
|
|
def getUTCMonth():
|
|
check_date(this)
|
|
if this.value is NaN:
|
|
return NaN
|
|
return MonthFromTime(this.value)
|
|
|
|
def getUTCDate():
|
|
check_date(this)
|
|
if this.value is NaN:
|
|
return NaN
|
|
return DateFromTime(this.value)
|
|
|
|
def getDay():
|
|
check_date(this)
|
|
if this.value is NaN:
|
|
return NaN
|
|
return WeekDay(UTCToLocal(this.value))
|
|
|
|
def getUTCDay():
|
|
check_date(this)
|
|
if this.value is NaN:
|
|
return NaN
|
|
return WeekDay(this.value)
|
|
|
|
def getHours():
|
|
check_date(this)
|
|
if this.value is NaN:
|
|
return NaN
|
|
return HourFromTime(UTCToLocal(this.value))
|
|
|
|
def getUTCHours():
|
|
check_date(this)
|
|
if this.value is NaN:
|
|
return NaN
|
|
return HourFromTime(this.value)
|
|
|
|
def getMinutes():
|
|
check_date(this)
|
|
if this.value is NaN:
|
|
return NaN
|
|
return MinFromTime(UTCToLocal(this.value))
|
|
|
|
def getUTCMinutes():
|
|
check_date(this)
|
|
if this.value is NaN:
|
|
return NaN
|
|
return MinFromTime(this.value)
|
|
|
|
def getSeconds():
|
|
check_date(this)
|
|
if this.value is NaN:
|
|
return NaN
|
|
return SecFromTime(UTCToLocal(this.value))
|
|
|
|
def getUTCSeconds():
|
|
check_date(this)
|
|
if this.value is NaN:
|
|
return NaN
|
|
return SecFromTime(this.value)
|
|
|
|
def getMilliseconds():
|
|
check_date(this)
|
|
if this.value is NaN:
|
|
return NaN
|
|
return msFromTime(UTCToLocal(this.value))
|
|
|
|
def getUTCMilliseconds():
|
|
check_date(this)
|
|
if this.value is NaN:
|
|
return NaN
|
|
return msFromTime(this.value)
|
|
|
|
def getTimezoneOffset():
|
|
check_date(this)
|
|
if this.value is NaN:
|
|
return NaN
|
|
return (this.value - UTCToLocal(this.value)) // 60000
|
|
|
|
def setTime(time):
|
|
check_date(this)
|
|
this.value = TimeClip(time.to_number().to_int())
|
|
return this.value
|
|
|
|
def setMilliseconds(ms):
|
|
check_date(this)
|
|
t = UTCToLocal(this.value)
|
|
tim = MakeTime(
|
|
Js(HourFromTime(t)), Js(MinFromTime(t)), Js(SecFromTime(t)), ms)
|
|
u = TimeClip(LocalToUTC(MakeDate(Day(t), tim)))
|
|
this.value = u
|
|
return u
|
|
|
|
def setUTCMilliseconds(ms):
|
|
check_date(this)
|
|
t = this.value
|
|
tim = MakeTime(
|
|
Js(HourFromTime(t)), Js(MinFromTime(t)), Js(SecFromTime(t)), ms)
|
|
u = TimeClip(MakeDate(Day(t), tim))
|
|
this.value = u
|
|
return u
|
|
|
|
def setSeconds(sec, ms=None):
|
|
check_date(this)
|
|
t = UTCToLocal(this.value)
|
|
s = sec.to_number()
|
|
if not ms is None: milli = Js(msFromTime(t))
|
|
else: milli = ms.to_number()
|
|
date = MakeDate(
|
|
Day(t), MakeTime(Js(HourFromTime(t)), Js(MinFromTime(t)), s, milli))
|
|
u = TimeClip(LocalToUTC(date))
|
|
this.value = u
|
|
return u
|
|
|
|
def setUTCSeconds(sec, ms=None):
|
|
check_date(this)
|
|
t = this.value
|
|
s = sec.to_number()
|
|
if not ms is None: milli = Js(msFromTime(t))
|
|
else: milli = ms.to_number()
|
|
date = MakeDate(
|
|
Day(t), MakeTime(Js(HourFromTime(t)), Js(MinFromTime(t)), s, milli))
|
|
v = TimeClip(date)
|
|
this.value = v
|
|
return v
|
|
|
|
def setMinutes(min, sec=None, ms=None):
|
|
check_date(this)
|
|
t = UTCToLocal(this.value)
|
|
m = min.to_number()
|
|
if not sec is None: s = Js(SecFromTime(t))
|
|
else: s = sec.to_number()
|
|
if not ms is None: milli = Js(msFromTime(t))
|
|
else: milli = ms.to_number()
|
|
date = MakeDate(Day(t), MakeTime(Js(HourFromTime(t)), m, s, milli))
|
|
u = TimeClip(LocalToUTC(date))
|
|
this.value = u
|
|
return u
|
|
|
|
def setUTCMinutes(min, sec=None, ms=None):
|
|
check_date(this)
|
|
t = this.value
|
|
m = min.to_number()
|
|
if not sec is None: s = Js(SecFromTime(t))
|
|
else: s = sec.to_number()
|
|
if not ms is None: milli = Js(msFromTime(t))
|
|
else: milli = ms.to_number()
|
|
date = MakeDate(Day(t), MakeTime(Js(HourFromTime(t)), m, s, milli))
|
|
v = TimeClip(date)
|
|
this.value = v
|
|
return v
|
|
|
|
def setHours(hour, min=None, sec=None, ms=None):
|
|
check_date(this)
|
|
t = UTCToLocal(this.value)
|
|
h = hour.to_number()
|
|
if not min is None: m = Js(MinFromTime(t))
|
|
else: m = min.to_number()
|
|
if not sec is None: s = Js(SecFromTime(t))
|
|
else: s = sec.to_number()
|
|
if not ms is None: milli = Js(msFromTime(t))
|
|
else: milli = ms.to_number()
|
|
date = MakeDate(Day(t), MakeTime(h, m, s, milli))
|
|
u = TimeClip(LocalToUTC(date))
|
|
this.value = u
|
|
return u
|
|
|
|
def setUTCHours(hour, min=None, sec=None, ms=None):
|
|
check_date(this)
|
|
t = this.value
|
|
h = hour.to_number()
|
|
if not min is None: m = Js(MinFromTime(t))
|
|
else: m = min.to_number()
|
|
if not sec is None: s = Js(SecFromTime(t))
|
|
else: s = sec.to_number()
|
|
if not ms is None: milli = Js(msFromTime(t))
|
|
else: milli = ms.to_number()
|
|
date = MakeDate(Day(t), MakeTime(h, m, s, milli))
|
|
v = TimeClip(date)
|
|
this.value = v
|
|
return v
|
|
|
|
def setDate(date):
|
|
check_date(this)
|
|
t = UTCToLocal(this.value)
|
|
dt = date.to_number()
|
|
newDate = MakeDate(
|
|
MakeDay(Js(YearFromTime(t)), Js(MonthFromTime(t)), dt), TimeWithinDay(t))
|
|
u = TimeClip(LocalToUTC(newDate))
|
|
this.value = u
|
|
return u
|
|
|
|
def setUTCDate(date):
|
|
check_date(this)
|
|
t = this.value
|
|
dt = date.to_number()
|
|
newDate = MakeDate(
|
|
MakeDay(Js(YearFromTime(t)), Js(MonthFromTime(t)), dt), TimeWithinDay(t))
|
|
v = TimeClip(newDate)
|
|
this.value = v
|
|
return v
|
|
|
|
def setMonth(month, date=None):
|
|
check_date(this)
|
|
t = UTCToLocal(this.value)
|
|
m = month.to_number()
|
|
if not date is None: dt = Js(DateFromTime(t))
|
|
else: dt = date.to_number()
|
|
newDate = MakeDate(
|
|
MakeDay(Js(YearFromTime(t)), m, dt), TimeWithinDay(t))
|
|
u = TimeClip(LocalToUTC(newDate))
|
|
this.value = u
|
|
return u
|
|
|
|
def setUTCMonth(month, date=None):
|
|
check_date(this)
|
|
t = this.value
|
|
m = month.to_number()
|
|
if not date is None: dt = Js(DateFromTime(t))
|
|
else: dt = date.to_number()
|
|
newDate = MakeDate(
|
|
MakeDay(Js(YearFromTime(t)), m, dt), TimeWithinDay(t))
|
|
v = TimeClip(newDate)
|
|
this.value = v
|
|
return v
|
|
|
|
def setFullYear(year, month=None, date=None):
|
|
check_date(this)
|
|
if not this.value is NaN: t = UTCToLocal(this.value)
|
|
else: t = 0
|
|
y = year.to_number()
|
|
if not month is None: m = Js(MonthFromTime(t))
|
|
else: m = month.to_number()
|
|
if not date is None: dt = Js(DateFromTime(t))
|
|
else: dt = date.to_number()
|
|
newDate = MakeDate(
|
|
MakeDay(y, m, dt), TimeWithinDay(t))
|
|
u = TimeClip(LocalToUTC(newDate))
|
|
this.value = u
|
|
return u
|
|
|
|
def setUTCFullYear(year, month=None, date=None):
|
|
check_date(this)
|
|
if not this.value is NaN: t = UTCToLocal(this.value)
|
|
else: t = 0
|
|
y = year.to_number()
|
|
if not month is None: m = Js(MonthFromTime(t))
|
|
else: m = month.to_number()
|
|
if not date is None: dt = Js(DateFromTime(t))
|
|
else: dt = date.to_number()
|
|
newDate = MakeDate(
|
|
MakeDay(y, m, dt), TimeWithinDay(t))
|
|
v = TimeClip(newDate)
|
|
this.value = v
|
|
return v
|
|
|
|
def toUTCString():
|
|
check_date(this)
|
|
return this.utc_strftime('%d %B %Y %H:%M:%S')
|
|
|
|
def toISOString():
|
|
check_date(this)
|
|
t = this.value
|
|
year = YearFromTime(t)
|
|
month, day, hour, minute, second, milli = pad(
|
|
MonthFromTime(t) + 1), pad(DateFromTime(t)), pad(
|
|
HourFromTime(t)), pad(MinFromTime(t)), pad(
|
|
SecFromTime(t)), pad(msFromTime(t))
|
|
return ISO_FORMAT % (unicode(year) if 0 <= year <= 9999 else pad(
|
|
year, 6, True), month, day, hour, minute, second, milli)
|
|
|
|
def toJSON(key):
|
|
o = this.to_object()
|
|
tv = o.to_primitive('Number')
|
|
if tv.Class == 'Number' and not tv.is_finite():
|
|
return this.null
|
|
toISO = o.get('toISOString')
|
|
if not toISO.is_callable():
|
|
raise this.MakeError('TypeError', 'toISOString is not callable')
|
|
return toISO.call(o, ())
|
|
|
|
|
|
def pad(num, n=2, sign=False):
|
|
'''returns n digit string representation of the num'''
|
|
s = unicode(abs(num))
|
|
if len(s) < n:
|
|
s = '0' * (n - len(s)) + s
|
|
if not sign:
|
|
return s
|
|
if num >= 0:
|
|
return '+' + s
|
|
else:
|
|
return '-' + s
|
|
|
|
|
|
fill_prototype(DatePrototype, DateProto, default_attrs)
|
|
|
|
Date.define_own_property(
|
|
'prototype', {
|
|
'value': DatePrototype,
|
|
'enumerable': False,
|
|
'writable': False,
|
|
'configurable': False
|
|
})
|
|
|
|
DatePrototype.define_own_property('constructor', {
|
|
'value': Date,
|
|
'enumerable': False,
|
|
'writable': True,
|
|
'configurable': True
|
|
})
|