Author: Stephan <step...@stzal.com>
Branch: 
Changeset: r358:0eca2e45608b
Date: 2013-02-19 13:02 +0100
http://bitbucket.org/pypy/lang-js/changeset/0eca2e45608b/

Log:    added translatable date and time functions

diff --git a/js/builtins/date.py b/js/builtins/date.py
--- a/js/builtins/date.py
+++ b/js/builtins/date.py
@@ -1,9 +1,16 @@
 from rpython.rlib.rfloat import NAN, isnan
-from rpython.rlib.objectmodel import we_are_translated
 
-import datetime
 from js.builtins import get_arg
-from js.object_space import w_return, hide_on_translate, _w
+from js.object_space import w_return, _w
+from js import rtime
+
+fMSEC = 1
+fSEC = 2
+fMIN = 3
+fHOUR = 4
+fDAY = 1
+fMONTH = 2
+fYEAR = 3
 
 
 def setup(global_object):
@@ -103,14 +110,9 @@
 
 @w_return
 def to_string(this, args):
-    if not we_are_translated():
-        d = w_date_to_datetime(this)
-        local = to_local(d)
-
-        s = local.strftime('%a %b %d %Y %H:%M:%S GMT%z (%Z)')
-        return s
-
-    return this.PrimitiveValue().to_string()
+    t = make_jstime(this)
+    s = t.strftime('%a %b %d %Y %H:%M:%S GMT%z (%Z)', local=True)
+    return s
 
 
 # 15.9.5.8
@@ -127,146 +129,121 @@
 
 # 15.9.5.10
 @w_return
-@hide_on_translate(0)
 def get_full_year(this, args):
-    d = w_date_to_datetime(this)
-    local = to_local(d)
-    return local.year
+    t = make_jstime(this)
+    return t.year(local=True)
 
 
 # 15.9.5.11
 @w_return
-@hide_on_translate(0)
 def get_utc_full_year(this, args):
-    d = w_date_to_datetime(this)
-    return d.year
+    t = make_jstime(this)
+    return t.year()
 
 
 # 15.9.5.12
 @w_return
-@hide_on_translate(0)
 def get_month(this, args):
-    d = w_date_to_datetime(this)
-    local = to_local(d)
-    return local.month
+    t = make_jstime(this)
+    return t.month(local=True)
 
 
 # 15.9.5.13
 @w_return
-@hide_on_translate(0)
 def get_utc_month(this, args):
-    d = w_date_to_datetime(this)
-    return d.day
+    t = make_jstime(this)
+    return t.month()
 
 
 # 15.9.5.14
 @w_return
-@hide_on_translate(0)
 def get_date(this, args):
-    d = w_date_to_datetime(this)
-    local = to_local(d)
-    return local.day
+    t = make_jstime(this)
+    return t.day(local=True)
 
 
 # 15.9.5.15
 @w_return
-@hide_on_translate(0)
 def get_utc_date(this, args):
-    d = w_date_to_datetime(this)
-    return d.day
+    t = make_jstime(this)
+    return t.day()
 
 
 # 15.9.5.16
 @w_return
-@hide_on_translate(0)
 def get_day(this, args):
-    d = w_date_to_datetime(this)
-    local = to_local(d)
-    return local.weekday()
+    t = make_jstime(this)
+    return t.wday(local=True)
 
 
 # 15.9.5.17
 @w_return
-@hide_on_translate(0)
 def get_utc_day(this, args):
-    d = w_date_to_datetime(this)
-    return d.weekday()
+    t = make_jstime(this)
+    return t.wday()
 
 
 # 15.9.5.18
 @w_return
-@hide_on_translate(0)
 def get_hours(this, args):
-    d = w_date_to_datetime(this)
-    local = to_local(d)
-    return local.hour
+    t = make_jstime(this)
+    return t.hour(local=True)
 
 
 # 15.9.5.19
 @w_return
-@hide_on_translate(0)
 def get_utc_hours(this, args):
