Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

getmtime() vs datetime.now():

Tags:

python

gmt

clock

This code prints a false warning once per year, in the night of the clock shift (central European summer time to central European time):

import os
import datetime

now = datetime.datetime.now()
age = now - datetime.datetime.fromtimestamp(os.path.getmtime(file_name))
if (age.seconds + age.days * 24 * 3600) < -180:
    print('WARN: file has timestap from future?: %s' % age)

How to make this code work even during this yearly one hour clock shift?

Update

I care only for the age, not the datetime.

like image 534
guettli Avatar asked Oct 28 '19 08:10

guettli


2 Answers

The posted fragment can be easily improved by switching from local to UTC time. There are no summer (daylight saving) time changes in UTC. Just replace these two datetime functions now() -> utcnow() (docs) and fromtimestamp() -> utcfromtimestamp() (docs).

However, if the only expected output is a file age in seconds, we can directly use the timestamps (seconds from an "epoch") without any conversion:

import time
import os.path

...
age = time.time() - os.path.getmtime(file_name)
like image 122
VPfB Avatar answered Sep 25 '22 16:09

VPfB


both your datetime objects are 'naive', meaning that they don't know about DST. datetime.now() returns the current time your machine runs on, and that might include DST. Same goes for datetime.fromtimestamp(os.path.getmtime()).

#1 - localizing your datetime objects could be an option; something like

from datetime import datetime
import tzlocal
now_aware = tzlocal.get_localzone().localize(datetime.now())
file_mtime = datetime.fromtimestamp(os.path.getmtime(file))
# assuming the file was created on a machine in the same timezone (!):
file_mtime_aware = now_aware.tzinfo.localize(file_mtime)
age = now_aware - file_mtime_aware

#2 - another option, using UTC conversion with datetime:

now = datetime.utcnow()
age = now - datetime.utcfromtimestamp(os.path.getmtime(file_name))
if (age.seconds + age.days * 24 * 3600) < -180:
    print(f'WARN: file has timestamp from future?: {age} s')

#3 - as VPfB points out in his answer, os.path.getmtime returns a UTC timestamp (check os module docs and time module docs). So the easiest solution could be to skip conversion to datetime in the first place and use only UTC timestamps; e.g. getting the current UTC timestamp as time.time().

Working with timezones can drive you mad... but there're some good resources out there, e.g. this medium post.

like image 40
FObersteiner Avatar answered Sep 23 '22 16:09

FObersteiner