def test_tzinfo(self): # Verify that tzinfo works correctly. ts1 = 294217199000 # In EST ts2 = 294217200000 # In EDT (spring forward, we skip ahead by 1 hour) utc_dt1 = datetime(1979, 4, 29, 6, 59, 59) utc_dt2 = datetime(1979, 4, 29, 7, 0, 0) self.assertEqual( moment.tz(ts1).datetime().strftime(fmt), '1979-04-29 06:59:59 UTC') self.assertEqual( moment.tz(ts2).datetime().strftime(fmt), '1979-04-29 07:00:00 UTC') # Verify that we get correct time zone variation depending on DST status. nyc_dt1 = moment.tz(ts1, 'America/New_York').datetime() nyc_dt2 = moment.tz(ts2, 'America/New_York').datetime() self.assertEqual(nyc_dt1.strftime(fmt), '1979-04-29 01:59:59 EST') self.assertEqual(nyc_dt2.strftime(fmt), '1979-04-29 03:00:00 EDT') # Make sure we can get timestamps back from these datatimes. self.assertEqual(moment.dt_to_ts(nyc_dt1) * 1000, ts1) self.assertEqual(moment.dt_to_ts(nyc_dt2) * 1000, ts2) # Verify that the datetime objects we get produce correct time zones in terms of DST when we # manipulate them. NOTE: it is a bit unexpected that we add 1hr + 1sec rather than just 1sec, # but it seems like that is how Python datetime works. Note that timezone does get switched # correctly between EDT and EST. self.assertEqual(nyc_dt1 + timedelta(seconds=3601), nyc_dt2) self.assertEqual(nyc_dt2 - timedelta(seconds=3601), nyc_dt1) self.assertEqual((nyc_dt1 + timedelta(seconds=3601)).strftime(fmt), '1979-04-29 03:00:00 EDT') self.assertEqual((nyc_dt2 - timedelta(seconds=3601)).strftime(fmt), '1979-04-29 01:59:59 EST')
def encode_object(value): """ Produces a Grist-encoded version of the value, e.g. turning a Date into ['d', timestamp]. Returns ['U', repr(value)] if it fails to encode otherwise. """ try: if isinstance(value, (six.text_type, float, bool)) or value is None: return value elif isinstance(value, six.binary_type): return value.decode('utf8') elif isinstance(value, six.integer_types): if not is_int_short(value): raise UnmarshallableError("Integer too large") return value elif isinstance(value, AltText): return six.text_type(value) elif isinstance(value, records.Record): return ['R', value._table.table_id, value._row_id] elif isinstance(value, RecordStub): return ['R', value.table_id, value.row_id] elif isinstance(value, datetime): return [ 'D', moment.dt_to_ts(value), value.tzinfo.zone.name if value.tzinfo else 'UTC' ] elif isinstance(value, date): return ['d', moment.date_to_ts(value)] elif isinstance(value, RaisedException): return ['E'] + value.encode_args() elif isinstance(value, (list, tuple)): return ['L'] + [encode_object(item) for item in value] elif isinstance(value, records.RecordSet): return ['r', value._table.table_id, value._get_encodable_row_ids()] elif isinstance(value, RecordSetStub): return ['r', value.table_id, value.row_ids] elif isinstance(value, dict): if not all(isinstance(key, six.string_types) for key in value): raise UnmarshallableError("Dict with non-string keys") return [ 'O', {key: encode_object(val) for key, val in six.iteritems(value)} ] elif value == _pending_sentinel: return ['P'] elif value == _censored_sentinel: return ['C'] elif isinstance(value, UnmarshallableValue): return ['U', value.value_repr] except Exception as e: pass # We either don't know how to convert the value, or failed during the conversion. Instead we # return an "UnmarshallableValue" object, with repr() of the value to show to the user. return ['U', safe_repr(value)]
def do_convert(self, value): if value in ("", None): return None elif isinstance(value, datetime.datetime): return moment.dt_to_ts(value, self.timezone) elif isinstance(value, datetime.date): return moment.date_to_ts(value, self.timezone) elif isinstance(value, (float, int, long)): return float(value) elif isinstance(value, basestring): # We also accept a datetime in ISO format (YYYY-MM-DD[T]HH:mm:ss) return moment.parse_iso(value, self.timezone) else: raise objtypes.ConversionError('DateTime')
def do_convert(cls, value): if value in ("", None): return None elif isinstance(value, datetime.datetime): return moment.dt_to_ts(value) elif isinstance(value, datetime.date): return moment.date_to_ts(value) elif isinstance(value, (float, int, long)): return float(value) elif isinstance(value, basestring): # We also accept a date in ISO format (YYYY-MM-DD), the time portion is optional and ignored return moment.parse_iso_date(value) else: raise objtypes.ConversionError('Date')
def encode_object(value): """ Produces a Grist-encoded version of the value, e.g. turning a Date into ['d', timestamp]. Returns ['U', repr(value)] if it fails to encode otherwise. """ try: if isinstance(value, (str, unicode, float, bool)) or value is None: return value elif isinstance(value, (long, int)): if not is_int_short(value): raise UnmarshallableError("Integer too large") return value elif isinstance(value, AltText): return str(value) elif isinstance(value, records.Record): return ['R', value._table.table_id, value._row_id] elif isinstance(value, datetime): return [ 'D', moment.dt_to_ts(value), value.tzinfo.zone.name if value.tzinfo else 'UTC' ] elif isinstance(value, date): return ['d', moment.date_to_ts(value)] elif isinstance(value, RaisedException): return ['E'] + value.encode_args() elif isinstance(value, (list, tuple, RecordList, records.ColumnView)): return ['L'] + [encode_object(item) for item in value] elif isinstance(value, records.RecordSet): # Represent RecordSet (e.g. result of lookupRecords) in the same way as a RecordList. return ['L'] + [encode_object(int(item)) for item in value] elif isinstance(value, dict): if not all(isinstance(key, basestring) for key in value): raise UnmarshallableError("Dict with non-string keys") return [ 'O', {key: encode_object(val) for key, val in value.iteritems()} ] elif value == _pending_sentinel: return ['P'] elif isinstance(value, UnmarshallableValue): return ['U', value.value_repr] except Exception as e: pass # We either don't know how to convert the value, or failed during the conversion. Instead we # return an "UnmarshallableValue" object, with repr() of the value to show to the user. return ['U', safe_repr(value)]
def test_dt_to_ds(self): # Verify that dt_to_ts works for both naive and aware datetime objects. value_dt = datetime(2015, 3, 14, 0, 0) # In UTC value_sec = 1426291200 tzla = moment.get_zone('America/Los_Angeles') def format_utc(ts): return moment.ts_to_dt(ts, moment.get_zone('UTC')).strftime(fmt) # Check that a naive datetime is interpreted in UTC. self.assertEqual(value_dt.strftime("%Y-%m-%d %H:%M:%S %Z"), '2015-03-14 00:00:00 ') self.assertEqual(moment.dt_to_ts(value_dt), value_sec) # Interpreted in UTC # Get an explicit UTC version and make sure that also works. value_dt_utc = value_dt.replace(tzinfo=moment.TZ_UTC) self.assertEqual(value_dt_utc.strftime(fmt), '2015-03-14 00:00:00 UTC') self.assertEqual(moment.dt_to_ts(value_dt_utc), value_sec) # Get an aware datetime, and make sure that works too. value_dt_aware = moment.ts_to_dt(value_sec, moment.get_zone('America/New_York')) self.assertEqual(value_dt_aware.strftime(fmt), '2015-03-13 20:00:00 EDT') self.assertEqual(moment.dt_to_ts(value_dt_aware), value_sec) # Check that dt_to_ts pays attention to the timezone. # If we interpret midnight in LA time, it's a later timestamp. self.assertEqual(format_utc(moment.dt_to_ts(value_dt, tzla)), '2015-03-14 07:00:00 UTC') # The second argument is ignored if the datetime is aware. self.assertEqual(format_utc(moment.dt_to_ts(value_dt_utc, tzla)), '2015-03-14 00:00:00 UTC') self.assertEqual(format_utc(moment.dt_to_ts(value_dt_aware, tzla)), '2015-03-14 00:00:00 UTC') # If we modify an aware datetime, we may get a new timezone abbreviation. value_dt_aware -= timedelta(days=28) self.assertEqual(value_dt_aware.strftime(fmt), '2015-02-13 20:00:00 EST')
def get_grist_column(self, values): grist_type = "Date" if all(self._is_date(v) for v in values) else "DateTime" grist_values = [(v if (v is None) else moment.dt_to_ts(v)) for v in values] return grist_type, grist_values