-    d = w_date_to_datetime(this)
-    return d.hour
+    t = make_jstime(this)
+    return t.hour()
 
 
 # 15.9.5.20
 @w_return
-@hide_on_translate(0)
 def get_minutes(this, args):
-    d = w_date_to_datetime(this)
-    local = to_local(d)
-    return local.minute
+    t = make_jstime(this)
+    return t.min(local=True)
 
 
 # 15.9.5.21
 @w_return
-@hide_on_translate(0)
 def get_utc_minutes(this, args):
-    d = w_date_to_datetime(this)
-    return d.minute
+    t = make_jstime(this)
+    return t.min()
 
 
 # 15.9.5.22
 @w_return
-@hide_on_translate(0)
 def get_seconds(this, args):
-    d = w_date_to_datetime(this)
-    local = to_local(d)
-    return local.second
+    t = make_jstime(this)
+    return t.sec(local=True)
 
 
 # 15.9.5.23
 @w_return
-@hide_on_translate(0)
 def get_utc_seconds(this, args):
-    d = w_date_to_datetime(this)
-    return d.second
+    t = make_jstime(this)
+    return t.sec()
 
 
 # 15.9.5.24
 @w_return
-@hide_on_translate(0)
 def get_milliseconds(this, args):
-    d = w_date_to_datetime(this)
-    local = to_local(d)
-    return local.microsecond / 1000
+    t = make_jstime(this)
+    return t.msec(local=True)
 
 
 # 15.9.5.25
 @w_return
-@hide_on_translate(0)
 def get_utc_milliseconds(this, args):
-    d = w_date_to_datetime(this)
-    return d.microsecond / 1000
+    t = make_jstime(this)
+    return t.msec()
 
 
 # 15.9.5.26
 @w_return
-@hide_on_translate(0)
 def get_timezone_offset(this, args):
-    d = w_date_to_datetime(this)
-    offset = -1 * (d.utcoffset().total_seconds() / 60)
+    t = make_jstime(this)
+    offset = -1 * t.utc_offset() / 60
     return offset
 
 
@@ -290,154 +267,137 @@
 
 # 15.9.5.28
 @w_return
-@hide_on_translate(0)
 def set_milliseconds(this, args):
-    time_args = to_timeargs(args, 1)
-    return set_datetime(this, time_args)
+    time_args = to_timeargs(args, fMSEC)
+    return change_wdate(this, time_args, local=True)
 
 
 # 15.9.5.29
 @w_return
-@hide_on_translate(0)
 def set_utc_milliseconds(this, args):
-    time_args = to_timeargs(args, 1)
-    return set_utc_datetime(this, time_args)
+    time_args = to_timeargs(args, fMSEC)
+    return change_wdate(this, time_args)
 
 
 # 15.9.5.30
 @w_return
-@hide_on_translate(0)
 def set_seconds(this, args):
-    time_args = to_timeargs(args, 2)
-    return set_datetime(this, time_args)
+    time_args = to_timeargs(args, fSEC)
+    return change_wdate(this, time_args, local=True)
 
 
 # 15.9.5.30
 @w_return
-@hide_on_translate(0)
 def set_utc_seconds(this, args):
-    time_args = to_timeargs(args, 2)
-    return set_utc_datetime(this, time_args)
+    time_args = to_timeargs(args, fSEC)
+    return change_wdate(this, time_args)
 
 
 # 15.9.5.32
 @w_return
-@hide_on_translate(0)
 def set_minutes(this, args):
-    time_args = to_timeargs(args, 3)
-    return set_datetime(this, time_args)
+    time_args = to_timeargs(args, fMIN)
+    return change_wdate(this, time_args, local=True)
 
 
 # 15.9.5.33
 @w_return
-@hide_on_translate(0)
 def set_utc_minutes(this, args):
-    time_args = to_timeargs(args, 3)
-    return set_utc_datetime(this, time_args)
+    time_args = to_timeargs(args, fMIN)
+    return change_wdate(this, time_args)
 
 
 # 15.9.5.34
 @w_return
-@hide_on_translate(0)
 def set_hours(this, args):
