handle timezones

This commit is contained in:
Dima Gerasimov 2019-04-30 16:03:54 +01:00
parent 08d4c447bf
commit 510d771e6e

35
sql.py
View file

@ -2,21 +2,40 @@
from pathlib import Path from pathlib import Path
from datetime import datetime from datetime import datetime
from itertools import islice from itertools import islice
from typing import Type, NamedTuple, Union from typing import Type, NamedTuple, Union, Optional
import logging import logging
from location import _load_locations, Location, get_logger from location import _load_locations, Location, get_logger
import sqlalchemy # type: ignore
import sqlalchemy as sa # type: ignore import sqlalchemy as sa # type: ignore
from kython import ichunks from kython import ichunks
from kython.py37 import fromisoformat
# TODO move to some common thing?
class IsoDateTime(sqlalchemy.TypeDecorator):
# TODO can we use something more effecient? e.g. blob for encoded datetime and tz? not sure if worth it
impl = sqlalchemy.types.String
# TODO optional?
def process_bind_param(self, value: Optional[datetime], dialect) -> Optional[str]:
if value is None:
return None
return value.isoformat()
def process_result_value(self, value: Optional[str], dialect) -> Optional[datetime]:
if value is None:
return None
return fromisoformat(value)
def _map_type(cls): def _map_type(cls):
tmap = { tmap = {
str: sa.String, str: sa.String,
float: sa.Float, float: sa.Float,
datetime: sa.types.TIMESTAMP(timezone=True), # TODO tz? datetime: IsoDateTime,
# TODO FIXME utc seems to be lost.. doesn't sqlite support it or what?
} }
r = tmap.get(cls, None) r = tmap.get(cls, None)
if r is not None: if r is not None:
@ -30,7 +49,8 @@ def _map_type(cls):
return _map_type(elems[0]) # meh.. return _map_type(elems[0]) # meh..
raise RuntimeError(f'Unexpected type {cls}') raise RuntimeError(f'Unexpected type {cls}')
# TODO to strart with, just assert utc when serializing, deserializing
# TODO how to use timestamp as key? just round it?
def make_schema(cls: Type[NamedTuple]): # TODO covariant? def make_schema(cls: Type[NamedTuple]): # TODO covariant?
res = [] res = []
@ -71,7 +91,7 @@ def test(tmp_path):
tdir = Path(tmp_path) tdir = Path(tmp_path)
tdb = tdir / 'test.sqlite' tdb = tdir / 'test.sqlite'
test_limit = 100 test_limit = 100
test_src = Path('/L/tmp/loc/LocationHistory.json') test_src = Path('/L/tmp/LocationHistory.json')
# TODO meh, double loading, but for now fine # TODO meh, double loading, but for now fine
with test_src.open('r') as fo: with test_src.open('r') as fo:
@ -80,10 +100,7 @@ def test(tmp_path):
cache_locs(source=test_src, db_path=tdb, limit=test_limit) cache_locs(source=test_src, db_path=tdb, limit=test_limit)
cached_locs = list(iter_db_locs(tdb)) cached_locs = list(iter_db_locs(tdb))
assert len(cached_locs) == test_limit assert len(cached_locs) == test_limit
def FIXME_tz(locs): assert real_locs == cached_locs
# TODO FIXME tzinfo...
return [x._replace(dt=x.dt.replace(tzinfo=None)) for x in locs]
assert FIXME_tz(real_locs) == FIXME_tz(cached_locs)
def main(): def main():