Timestamps Server vs Client

This is mostly to satisfy my own curiosity because to me, it doesn’t make sense at first glance. I run this code on client and server side at the same time (as close as possible using one button push):

print(time.mktime(datetime.datetime.now().timetuple()))
print(time.mktime(datetime.datetime.utcnow().timetuple()))

The client output is:

1544030015
1544051615

The server output is:

1544029911.0
1544029911.0

On the server side, datetime.now() and datetime.utcnow() are identical, which is expected. My timezone is UTC - 6:00 at the moment, which is the exact difference between the two client timestamps, also as expected. But then why is the timestamp for datetime.now() on the client side closer to to the server’s timestamp than the client’s datetime.utcnow()? Is this coming from skulpt, the time package, Anvil, or is this exactly how it should be and I’m just not getting it?

I know I shouldn’t be using times from the client side, so this isn’t super significant, but now that I’ve found it, my brain won’t leave it alone lol.

This is because you used time.mktime(), which interprets its input as a local time (and then adjusts to produce an output in “seconds since the epoch”, which is defined as midnight UTC on Jan 1st 1970).

Generally speaking, the time.* functions in Python are full of timezone-related bear traps. You should avoid them and use datetime everywhere.

(Fun fact: Anvil handles datetimes intelligently! If you pass a time-zone-unaware datetime to or from a server function, it gets stamped with the timezone of wherever it came from. So when you collect a datetime in a DatePicker on the client, pass it to the server and store it in a data table, it (correctly) ends up in the client’s time zone.)

1 Like

Thanks for your help! That was driving me crazy. :laughing:

On the subject, what do you think is the optimal way of storing a time-related object in a JSON field? I know it could be the timestamp like I’m currently trying to use, but I know I could also do something like an ISO formatted string. Do you have any opinions on the subject?

ISO format is nice, and easy to generate with datetime.toisoformat(), but parsing it back out is a pain. (You need to do it by hand with strptime – astonishingly, the datetime.fromisoformat() method didn’t turn up until Python 3.7!)

If you want your JSON to be human-friendly, use ISO format; if you’re feeling lazy use epoch timestamps.

For the same reason, I’ve also had to do this in order to store dates/times in an Anvil SimpleObject column.

But only server-side. On the client side:
NotImplementedError: _strptime is not yet implemented in Skulpt

workaround:

def as_date(s): # where s is in ISO format
    result = date(int(s[0:4]), int(s[5:7]), int(s[8:10]))
    return result

This does very little syntax-checking, but for dates anywhere near today (e.g., birthdates of someone living), it may suffice.

1 Like

For future victims of Skulpt’s missing strptime:

def datetimefromisoformat(s, tzinfo=None):
    return datetime(int(s[0:4]), int(s[5:7]), int(s[8:10]), int(s[11:13]), int(s[14:16]), int(s[17:19]), int(s[20:]), tzinfo=tzinfo)

Same deal as @p.colbert’s version: this does basically no syntax checking, but it may suffice for modern dates.

if you’re using the tzinfo arg, be sure to read this post from @daviesian first: Time Zone issues

1 Like