-    time_args = to_timeargs(args, 4)
-    return set_datetime(this, time_args)
+    time_args = to_timeargs(args, fHOUR)
+    return change_wdate(this, time_args, local=True)
 
 
 # 15.9.5.35
 @w_return
-@hide_on_translate(0)
 def set_utc_hours(this, args):
-    time_args = to_timeargs(args, 4)
-    return set_utc_datetime(this, time_args)
+    time_args = to_timeargs(args, fHOUR)
+    return change_wdate(this, time_args)
 
 
 # 15.9.5.36
 @w_return
-@hide_on_translate(0)
 def set_date(this, args):
-    date_args = to_dateargs(args, 1)
-    return set_datetime(this, date_args)
+    date_args = to_dateargs(args, fDAY)
+    return change_wdate(this, date_args, local=True)
 
 
 # 15.9.5.37
 @w_return
-@hide_on_translate(0)
 def set_utc_date(this, args):
-    date_args = to_dateargs(args, 1)
-    return set_utc_datetime(this, date_args)
+    date_args = to_dateargs(args, fDAY)
+    return change_wdate(this, date_args)
 
 
 # 15.9.5.38
 @w_return
-@hide_on_translate(0)
 def set_month(this, args):
-    date_args = to_dateargs(args, 2)
-    return set_datetime(this, date_args)
+    date_args = to_dateargs(args, fMONTH)
+    return change_wdate(this, date_args, local=True)
 
 
 # 15.9.5.39
 @w_return
-@hide_on_translate(0)
 def set_utc_month(this, args):
-    date_args = to_dateargs(args, 2)
-    return set_utc_datetime(this, date_args)
+    date_args = to_dateargs(args, fMONTH)
+    return change_wdate(this, date_args)
 
 
 # 15.9.5.38
 @w_return
-@hide_on_translate(0)
 def set_full_year(this, args):
-    date_args = to_dateargs(args, 3)
-    return set_datetime(this, date_args)
+    date_args = to_dateargs(args, fYEAR)
+    return change_wdate(this, date_args, local=True)
 
 
 # 15.9.5.39
 @w_return
-@hide_on_translate(0)
 def set_utc_full_year(this, args):
-    date_args = to_dateargs(args, 3)
-    return set_utc_datetime(this, date_args)
+    date_args = to_dateargs(args, fYEAR)
+    return change_wdate(this, date_args)
 
 
 # B.2.4
 @w_return
-@hide_on_translate(0)
 def get_year(this, args):
-    d = w_date_to_datetime(this)
-    local = to_local(d)
-    y = local.year - 1900
+    t = make_jstime(this)
+    y = t.year(local=True) - 1900
     return y
 
 
 # B.2.5
 @w_return
-@hide_on_translate(0)
 def set_year(this, args):
     arg0 = get_arg(args, 0)
     year = arg0.ToInteger()
 
     if isnan(year) or year < 0 or year > 99:
-        this.set_primitive_value(NAN)
+        this.set_primitive_value(_w(NAN))
         return NAN
 
     y = year + 1900
-
-    return set_datetime(this, [y])
+    c = JsDateChange()
+    c.set_year(y)
+    change_wdate(this, c)
+    return y
 
 
 # 15.9.5.42
 @w_return
-@hide_on_translate(0)
 def to_utc_string(this, args):
-    d = w_date_to_datetime(this)
-    s = d.strftime('%c %z')
+    t = make_jstime(this)
+    s = t.strftime('%c %z')
     return s
 
 
 # B.2.6
 @w_return
-@hide_on_translate(0)
 def to_gmt_string(this, args):
     return to_utc_string(this, args)
 
@@ -456,105 +416,247 @@
 ####### helper
 
 
-def to_timeargs(args, count):
-    a = argv(args)
-    rfilled = rfill_args(a, count)
-    lfilled = lfill_args(rfilled, 7)
-    return lfilled
+def to_timeargs(args, fill):
+    a = w_argi(args)
+    c = JsDateChange()
+    ac = len(a)
 
