# limitations under the License. from __future__ import division """ This module defines temporal data types. """ from datetime import time, datetime, timedelta from neotime import Duration, Date, Time, DateTime from pytz import FixedOffset, timezone, utc from neobolt.types import Structure UNIX_EPOCH_DATE = Date(1970, 1, 1) UNIX_EPOCH_DATE_ORDINAL = UNIX_EPOCH_DATE.to_ordinal() UNIX_EPOCH_DATETIME_UTC = DateTime(1970, 1, 1, 0, 0, 0, utc) def hydrate_date(days): """ Hydrator for `Date` values. :param days: :return: Date """ return Date.from_ordinal(UNIX_EPOCH_DATE_ORDINAL + days) def dehydrate_date(value): """ Dehydrator for `date` values.
def _hydrate(self, obj, inst=None, version=None): from neotime import Duration, Date, Time, DateTime from pytz import FixedOffset, timezone from py2neo.data import Node, Relationship, Path from py2neo.data.spatial import Point unbound_relationship = namedtuple("UnboundRelationship", ["id", "type", "properties"]) unix_epoch_date = Date(1970, 1, 1) unix_epoch_date_ordinal = unix_epoch_date.to_ordinal() def hydrate_object(o): if isinstance(o, Structure): tag = o.tag if isinstance(o.tag, bytes) else bytes( bytearray([o.tag])) try: f = functions[tag] except KeyError: # If we don't recognise the structure type, just return it as-is return o else: return f(*o.fields) elif isinstance(o, list): return list(map(hydrate_object, o)) elif isinstance(o, dict): return {key: hydrate_object(value) for key, value in o.items()} else: return o def hydrate_node(identity, labels, properties): return Node.hydrate(self.graph, identity, labels, hydrate_object(properties), into=inst) def hydrate_relationship(identity, start_node_id, end_node_id, r_type, properties): return Relationship.hydrate(self.graph, identity, start_node_id, end_node_id, r_type, hydrate_object(properties), into=inst) def hydrate_path(nodes, relationships, sequence): nodes = [ Node.hydrate(self.graph, n_id, n_label, hydrate_object(n_properties)) for n_id, n_label, n_properties in nodes ] u_rels = [] for r_id, r_type, r_properties in relationships: u_rel = unbound_relationship(r_id, r_type, hydrate_object(r_properties)) u_rels.append(u_rel) return Path.hydrate(self.graph, nodes, u_rels, sequence) def hydrate_date(days): """ Hydrator for `Date` values. :param days: :return: Date """ return Date.from_ordinal(unix_epoch_date_ordinal + days) def hydrate_time(nanoseconds, tz=None): """ Hydrator for `Time` and `LocalTime` values. :param nanoseconds: :param tz: :return: Time """ seconds, nanoseconds = map(int, divmod(nanoseconds, 1000000000)) minutes, seconds = map(int, divmod(seconds, 60)) hours, minutes = map(int, divmod(minutes, 60)) seconds = (1000000000 * seconds + nanoseconds) / 1000000000 t = Time(hours, minutes, seconds) if tz is None: return t tz_offset_minutes, tz_offset_seconds = divmod(tz, 60) zone = FixedOffset(tz_offset_minutes) return zone.localize(t) def hydrate_datetime(seconds, nanoseconds, tz=None): """ Hydrator for `DateTime` and `LocalDateTime` values. :param seconds: :param nanoseconds: :param tz: :return: datetime """ minutes, seconds = map(int, divmod(seconds, 60)) hours, minutes = map(int, divmod(minutes, 60)) days, hours = map(int, divmod(hours, 24)) seconds = (1000000000 * seconds + nanoseconds) / 1000000000 t = DateTime.combine( Date.from_ordinal(unix_epoch_date_ordinal + days), Time(hours, minutes, seconds)) if tz is None: return t if isinstance(tz, int): tz_offset_minutes, tz_offset_seconds = divmod(tz, 60) zone = FixedOffset(tz_offset_minutes) else: zone = timezone(tz) return zone.localize(t) def hydrate_duration(months, days, seconds, nanoseconds): """ Hydrator for `Duration` values. :param months: :param days: :param seconds: :param nanoseconds: :return: `duration` namedtuple """ return Duration(months=months, days=days, seconds=seconds, nanoseconds=nanoseconds) def hydrate_point(srid, *coordinates): """ Create a new instance of a Point subclass from a raw set of fields. The subclass chosen is determined by the given SRID; a ValueError will be raised if no such subclass can be found. """ try: point_class, dim = Point.class_for_srid(srid) except KeyError: point = Point(coordinates) point.srid = srid return point else: if len(coordinates) != dim: raise ValueError( "SRID %d requires %d coordinates (%d provided)" % (srid, dim, len(coordinates))) return point_class(coordinates) functions = { b"N": hydrate_node, b"R": hydrate_relationship, b"P": hydrate_path, } if version >= (2, 0): functions.update({ b"D": hydrate_date, b"T": hydrate_time, # time zone offset b"t": hydrate_time, # no time zone b"F": hydrate_datetime, # time zone offset b"f": hydrate_datetime, # time zone name b"d": hydrate_datetime, # no time zone b"E": hydrate_duration, b"X": hydrate_point, b"Y": hydrate_point, }) return hydrate_object(obj)