tech4nature / hogapp

1 stars 0 forks source link

Measurements appear to be in the future #34

Open sebbacon opened 5 years ago

sebbacon commented 5 years ago

When a measurement is posted, it is displayed as one hour in the future.

I'm not familiar with Django time zone stuff, so this is to record my learnings.

The docs say:

When support for time zones is enabled, Django stores datetime information in UTC in the database, uses time-zone-aware datetime objects internally, and translates them to the end user’s time zone in templates and forms

Regarding postgres, it says:

The PostgreSQL backend stores datetimes as timestamp with time zone. In practice, this means it converts datetimes from the connection’s time zone to UTC on storage, and from UTC to the connection’s time zone on retrieval.

As a consequence, if you’re using PostgreSQL, you can switch between USE_TZ = False and USE_TZ = True freely. The database connection’s time zone will be set to TIME_ZONE or UTC respectively, so that Django obtains correct datetimes in all cases. You don’t need to perform any data conversions.

Which makes sense.

The timecode burning code appears to use the creation time embedded in the video metadata, which according to this is interpreted by ffmpeg as local time and is converted to UTC. Our code then converts this back to local time.

We appear only to use datetime.datetime in our Django code, which should create UTC times. The database format assumes this.

The HogPi code appears to use datetime.datetime.now(), which is a "naive" format (no timezone info)

Django docs state:

When USE_TZ is True, Django still accepts naive datetime objects, in order to preserve backwards-compatibility. When the database layer receives one, it attempts to make it aware by interpreting it in the default time zone and raises a warning

Thus sending a naive datetime as a string as we do here creates a naive datetime at the Django end, which is then interpreted as local time and therefore stored as one hour earlier.

sebbacon commented 5 years ago

Taking current measurement 17929 as an example, the timecode is 2019 07 26 09 48 31. Its observed_at date is shown in the admin interface as 09:48:31 and in postgres it is stored as 2019-07-26 09:48:31+00, i.e. UTC. It appears in our web frontend as "2 days, 6 hours ago" - which would make it about 10:48, I guess.

sebbacon commented 5 years ago

To summarise: everything in the database is stored as UTC. We are sending UTC datestamps to the server without timezone info, which means they are interpreted as local time.

To be explicit about the timezone, we should change all datetime.now references to datetime.now(timezone.utc).isoformat() throughout.

Videos have the local time burnt in, and stored in their filenames. This is then parsed by the datetime module as if it were UTC, giving the same effect.

In that case, datetime.strptime should be called with our local timezone

time = datetime.strptime(strtime, "%Y-%m-%d-%H-%M-%S")
time = time.replace(tzinfo=tzlocal.get_localzone())