+    if fill == fMSEC:
+        c.set_msecond(a[0])
+    elif fill == fSEC:
+        c.set_second(a[0])
+        if ac > 1:
+            c.set_msecond(a[1])
+    elif fill == fMIN:
+        c.set_minute(a[0])
+        if ac > 1:
+            c.set_second(a[1])
+        if ac > 2:
+            c.set_msecond(a[2])
+    elif fill == fHOUR:
+        c.set_hour(a[0])
+        if ac > 1:
+            c.set_minute(a[1])
+        if ac > 2:
+            c.set_second(a[2])
+        if ac > 3:
+            c.set_msecond(a[3])
 
-def to_dateargs(args, count):
-    a = argv(args)
-    rfilled = rfill_args(a, count)
-    lfilled = lfill_args(rfilled, 3)
-    return lfilled
+    return c
 
 
-def set_datetime(this, args):
-    d = w_date_to_datetime(this)
-    local = to_local(d)
-    new_d = change_datetime(local, *args)
+def to_dateargs(args, fill):
+    a = w_argi(args)
+    c = JsDateChange()
+    ac = len(a)
 
-    u = datetime_to_msecs(new_d)
-    this.set_primitive_value(u)
+    if fill == fDAY:
+        c.set_day(a[0])
+    elif fill == fMONTH:
+        c.set_month(a[0])
+        if ac > 1:
+            c.set_day(a[1])
+    elif fill == fYEAR:
+        c.year = a[0]
+        if ac > 1:
+            c.set_month(a[1])
+        if ac > 2:
+            c.set_day(a[2])
 
-    return u
+    return c
 
 
-def set_utc_datetime(this, args):
-    d = w_date_to_datetime(this)
-    new_d = change_datetime(d, *args)
+class JsDateChange(object):
+    year = 0
+    has_year = False
+    month = 0
+    has_month = False
+    day = 0
+    has_day = False
+    hour = 0
+    has_hour = False
+    minute = 0
+    has_minute = False
+    second = 0
+    has_second = False
+    msecond = 0
+    has_msecond = False
 
-    u = datetime_to_msecs(new_d)
-    this.set_primitive_value(u)
+    def set_year(self, year):
+        self.has_year = True
+        self.year = year
 
-    return u
+    def set_month(self, month):
+        self.has_month = True
+        self.month = month
 
+    def set_day(self, day):
+        self.has_day = True
+        self.day = day
 
-def argv(args):
-    return [arg.ToInteger() for arg in args]
+    def set_hour(self, hour):
+        self.has_hour = True
+        self.hour = hour
 
+    def set_minute(self, minute):
+        self.has_minute = True
+        self.minute = minute
 
-def lfill_args(args, count):
-    if count > 0:
-        missing = count - len(args)
-        return ([None] * missing) + args
-    return args
+    def set_second(self, second):
+        self.has_second = True
+        self.second = second
 
+    def set_msecond(self, msecond):
+        self.has_msecond = True
+        self.msecond = msecond
 
-def rfill_args(args, count):
-    if count > 0:
-        missing = count - len(args)
-        return args + ([None] * missing)
 
-    return args
+def change_wdate(w_date, time_change, local=False):
+    t = make_jstime(w_date)
 
+    if time_change.has_year:
+        t.set_year(time_change.year, local)
 
-def change_datetime(d, year=None, month=None, day=None, hour=None, 
minute=None, second=None, ms=None):
-    args = {}
-    if year is not None:
-        args['year'] = year
-    if month is not None:
-        args['month'] = month
-    if day is not None:
-        args['day'] = day
-    if hour is not None:
-        args['hour'] = hour
-    if minute is not None:
-        args['minute'] = minute
-    if second is not None:
-        args['second'] = second
-    if ms is not None:
-        mu_sec = ms * 1000
-        args['microsecond'] = mu_sec
-    return d.replace(**args)
+    if time_change.has_month:
+        t.set_month(time_change.month, local)
 
+    if time_change.has_day:
+        t.set_day(time_change.day, local)
 
