I used a crappy editor and needed to make some tab->space conversions.
Also added some comments about possible future improvements, and a test for an 1870 datetime.
Kind regards,
--
Danny W. Adair
Director
Unfold Limited
New Zealand
Talk: +64 4 472 1679
Fax: +64 4 472 1680
Write: [EMAIL PROTECTED]
Browse: www.unfold.co.nz
Visit/Post: 22a Clifton Terrace, Kelburn 6005, Wellington, New Zealand
==============================
Caution
The contents of this email and any attachments contain information which is CONFIDENTIAL and may be subject to LEGAL PRIVILEGE. If you are not the intended recipient, you must not read, use, distribute, copy or retain this email or its attachments. If you have received this email in error, please notify us immediately by return email or collect telephone call and delete this email. Thank you. We do not accept any responsibility for any changes made to this email or any attachment after transmission from us.
==============================
#!/usr/bin/env python """ qooxdoo JSON Date support Functions for serialization of datetime objects to JSON Dates in the format 'new Date(Date.UTC(year,month,day[,hour[,minute[,seconds[,milliseconds]]]]))' and vice versa.
Full timezone support. Version: 1.1 Author: Danny W. Adair <[EMAIL PROTECTED]> Last Change: 20 June 2006 """ import datetime, time # Timezone helpers # See http://docs.python.org/lib/datetime-tzinfo.html # XXX - Note that this is only done once. A long running server process should # probably re-create the local timezone every time it's needed, in case daylight # saving time kicks in while it's running. STDOFFSET = datetime.timedelta(seconds=-time.timezone) DSTOFFSET = time.daylight and datetime.timedelta(seconds=-time.altzone) or STDOFFSET DSTDIFF = DSTOFFSET - STDOFFSET class LocalTimezone(datetime.tzinfo): """A class capturing the platform's idea of local time.""" def utcoffset(self, dt): return self._isdst(dt) and DSTOFFSET or STDOFFSET def dst(self, dt): return self._isdst(dt) and DSTDIFF or datetime.timedelta(0) def tzname(self, dt): return time.tzname[self._isdst(dt)] def _isdst(self, dt): tt = (dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.weekday(), 0, -1) stamp = time.mktime(tt) tt = time.localtime(stamp) return tt.tm_isdst > 0 local_timezone = LocalTimezone() class UTC(datetime.tzinfo): """UTC time zone.""" def utcoffset(self, dt): return datetime.timedelta(0) def tzname(self, dt): return 'UTC' def dst(self, dt): return datetime.timedelta(0) utc = UTC() # JSON Date Serialization/Deserialization class JSONDateError(Exception): """Exception for JSON parsing errors.""" pass def datetime2JSON(dt): """ Converts the given datetime object to a string suitable for JavaScript evaluation: 'new Date(Date.UTC(year,month,day[,hour[,minute[,seconds[,milliseconds]]]]))' If the datetime object is timezone-aware, it will be converted to UTC. If it is naive (= no timezone information), UTC will be assumed and applied. XXX This could be extended to also accept date instead of datetime objects, and return correspondingly shorter JavaScript commands for them. XXX 'dt.microseconds / 1000' truncates. Would rounding - 'int(round(dt.microsecond / 1000.0)) - be better? """ # Apply UTC if datetime is naive, otherwise convert to UTC dt = (dt.tzinfo is None) and dt.replace(tzinfo = utc) or dt.astimezone(utc) return 'new Date(Date.UTC(%i,%i,%i,%i,%i,%i,%i))' % (dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond / 1000) def JSON2datetime(json_dt): """ Parses json datetime string and returns a corresponding datetime object in UTC timezone. json_dt is expected to be in the format 'new Date(Date.UTC(year,month,day[,hour[,minute[,seconds[,milliseconds]]]]))' or 'null' A JSONDateError exception is raised if it isn't. Empty strings also raise this exception; use JavaScript's 'null' to indicate no date. 'null' will return None. # XXX The json datetime string currently must start with 'new Date(Date.UTC(' and must end in '))'. This could be less strict to allow white space as in JavaScript - regular expressions ftw? XXX This could allow for 'date_only' and in such a case return a date object instead of a datetime object. XXX This could allow for timezone-related parameters, so that the datetime could be returned in a different timezone, or as a naive datetime. """ if not json_dt: raise JSONDateError, 'Empty date - use "null" to indicate no date' elif json_dt=='null': return None try: assert json_dt.startswith('new Date(Date.UTC(') and json_dt.endswith('))') except AssertionError: raise JSONDateError, 'Invalid date format' try: parts = [int(part) for part in json_dt.split('(')[2].split(')')[0].split(',')] num_parts = len(parts) if num_parts > 7: raise ValueError except (IndexError, ValueError): raise JSONDateError, 'Invalid date format' if num_parts < 3: raise JSONDateError, 'Not enough arguments' elif num_parts > 7: raise JSONDateError, 'Too many arguments' elif num_parts == 7: # datetime constructor will take microseconds parts[6] = parts[6] * 1000 # An invalid date might have been specified (29 Feb in non-leap year etc.) try: # Construct as timezone-aware UTC return datetime.datetime(tzinfo=utc, *parts) except ValueError, msg: raise JSONDateError, 'Invalid date: %s' % msg def test(): import sys, traceback LABEL_WIDTH = 18 print 'Naive datetime <-> JSON' print '(UTC is applied to naive datetimes)' print naive_now = datetime.datetime.now() print 'Naive now:'.ljust(LABEL_WIDTH), naive_now json_naive_now = datetime2JSON(naive_now) print 'Qooxdoo JSON UTC:'.ljust(LABEL_WIDTH), json_naive_now utc_now = JSON2datetime(json_naive_now) print 'UTC now from JSON:'.ljust(LABEL_WIDTH), utc_now json_now = datetime2JSON(utc_now) print 'Qooxdoo JSON UTC:'.ljust(LABEL_WIDTH), json_now assert json_naive_now == json_now print local_now = datetime.datetime.now(local_timezone) local_tz_name = local_timezone.tzname(local_now) local_tz_utcoffset = str(local_now)[-6:] print 'Local timezone-aware datetime <-> JSON' print '(converted from %s(%s) to UTC)' % (local_tz_name, local_tz_utcoffset) print print 'Local now:'.ljust(LABEL_WIDTH), local_now json_local_now = datetime2JSON(local_now) print 'Qooxdoo JSON UTC:'.ljust(LABEL_WIDTH), json_local_now utc_now = JSON2datetime(json_local_now) print 'UTC now from JSON:'.ljust(LABEL_WIDTH), utc_now json_now = datetime2JSON(utc_now) print 'Qooxdoo JSON UTC:'.ljust(LABEL_WIDTH), json_now assert json_local_now == json_now print print 'Various JSON -> datetime' def test_json(input): print 'Input:', repr(input) print 'Output:', try: print JSON2datetime(input) except: exc_class, exc_value, exc_tb = sys.exc_info() # Don't be verbose with handled errors if exc_class!=JSONDateError: traceback.print_tb(exc_tb) print '%s: %s' % (exc_class.__name__, exc_value) print '-' * 30 test_json('') test_json('null') test_json('hum(bug(') test_json('new Date(Date.UTC(') test_json('new Date(Date.UTC(humbug))') test_json('new Date(Date.UTC(2006))') test_json('new Date(Date.UTC(2006, 6))') test_json('new Date(Date.UTC(2006, 6, 20))') test_json('new Date(Date.UTC(2006, 6, x))') test_json('new Date(Date.UTC(2006,6,20,13)') test_json('new Date(Date.UTC(2006,6,20,13))') test_json('new Date(Date.UTC(2006,6,31,13,55,12,123))') test_json('new Date( Date.UTC(2006,6,20, 13,55,12,123) )') test_json('new Date(Date.UTC(2006,6,20, 13,55,12,123))') test_json('new Date(Date.UTC(1870,6,20, 13,55,12,123))') if __name__=='__main__': test()
_______________________________________________ qooxdoo-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/qooxdoo-devel
