Search code examples
pythonorientdbtimestamp-with-timezone

OrientDB: DateTime conversion issue on SELECT in python with different timezone between server and db


My System and relevant settings:

  • Linux (tried both in Ubuntu and Debian)
  • Python 2.7.11
  • pyorient 1.4.6a0
  • OrientDB 2.1.8
  • Studio 2.1
  • Server timezone "Europe/Rome" (CET/CEST)
  • OrientDB timezone "UTC"

Due to datetime inserting problems like the one described here I had to set the OrientDB timezone to "UTC":

ALTER DATABASE TIMEZONE UTC

Having the server timezone set to "Europe/Rome" creates some problems when executing SELECT on a datetime object in python. For example:

select distinct(tstamp_ini) as ini from Fct order by ini desc limit 1

in Studio the command returns what I expect:

2016-03-22 12:00:00 

while in python I have a different result:

print result[0]
{{'ini': datetime.datetime(2016, 3, 22, 13, 0)},'version':0,'rid':'#-2:139359'}

res=result[0].ini
print res
2016-03-22 13:00:00
print type(res)
<type 'datetime.datetime'>
print res.tzinfo
None

I'd like the resulting datetime to be the same in python as in Studio.


Solution

  • As explained here in pyorient (serializations.py) dates and datetimes are encoded and decoded using local time. This create several problems as described in the link and also the one described in the question.

    A possible solution is to change serialization.py so that everything is treated as UTC.

    In

    def _encode_value(self, value):
    

    add

    from calendar import timegm
    

    for datetime change

    elif isinstance(value, datetime):
      ret = str(int(time.mktime(value.timetuple())) * 1000) + 't'
    

    to

    elif isinstance(value, datetime):
      ret = str(int(timegm(value.timetuple())) * 1000) + 't'
    

    for date change

    elif isinstance(value, date):
      ret = str(int(time.mktime(value.timetuple())) * 1000) + 'a'
    

    to

    elif isinstance(value, date):
      ret = str(int(timegm(value.timetuple())) * 1000) + 'a'
    

    in

    def _parse_number(self, content):
    

    for date change

    if c == 'a':
      collected = date.fromtimestamp(float(collected) / 1000)
    

    to

    if c == 'a':
      collected = datetime.utcfromtimestamp(float(collected) / 1000).date()
    

    for datetime change

    elif c == 't':
      collected = datetime.fromtimestamp(float(collected) / 1000)
    

    to

    elif c == 't':
      collected = datetime.utcfromtimestamp(float(collected) / 1000)