-def w_date_to_datetime(w_date):
-    msecs = w_date.PrimitiveValue().ToInteger()
-    return msecs_to_datetime(msecs)
+    if time_change.has_hour:
+        t.set_hour(time_change.hour, local)
 
+    if time_change.has_minute:
+        t.set_min(time_change.minute, local)
 
-def msecs_to_datetime(timestamp_msecs):
-    from dateutil.tz import tzutc
+    if time_change.has_second:
+        t.set_sec(time_change.second, local)
 
-    seconds_since_epoch = timestamp_msecs / 1000
-    msecs = timestamp_msecs - seconds_since_epoch * 1000
-    timestamp = seconds_since_epoch + (msecs / 1000.0)
-    utc = datetime.datetime.utcfromtimestamp(timestamp)
-    utc = utc.replace(tzinfo=tzutc())
+    if time_change.has_msecond:
+        t.set_msec(time_change.msecond, local)
 
-    return utc
+    w_t = _w(t.to_msec_epoc())
+    w_date.set_primitive_value(w_t)
 
+    return w_t
 
-def datetime_to_msecs(d):
-    from time import mktime
-    timestamp = int(mktime(d.utctimetuple()))
-    msecs = timestamp * 1000
-    msecs += (d.microsecond / 1000)
-    return msecs
 
+def w_argi(args):
+    argi = []
+    for arg in args:
+        a = arg.ToInteger()
+        assert isinstance(a, int)
+        argi += [a]
+    return argi
 
