TimeZone confusion

I’m trying to understand the differences in storing datetime and presenting datetime.

I understand that browsers are local timezone aware and that they ‘stamp’ the datetime object with the local timezone when data is created through the client app.
I understand that everything on the server side is UTC plus a timestamp.

But I can’t seem to get my head around the following:

I was in Spain last week, and I made an entry at 08:42am which was UTC+2
This is confirmed by the database table entry where I keep a ‘created’ timestamp (it says 06:42 utc)
When I got back to the UK last week, I viewed the entry in a client app browser, and the datetime was presented as 07:42am. I assumed that it was being automatically updated to the local timezone of the browser.

when I look at the same datetime in the same client app browser today, it says 09:42!!!

I know we went back an hour this morning, and I know Spain did the same with their Daylight Savings…but can anyone explain what is going on?

Note:
I access these entries by clicking an ‘edit’ button in a repeating panel row, which then populates a form. On that form is a datetime picker object, which is where the date/time is being present.

Thanks very much for any advice/guidance. I’m just trying to understand, rather than fix anything.
Cheers
Boz

Going step-by-step:

So far, so sensible.

Yes, pretty much. (It’s actually not being updated at all - it’s being stored as a timestamp with a UTC offset. How it’s then displayed is up to you, but “07:42 local” is a good representation of 06:42UTC when local is BST ie UTC+1)

Wat. This is the point where I start asking questions about how exactly your client app is displaying that date. What’s the code? What happens if you just print out the datetime object? I suspect something very strange is happening in whatever conversion-to-local-time-for-presentation machinery you’re using.

1 Like

Thanks very much @meredydd - this is getting more confusing now, so I"m going to work through it here, hopefully with screenshots and let’s see if we can get to the bottom of it.

I repeat, I’m not looking for a code fix, I’m just trying to understand what is happening to the timings/timezone data.

I made an entry in Spain at 08:42 on 18/10 for a diary entry of the 15/10

The data is captured from a simple user form on the client app, using a datepicker object with time_picker enabled. No other settings or special anvil.tz() stuff.

I then create a new article in the client form code, to send to a server function so that it can be written to the data table. The important bit of the client side code looks like this:

new_article={'DOSE_DATE_TIME':self.dose_date_pkr.date,

I then call a server function from the client to save the new article to the datatables

result=anvil.server.call('add_article_daily_diary', new_article)

That server function looks like this:

# add a row to T_DIARY
@anvil.server.callable
def add_article_daily_diary(article_dict):
  me=check_user()
  # I've snipped some code out of this function, so that I don't fill up the forum post
  # nothing there that messes with DOSE_DATE_TIME though
  try:  
     app_tables.t_diary.add_row(
     DOSE_DATE=DOSE_DATE,
     PATIENT_ID=me['PATIENT_ID'],
     CREATED=datetime.now(),
     CREATOR=me['email'],
     STUDY_SITE=get_patient_study_site(),
     LATEST=bool(True),
     STEP=str(step),
     **article_dict)
     val=True
  except Exception as E:
     print(f"Boz in ServerMod add_article_daily_diary. Error is {E}")
     val=False
  return val

Just a simple add_row() function.

The data is stored in a datatable and looks like this

As you can see, we have a CREATED timestamp and a DOSE_DATE_TIME, which is the local timestamp when I was in Spain. All as expected so far.
Note: Within the data table, the DOSE_DATE_TIME column is of datatype (date and time)

Viewing the data when back in the UK

In the client app, I have a form with a repeating_panel in it.
Each row in the repeating_panel is a card, and has several elements…including an edit button…
It looks like this

We are interested in the row with the Date 15-10-2024
I load the items into the repeating_panel by calling a server function like this:

self.repeating_panel_1.items = anvil.server.call('get_all_user_diary_entries')

And here is the server side function:

This function just returns the search results ordered by a different column (DOSE_DATE)
I’ve put a debug line into the server function, and here are the results

BOZ in get_all_user_diary_entries and CREATED is: 2024-10-18 06:42:29.914064+00:00 and DOSE_DATE_TIME is: 2024-10-15 10:42:00+02:00

So, the server function is amending the DOSE_DATE_TIME as it transfers that information back to the client… It is saying 10:42+02:00

This 10:42 now gets changed to 09:42 when I display it in the client app:

Now when I click the edit button in my repeating panel I populate a hidden linear panel with the original form used to capture the data from the user in the first place, and populate the fields so they can edit them…

The important part of that edit_btn code is below, and I’ve whacked a debug line in there

  def edit_btn_click(self, **event_args):
    # Open an alert displaying the 'ArticleEdit' Form
    article_copy=dict(self.item) # grab a copy of the rows values
    orig_copy=self.item
    print(f'boz self.item is of type {type(self.item)}')
    print(f'BOZ in diary_view_copy and datetime is set to: {article_copy["DOSE_DATE_TIME"]}')
....

In the console I get the following output:

BOZ in diary_view_copy and datetime is seet to: 2024-10-15 10:42:00+02:00

So I think this is where the browse locale is kicking in for the datetime object.

Here is a screenshot of the client app when the edit_btn has been clicked

So I guess my question is as follows:

if the data in the table is 08:42+0200 from UTC, why is a search returning 10:42+02:00? Something is then displaying it as 09:42 (see above)

Sorry for the very long response…it has been good to identify where the issue is coming from though.

Cheers
Boz

Hello @robert.heelan,

If you access your app using different browsers on the same device and from other devices, is the conversion of the DOSE_DATE_TIME consistent?

(I’m wondering whether an incorrect LOCALE setting in one browser on one device may be the culprit.)

1 Like

Hi @tomherden ,

I like your thinking. I tried out your suggestions on my Mac (Chrome + Safari), then I tried it out on my Android device with DuckDuckGo and Chrome, and the dates are always the same.

On my Mac, I then VPN’d to Australia and tried from there with Safari, and I still get the 09:42 time. Maybe I misunderstand vpns.

Thanks all the same.
Boz

You can probably change the timezone of your computer
then refresh the page

Hi @stucork
I changed the timezone of my android to Hong Kong, and you’re correct, the time now states 16:42 in the app. HK is UTC+8 at the moment.
So the presentation within the app is using timezone of the browser.

My timezone is set to London and GMT on the mac, and the date/time on my machine is correct for my location.

What do you guys thing to this theory:

1.) The data was entered on the 18th October at 08:42 in Spain (GMT+2), but the data reads for 08:42 on the 15th October
2.) Both Spain and UK have had daylight savings (back 1 hour), so the equivalent locale time would be 09:42 in both Spain and UK.

Therefore, the App is presenting a conversion of what the present time would be, in the present location for the time the entry is stating in Spain.

“You set it at 08:42 in Spain on the 15th, today that is the equivalent of 09:42”
So it is today’s local equivalent of the timing?

I’m guessing…can you tell?
Boz

Decades ago, Python decided to store time zone offsets (numbers), not actual time zones (names). It’s mathematically impossible to reliably reverse-engineer the latter from only the former.

See

for a discussion of the issues that can result. The author has created a library to help address those issues, with Python source code that might work in the browser. (I haven’t tried it.)

You may really need the time zone (by name). If so, you can add a column to your database, and store it there.