0

I wrote this script to capture the current time from the server but forgot to take into account Daylight Savings Time (DST). The server outputs the time in GMT, so after a few shenanigans I was able to create a cleaner output. The problem is that it's giving me the time two hours behind my time zone in Rome, Italy.

I'm currently using timedelta(hours=1), and if I change hours=1 to hours=2 I get the corret time, but I was wondering if anyone knows an easy, hassle-free way to automate this, so I won't have to change this twice a year.

Here is what I have so far:

This is how the timestamp comes out of the server:

logstash_firewall_timestamp = '2023-04-11T14:37:27.840Z'

Here is where I convert it and have been adding one hour:

import datetime
from datetime import datetime,timedelta

pattern = '%Y-%m-%dT%H:%M:%S.%fZ'
dt = datetime.strptime(logstash_firewall_timestamp, pattern)
new_timestamp = str(dt + timedelta(hours=1))[:-3] + 'Z'

And here is a final cleanup:

formatted_time = (''.join(letter for letter in new_timestamp if not letter.isalpha()))[:19]

To summarize:

GMT Time:

2023-04-11 14:37:27

Current Script Output:

2023-04-11 15:37:27

Intended Output:

2023-04-11 16:37:27
tadman
  • 208,517
  • 23
  • 234
  • 262
  • UTC is Universal. I'm not sure what UTC(Rome) is. Also GMT and UTC are roughly the same, if you ignore leap seconds. Try testing output with the time-zone or at least time-zone offset included. The examples you've given don't make any sense in isolation. UTC does not have DST. GMT shouldn't, either, but London's time-zone will have British Summer Time applied. – tadman Apr 11 '23 at 14:49
  • @tadman Hey, thanks for your reply. Everything I've tried so far has been a bust, but to answer your question, UTC Rome is UTC+2 (at the moment) because of daylight savings. – OverflowStack Apr 11 '23 at 15:08
  • You keep saying UTC Rome like it's a thing, but that's a contradiction. UTC is universal. Rome is [CET/CEST](https://en.wikipedia.org/wiki/Central_European_Time). – tadman Apr 11 '23 at 15:09
  • @tadman po-tay-to, po-tah-to... still doesnt help me with my problem – OverflowStack Apr 11 '23 at 15:12
  • It gets you one step closer since you'll know what time zones to use for conversion from/to your desired value. First thing is to pin down precisely what zone your source data is in, and secondly what your target is. If it's UTC+2 that'd map to your expectations, but you might be using BST (UTC+1) inadvertently due to a configuration error. – tadman Apr 11 '23 at 15:14
  • 1
    On Python >= 3.9, using the `zoneinfo` module is probably the most streamlined way of doing the conversion. See worked example: https://stackoverflow.com/a/67354610/765091 – slothrop Apr 11 '23 at 15:16
  • @tadman yes, I know that. As I explained in the question, the server outputs the time in plain UTC 0. Rome is 2 hours ahead at the moment because of DST. The original script I wrote uses UTC+1 (without DST), but now that DST is in place, I found myself having to change over 30 files. So my question is how I can rewrite this script to account for these DST changes automatically. – OverflowStack Apr 11 '23 at 15:18
  • @OverflowStack (1) change your strptime pattern to `'%Y-%m-%dT%H:%M:%S.%f%z'`. The use of `%z` means that the "Z" in the log timestamp will be interpreted as UTC, so you'll get a Python datetime object that knows that it is in UTC. (2) follow example in my earlier comment to convert it to the Europe/Rome timezone. – slothrop Apr 11 '23 at 15:20

2 Answers2

3

Based on the answer from @vighub, but using the zoneinfo module available in Python >= 3.9, rather than deprecated pytz:

import datetime
from zoneinfo import ZoneInfo

server_dtstr = '2023-04-11T14:37:27.840Z'  # final 'Z' denotes UTC
server_format = '%Y-%m-%dT%H:%M:%S.%f%z'

server_dt = datetime.datetime.strptime(server_dtstr, server_format)

local_tz = ZoneInfo('Europe/Rome')
local_dt = server_dt.astimezone(local_tz)

output_format = '%Y-%m-%d %H:%M:%S'  # or your preferred format
print(local_dt.strftime(output_format))

Output:

2023-04-11 16:37:27
slothrop
  • 3,218
  • 1
  • 18
  • 11
  • Bizarre error I'm getting when I run this on my end... Any idea why? raise ZoneInfoNotFoundError(f"No time zone found with key {key}") zoneinfo._common.ZoneInfoNotFoundError: 'No time zone found with key Europe/Rome – OverflowStack Apr 12 '23 at 16:16
  • This looks like `zoneinfo` can't find the system timezone directory (as in https://stackoverflow.com/questions/71058888/zoneinfonotfounderror-no-time-zone-found-with-key-utc) – slothrop Apr 12 '23 at 16:22
  • 1
    In that case, you could `pip install tzdata` - the tzdata package provides a source of time zone data that doesn't rely on your OS for it. – slothrop Apr 12 '23 at 16:23
2

If you have a datetime object, you can call the astimezone method to convert to a proper timezone

from datetime import datetime
import pytz

rome_tz = pytz.timezone('Europe/Rome')
server_date = '2023-04-11T14:37:27.840Z'
pattern = '%Y-%m-%dT%H:%M:%S.%f%z'
# time in UTC, your case
dt = datetime.strptime(server_date, pattern)
# convert in with Rome time with daylight saving
dt_rome = dt.astimezone(rome_tz)

print(dt) 
>>> 2023-04-11 14:37:27+00:00
print(dt_rome)
>>> 2023-04-11 16:37:27+02:00

# without daylight saving time
dt = datetime(2023, 1, 11, 12, 37, tzinfo=pytz.UTC)
dt_rome = dt.astimezone(rome_tz)
print(dt_rome)
>>> 2023-01-11 15:37:27+01:00
vighub
  • 173
  • 1
  • 6
  • Hey, for a moment I thought this was going to work. The values used in the datetime function are integers, but the server outputs a long string ('2023-04-11T14:37:27.840Z'). I really don't feel like Regex'ing it (although I will if I really have to), but if you know a quick workaround, it'll be trully appreciated. – OverflowStack Apr 11 '23 at 15:54
  • 1
    @OverflowStack as per my comment, pass that string to strptime using the pattern `'%Y-%m-%dT%H:%M:%S.%f%z'`. The `%z` specifier will cause the final Z to be interpreted as the UTC timezone. – slothrop Apr 11 '23 at 15:55
  • @slothrop Sorry, but I don't understand it. Even after replacing Z with z, I still get the same result. – OverflowStack Apr 11 '23 at 16:08
  • @OverflowStack you need to replace your `Z` with `%z`. – slothrop Apr 11 '23 at 16:08
  • I edited my answer adding the good point expressed by @slothrop – vighub Apr 11 '23 at 16:11
  • @slothrop Doesn't work. My current time is 18:11 but I'm still getting it one hour behind 17:11 – OverflowStack Apr 11 '23 at 16:11
  • @OverflowStack sorry to hear that, can you specify the timestamp in the log file that you are using to get that 17:11 result? – slothrop Apr 11 '23 at 16:13
  • @slothrop Gee, it worked... Thank you very much for your help and for bearing with me! – OverflowStack Apr 11 '23 at 16:15
  • @vighub Thank you very much for your help and for bearing with me! – OverflowStack Apr 11 '23 at 16:15
  • @vighub Found another and more concise way to do it. I posted an answer. Any thoughts? – OverflowStack Apr 12 '23 at 15:39
  • @slothrop Found another and more concise way to do it. I posted an answer. Any thoughts? – OverflowStack Apr 12 '23 at 15:39