-def to_local(datetime):
-    from dateutil.tz import tzlocal
-    return datetime.astimezone(tzlocal())
+
+def _change_tuple(t, idx, value):
+    assert len(t) == 9
+    l = list(t)
+    l[idx] = value
+    return (l[0], l[1], l[2], l[3], l[4], l[5], l[6], l[7], l[8])
+
+
+def _get_tuple_at(t, idx):
+    l = list(t)
+    return l[idx]
+
+
+class JsTime(object):
+    def __init__(self, msec_timestamp):
+        self._timep = msec_timestamp / 1000
+        self._msec = msec_timestamp - self._timep * 1000
+
+    def __str__(self):
+        return 'JsTime(%d)' % (self.to_msec_epoc(), )
+
+    def _get_time(self, local):
+        if local:
+            return self.localtime()
+        return self.gmtime()
+
+    def gmtime(self):
+        return rtime.gmtime(self._timep)
+
+    def localtime(self):
+        return rtime.localtime(self._timep)
+
+    def _set_time(self, tm, local):
+        if local:
+            self._timep = int(rtime.mktime(tm))
+        else:
+            self._timep = int(rtime.timegm(tm))
+
+    def _update_time(self, component, value, local):
+        tm = self._get_time(local)
+        new_tm = _change_tuple(tm, component, value)
+        self._set_time(new_tm, local)
+
+    def _get_time_component(self, component, local):
+        return _get_tuple_at(self._get_time(local), component)
+
+    def _get_timestamp(self):
+        return self._timep
+
+    def to_msec_epoc(self):
+        return (self._get_timestamp() * 1000) + (self.msec())
+
+    def year(self, local=False):
+        return self._get_time_component(rtime.tmYEAR, local)
+
+    def set_year(self, year, local=False):
+        self._update_time(rtime.tmYEAR, year, local)
+
+    def month(self, local=False):
+        return self._get_time_component(rtime.tmMONTH, local)
+
+    def set_month(self, month, local=False):
+        self._update_time(rtime.tmMONTH, month, local)
+
+    def day(self, local=False):
+        return self._get_time_component(rtime.tmDAY, local)
+
+    def set_day(self, day, local=False):
+        self._update_time(rtime.tmDAY, day, local)
+
+    def hour(self, local=False):
+        return self._get_time_component(rtime.tmHOUR, local)
+
+    def set_hour(self, hour, local=False):
+        self._update_time(rtime.tmHOUR, hour, local)
+
+    def min(self, local=False):
+        return self._get_time_component(rtime.tmMIN, local)
+
+    def set_min(self, min, local=False):
+        self._update_time(rtime.tmMIN, min, local)
+
+    def sec(self, local=False):
+        return self._get_time_component(rtime.tmSEC, local)
+
+    def set_sec(self, sec, local=False):
+        self._update_time(rtime.tmSEC, sec, local)
+
+    def msec(self, local=False):
+        return self._msec
+
+    def set_msec(self, msec, local=False):
+        assert msec < 1000
+        self._msec = msec
+
+    def wday(self, local=False):
+        return self._get_time_component(rtime.tmWDAY, local)
+
+    def strftime(self, format, local=False):
+        tm = self._get_time(local)
+        s = rtime.strftime(format, tm)
+        return s
+
+    def utc_offset(self):
+        o = rtime.mktime(self.localtime()) - rtime.mktime(self.gmtime())
+        return o
+
+
+def make_jstime(w_obj):
+    msecs = w_obj.PrimitiveValue().ToInteger()
+    return JsTime(msecs)
diff --git a/js/rtime.py b/js/rtime.py
new file mode 100644
--- /dev/null
+++ b/js/rtime.py
@@ -0,0 +1,187 @@
+# see pypy/module/rctime/interp_time.py
+import os
+
+from rpython.rtyper.lltypesystem import rffi, lltype
+from rpython.rlib.rarithmetic import intmask
+from pypy.module.rctime.interp_time import c_gmtime, c_localtime, c_mktime, 
glob_buf, _POSIX, _CYGWIN, _WIN, c_tzset, c_strftime
+
+tmYEAR = 0
+tmMONTH = 1
+tmDAY = 2
+tmHOUR = 3
+tmMIN = 4
+tmSEC = 5
+tmWDAY = 6
+
+
+def _tm_to_tuple(t):
+    time_tuple = (
+        rffi.getintfield(t, 'c_tm_year') + 1900,
+        rffi.getintfield(t, 'c_tm_mon') + 1,  # want january == 1
+        rffi.getintfield(t, 'c_tm_mday'),
+        rffi.getintfield(t, 'c_tm_hour'),
+        rffi.getintfield(t, 'c_tm_min'),
+        rffi.getintfield(t, 'c_tm_sec'),
+        ((rffi.getintfield(t, 'c_tm_wday') + 6) % 7),  # want monday == 0
+        rffi.getintfield(t, 'c_tm_yday') + 1,  # want january, 1 == 1
+        rffi.getintfield(t, 'c_tm_isdst'))
+    return time_tuple
+
+
+def _gettmarg(tup):
+    if len(tup) != 9:
+        raise Exception("argument must be sequence of length 9, not %d", 
len(tup))
+
+    y = tup[0]
+    tm_mon = tup[1]
+    if tm_mon == 0:
+        tm_mon = 1
+    tm_mday = tup[2]
+    if tm_mday == 0:
+        tm_mday = 1
+    tm_yday = tup[7]
+    if tm_yday == 0:
+        tm_yday = 1
+    rffi.setintfield(glob_buf, 'c_tm_mon', tm_mon)
+    rffi.setintfield(glob_buf, 'c_tm_mday', tm_mday)
+    rffi.setintfield(glob_buf, 'c_tm_hour', tup[3])
+    rffi.setintfield(glob_buf, 'c_tm_min', tup[4])
+    rffi.setintfield(glob_buf, 'c_tm_sec', tup[5])
+    rffi.setintfield(glob_buf, 'c_tm_wday', tup[6])
+    rffi.setintfield(glob_buf, 'c_tm_yday', tm_yday)
+    rffi.setintfield(glob_buf, 'c_tm_isdst', tup[8])
+    if _POSIX:
+        if _CYGWIN:
+            pass
+        else:
+            # actually never happens, but makes annotator happy
+            glob_buf.c_tm_zone = lltype.nullptr(rffi.CCHARP.TO)
+            rffi.setintfield(glob_buf, 'c_tm_gmtoff', 0)
+
+    if y < 1900:
+        if 69 <= y <= 99:
+            y += 1900
+        elif 0 <= y <= 68:
+            y += 2000
+        else:
+            raise Exception("year out of range")
+
+    # tm_wday does not need checking of its upper-bound since taking "%
+    #  7" in gettmarg() automatically restricts the range.
+    if rffi.getintfield(glob_buf, 'c_tm_wday') < -1:
+        raise Exception("day of week out of range")
+
+    rffi.setintfield(glob_buf, 'c_tm_year', y - 1900)
+    rffi.setintfield(glob_buf, 'c_tm_mon', rffi.getintfield(glob_buf, 
'c_tm_mon') - 1)
+    rffi.setintfield(glob_buf, 'c_tm_wday', (rffi.getintfield(glob_buf, 
'c_tm_wday') + 1) % 7)
+    rffi.setintfield(glob_buf, 'c_tm_yday', rffi.getintfield(glob_buf, 
'c_tm_yday') - 1)
+
+    return glob_buf
+
+
+def gmtime(time_t):
+    seconds = time_t
+    t_ref = lltype.malloc(rffi.TIME_TP.TO, 1, flavor='raw')
+    t_ref[0] = seconds
+    p = c_gmtime(t_ref)
+    lltype.free(t_ref, flavor='raw')
+    return _tm_to_tuple(p)
+
+
+def localtime(time_t):
+    seconds = time_t
+    t_ref = lltype.malloc(rffi.TIME_TP.TO, 1, flavor='raw')
+    t_ref[0] = seconds
+    p = c_localtime(t_ref)
+    lltype.free(t_ref, flavor='raw')
+    return _tm_to_tuple(p)
+
+
+def mktime(tup):
+    buf = _gettmarg(tup)
+    rffi.setintfield(buf, "c_tm_wday", -1)
+    tt = c_mktime(buf)
+    if tt == -1 and rffi.getintfield(buf, "c_tm_wday") == -1:
+        raise Exception('mktime argument out of range')
+
+    return float(tt)
+
+
+def tzset():
+    c_tzset()
+
+
+def timegm(tup):
+    tz = os.environ.get('TZ')
+    os.environ['TZ'] = ''
+    tzset()
+
+    try:
+        tt = mktime(tup)
+    finally:
+        if tz:
+            os.environ['TZ'] = tz
+        else:
+            del os.environ['TZ']
+        tzset()
+
+    return tt
+
+
+def strftime(format, time_t):
+    """strftime(format[, tuple]) -> string
+
+    Convert a time tuple to a string according to a format specification.
+    See the library reference manual for formatting codes. When the time tuple
+    is not present, current time as returned by localtime() is used."""
+    buf_value = _gettmarg(time_t)
+
+    # Checks added to make sure strftime() does not crash Python by
+    # indexing blindly into some array for a textual representation
+    # by some bad index (fixes bug #897625).
+    # No check for year since handled in gettmarg().
+    if rffi.getintfield(buf_value, 'c_tm_mon') < 0 or 
rffi.getintfield(buf_value, 'c_tm_mon') > 11:
+        raise Exception("month out of range")
+    if rffi.getintfield(buf_value, 'c_tm_mday') < 1 or 
rffi.getintfield(buf_value, 'c_tm_mday') > 31:
+        raise Exception("day of month out of range")
+    if rffi.getintfield(buf_value, 'c_tm_hour') < 0 or 
rffi.getintfield(buf_value, 'c_tm_hour') > 23:
+        raise Exception("hour out of range")
+    if rffi.getintfield(buf_value, 'c_tm_min') < 0 or 
rffi.getintfield(buf_value, 'c_tm_min') > 59:
+        raise Exception("minute out of range")
+    if rffi.getintfield(buf_value, 'c_tm_sec') < 0 or 
rffi.getintfield(buf_value, 'c_tm_sec') > 61:
+        raise Exception("seconds out of range")
+    if rffi.getintfield(buf_value, 'c_tm_yday') < 0 or 
rffi.getintfield(buf_value, 'c_tm_yday') > 365:
+        raise Exception("day of year out of range")
+    if rffi.getintfield(buf_value, 'c_tm_isdst') < -1 or 
rffi.getintfield(buf_value, 'c_tm_isdst') > 1:
+        raise Exception("daylight savings flag out of range")
+
+    if _WIN:
+        # check that the format string contains only valid directives
+        length = len(format)
+        i = 0
+        while i < length:
+            if format[i] == '%':
+                i += 1
+                if i < length and format[i] == '#':
+                    # not documented by python
+                    i += 1
+                if i >= length or format[i] not in "aAbBcdHIjmMpSUwWxXyYzZ%":
+                    raise Exception("invalid format string")
+            i += 1
+
+    i = 1024
+    while True:
+        outbuf = lltype.malloc(rffi.CCHARP.TO, i, flavor='raw')
+        try:
+            buflen = c_strftime(outbuf, i, format, buf_value)
+            if buflen > 0 or i >= 256 * len(format):
+                # if the buffer is 256 times as long as the format,
+                # it's probably not failing for lack of room!
+                # More likely, the format yields an empty result,
+                # e.g. an empty format, or %Z when the timezone
+                # is unknown.
+                result = rffi.charp2strn(outbuf, intmask(buflen))
+                return result
+        finally:
+            lltype.free(outbuf, flavor='raw')
+        i += i
diff --git a/test/test_js_time.py b/test/test_js_time.py
new file mode 100644
--- /dev/null
+++ b/test/test_js_time.py
@@ -0,0 +1,97 @@
+from js.builtins.date import JsTime
+
+
+class TestJsTime(object):
+    # Sun, 17 Feb 2013 14:58:35 GMT
+    T = 1361113115765
+
+    def _new_t(self):
+        return JsTime(self.T)
+
+    def test_to_msecs(self):
+        t = self._new_t()
+        assert t.to_msec_epoc() == self.T
+
+    def test_year(self):
+        t = self._new_t()
+        assert t.year() == 2013
+
+    def test_month(self):
+        t = self._new_t()
+        assert t.month() == 2
+
+    def test_day(self):
+        t = self._new_t()
+        assert t.day() == 17
+
+    def test_hour(self):
+        t = self._new_t()
+        assert t.hour() == 14
+
+    def test_min(self):
+        t = self._new_t()
+        assert t.min() == 58
+
+    def test_sec(self):
+        t = self._new_t()
+        assert t.sec() == 35
+
+    def test_set_year(self):
+        t = self._new_t()
+        t.set_year(2012)
+        assert t.year() == 2012
+
+    def test_set_month(self):
+        t = self._new_t()
+        t.set_month(4)
+        assert t.month() == 4
+
+    def test_set_month_local(self):
+        t = self._new_t()
+        t.set_month(4, local=True)
+        assert t.month(local=True) == 4
+
+    def test_set_day(self):
+        t = self._new_t()
+        t.set_day(23)
+        assert t.day() == 23
+
+    def test_set_day_local(self):
+        t = self._new_t()
+        t.set_day(23, local=True)
+        assert t.day(local=True) == 23
+
+    def test_set_hour(self):
+        t = self._new_t()
+        t.set_hour(23)
+        assert t.hour() == 23
+
+    def test_set_hour_local(self):
+        t = self._new_t()
+        t.set_hour(23, local=True)
+        assert t.hour(local=True) == 23
+
+    def test_set_min(self):
+        t = self._new_t()
+        t.set_min(42)
+        assert t.min() == 42
+
+    def test_set_min_local(self):
+        t = self._new_t()
+        t.set_min(42, local=True)
+        assert t.min(local=True) == 42
+
+    def test_set_sec(self):
+        t = self._new_t()
+        t.set_sec(42)
+        assert t.sec() == 42
+
+    def test_set_sec_local(self):
+        t = self._new_t()
+        t.set_sec(42, local=True)
+        assert t.sec(local=True) == 42
+
+    def test_set_msec(self):
+        t = self._new_t()
+        t.set_msec(42)
+        assert t.msec() == 42
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to