How to compare two timezone strings? - python

Is there some library or built-in to compare two timezones? What I want is the offset of hours between two timezones
For example:
hours = diff_timezones("America/Los_Angeles", "America/Sao_Paulo")
print(hours) # -> 3

FYI: Python 3.9+ ships with zoneinfo in its standard library, while dateutil (below) is a third-party package available on PyPI as python-dateutil.
Using dateutil.tz.gettz:
from datetime import datetime, timedelta
from dateutil.tz import gettz
def diff_timezones(tz1: str, tz2: str) -> timedelta:
zero = datetime.utcfromtimestamp(0)
diff = zero.replace(tzinfo=gettz(tz1)) - zero.replace(tzinfo=gettz(tz2))
return diff
Sample usage:
>>> diff_timezones('America/Los_Angeles', 'America/Sao_Paulo')
datetime.timedelta(seconds=18000)
The result here is a datetime.timedelta instance. To get a float of hours:
>>> td.total_seconds() / (60 * 60)
5.0
CAUTION: I don't believe this would take into account DST since it uses a fixed datetime of the Unix epoch (1970-01-01), so it might be off in cases where one area obeys DST and another does not. To account for that you might be able to use the current timestamp as a reference date instead.

This should work.
and here's a great blog about timezones and datetime: Blog
import datetime, pytz
d_naive = datetime.datetime.now()
timezone_a = pytz.timezone("America/Los_Angeles")
timezone_b = pytz.timezone("America/New_York")
d_aware_a = timezone_a.localize(d_naive)
d_aware_b = timezone_b.localize(d_naive)
difference = d_aware_a - d_aware_b
print(difference.total_seconds() / 60 / 60 ) # seconds / minutes

Related

convert string 'GMT+5:30' to Time Zone (like Aisa/Kolkata) without checking datetime.datetime.now() in python

convert string 'GMT+5:30' to Time Zone (like Aisa/Kolkata) without checking datetime.datetime.now() in python
now = datetime.datetime.astimezone(Time_Zone).tzname() # current time
print(now)
print(type(now))
utc_offset = datetime.timedelta(hours=5, minutes=30) # +5:30
print(utc_offset)
for tz in map(pytz.timezone, pytz.all_timezones_set):
if (now.astimezone(tz).utcoffset() == utc_offset):
print(tz.zone)
To find matching timezones for a given UTC offset you must specify a date since the UTC offset of timezones changes over time and they might have DST during certain periods. Timezones and DST originate from political decisions so it's not as easy as hacking together a Python script.
Here's an example to find timezones with UTC+5:30 using dateutil:
import datetime
from dateutil.tz import gettz
from dateutil.zoneinfo import get_zonefile_instance
offset, match_offset = int(60*60*5.5), []
for z in get_zonefile_instance().zones:
off = datetime.datetime.now(tz=gettz(z)).utcoffset()
if int(off.total_seconds()) == offset:
match_offset.append(z)
print(match_offset)
# ['Asia/Calcutta', 'Asia/Colombo', 'Asia/Kolkata']
You could replace datetime.datetime.now with any date of your choice.
Same result using pytz:
import pytz
offset, match_offset = int(60*60*5.5), []
for z in pytz.all_timezones:
off = datetime.datetime.now(tz=pytz.timezone(z)).utcoffset()
if int(off.total_seconds()) == offset:
match_offset.append(z)
print(match_offset)
# ['Asia/Calcutta', 'Asia/Colombo', 'Asia/Kolkata']
Note that pytz is more efficient in getting UTC offsets, however I'd prefer dateutil due to its better integration with the Python standard lib / datetime objects.

How to get UTC time in Python?

How do I get the UTC time, i.e. milliseconds since Unix epoch on Jan 1, 1970?
For Python 2 code, use datetime.utcnow():
from datetime import datetime
datetime.utcnow()
For Python 3, use datetime.now(timezone.utc) (the 2.x solution will technically work, but has a giant warning in the 3.x docs):
from datetime import datetime, timezone
datetime.now(timezone.utc)
For your purposes when you need to calculate an amount of time spent between two dates all that you need is to subtract end and start dates. The results of such subtraction is a timedelta object.
From the python docs:
class datetime.timedelta([days[, seconds[, microseconds[, milliseconds[, minutes[, hours[, weeks]]]]]]])
And this means that by default you can get any of the fields mentioned in it's definition -
days, seconds, microseconds, milliseconds, minutes, hours, weeks. Also timedelta instance has total_seconds() method that:
Return the total number of seconds contained in the duration.
Equivalent to (td.microseconds + (td.seconds + td.days * 24 * 3600) *
106) / 106 computed with true division enabled.
Timezone-aware datetime object, unlike datetime.utcnow():
from datetime import datetime,timezone
now_utc = datetime.now(timezone.utc)
Timestamp in milliseconds since Unix epoch:
datetime.now(timezone.utc).timestamp() * 1000
In the form closest to your original:
import datetime
def UtcNow():
now = datetime.datetime.utcnow()
return now
If you need to know the number of seconds from 1970-01-01 rather than a native Python datetime, use this instead:
return (now - datetime.datetime(1970, 1, 1)).total_seconds()
Python has naming conventions that are at odds with what you might be used to in Javascript, see PEP 8. Also, a function that simply returns the result of another function is rather silly; if it's just a matter of making it more accessible, you can create another name for a function by simply assigning it. The first example above could be replaced with:
utc_now = datetime.datetime.utcnow
import datetime
import pytz
# datetime object with timezone awareness:
datetime.datetime.now(tz=pytz.utc)
# seconds from epoch:
datetime.datetime.now(tz=pytz.utc).timestamp()
# ms from epoch:
int(datetime.datetime.now(tz=pytz.utc).timestamp() * 1000)
Timezone aware with zero external dependencies:
from datetime import datetime, timezone
def utc_now():
return datetime.utcnow().replace(tzinfo=timezone.utc)
From datetime.datetime you already can export to timestamps with method strftime. Following your function example:
import datetime
def UtcNow():
now = datetime.datetime.utcnow()
return int(now.strftime("%s"))
If you want microseconds, you need to change the export string and cast to float like: return float(now.strftime("%s.%f"))
you could use datetime library to get UTC time even local time.
import datetime
utc_time = datetime.datetime.utcnow()
print(utc_time.strftime('%Y%m%d %H%M%S'))
why all reply based on datetime and not time?
i think is the easy way !
import time
nowgmt = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime())
print(nowgmt)
To be correct, UTC format needs at least the T letter:
>>> a=(datetime.datetime.now(timezone.utc))
>>> a.strftime("%Y-%m-%dT%H:%M:%SZ")
'2022-11-28T16:42:17Z'

How to see if file is older than 3 months in Python?

I'm curious about manipulating time in Python. I can get the (last modified) age of a file using the os.path.getmtime() function as such:
import os.path, time
os.path.getmtime(oldLoc)
I need to run some kind of test to see whether this time is within the last three months or not, but I'm thoroughly confused by all the available time options in Python.
Can anyone offer any insight? Kind Regards.
time.time() - os.path.getmtime(oldLoc) > (3 * 30 * 24 * 60 * 60)
You can use a bit of datetime arthimetic here for the sake of clarity.
>>> import datetime
>>> today = datetime.datetime.today()
>>> modified_date = datetime.datetime.fromtimestamp(os.path.getmtime('yourfile'))
>>> duration = today - modified_date
>>> duration.days > 90 # approximation again. there is no direct support for months.
True
To find whether a file is older than 3 calendar months, you could use dateutil.relativedelta:
#!/usr/bin/env python
import os
from datetime import datetime
from dateutil.relativedelta import relativedelta # $ pip install python-dateutil
three_months_ago = datetime.now() - relativedelta(months=3)
file_time = datetime.fromtimestamp(os.path.getmtime(filename))
if file_time < three_months_ago:
print("%s is older than 3 months" % filename)
The exact number of days in "last 3 months" may differ from 90 days in this case. If you need 90 days exactly instead:
from datetime import datetime, timedelta
three_months_ago = datetime.now() - timedelta(days=90)
If you want to take into account the changes in the local utc offset, see Find if 24 hrs have passed between datetimes - Python.
I was looking for something similar and came up with this alternative solution:
from os import path
from datetime import datetime, timedelta
two_days_ago = datetime.now() - timedelta(days=2)
filetime = datetime.fromtimestamp(path.getctime(file))
if filetime < two_days_ago:
print "File is more than two days old"
If you need to have the exact number of days you can use the calendar module in conjunction with datetime, e.g.,
import calendar
import datetime
def total_number_of_days(number_of_months=3):
c = calendar.Calendar()
d = datetime.datetime.now()
total = 0
for offset in range(0, number_of_months):
current_month = d.month - offset
while current_month <= 0:
current_month = 12 + current_month
days_in_month = len( filter(lambda x: x != 0, c.itermonthdays(d.year, current_month)))
total = total + days_in_month
return total
And then feed the result of total_number_of_days() into the code that others have provided for the date arithmetic.
1 day = 24 hours = 86400 seconds. Then 3 months is roughly 90 days which is 90 * 86400 seconds. You can use this information to add/subtract time. Or you can try the Python datetime module for date maths. (especially timedelta )
This is to know whether a date is 3 months older
from datetime import date, timedelta
time_period=date.today()-date(2016, 8, 10) < timedelta(days = 120)
Here is a generic solution using time deltas:
from datetime import datetime
def is_file_older_than (file, delta):
cutoff = datetime.utcnow() - delta
mtime = datetime.utcfromtimestamp(os.path.getmtime(file))
if mtime < cutoff:
return True
return False
To detect a file older than 3 months we can either approximate to 90 days:
from datetime import timedelta
is_file_older_than(filename, timedelta(days=90))
Or, if you are ok installing external dependencies:
from dateutil.relativedelta import relativedelta # pip install python-dateutil
is_file_older_than(filename, relativedelta(months=3))

Get time zone information of the system in Python?

I want to get the default timezone (PST) of my system from Python. What's the best way to do that? I'd like to avoid forking another process.
This should work:
import time
time.tzname
time.tzname returns a tuple of two strings: The first is the name of the local non-DST timezone, the second is the name of the local DST timezone.
Example return: ('MST', 'MDT')
Gives a UTC offset like in ThomasH's answer, but takes daylight savings into account.
>>> import time
>>> offset = time.timezone if (time.localtime().tm_isdst == 0) else time.altzone
>>> offset / 60 / 60 * -1
-9
The value of time.timezone or time.altzone is in seconds West of UTC (with areas East of UTC getting a negative value). This is the opposite to how we'd actually like it, hence the * -1.
time.localtime().tm_isdst will be zero if daylight savings is currently not in effect (although this may not be correct if an area has recently changed their daylight savings law).
EDIT: marr75 is correct, I've edited the answer accordingly.
I found this to work well:
import datetime
tz_string = datetime.datetime.now(datetime.timezone.utc).astimezone().tzname()
For me this was able to differentiate between daylight savings and not.
From Python 3.6 you can do:
tz_string = datetime.datetime.now().astimezone().tzname()
Or
tz_string = datetime.datetime.now().astimezone().tzinfo
Reference with more detail: https://stackoverflow.com/a/39079819/4549682
Check out the Python Time Module.
from time import gmtime, strftime
print(strftime("%z", gmtime()))
Pacific Standard Time
The code snippets for calculating offset are incorrect, see http://bugs.python.org/issue7229.
The correct way to handle this is:
def local_time_offset(t=None):
"""Return offset of local zone from GMT, either at present or at time t."""
# python2.3 localtime() can't take None
if t is None:
t = time.time()
if time.localtime(t).tm_isdst and time.daylight:
return -time.altzone
else:
return -time.timezone
This is in all likelihood, not the exact question that the OP asked, but there are two incorrect snippets on the page and time bugs suck to track down and fix.
For Python 3.6+ this can be easily achieved by following code:
import datetime
local_timezone = datetime.datetime.utcnow().astimezone().tzinfo
print(local_timezone)
But with Python < 3.6 calling astimezone() on naive datetime doesn't work. So we've to do it in a slightly different way.
So for Python 3.x,
import datetime
local_timezone = datetime.datetime.now(datetime.timezone.utc).astimezone().tzinfo
print(local_timezone)
Sample Output:
On Netherlands Server(Python 3.6.9):
CEST
On Bangladesh Server(Python 3.8.2):
+06
More details can be found on this thread.
To obtain timezone information in the form of a datetime.tzinfo object, use dateutil.tz.tzlocal():
from dateutil import tz
myTimeZone = tz.tzlocal()
This object can be used in the tz parameter of datetime.datetime.now():
from datetime import datetime
from dateutil import tz
localisedDatetime = datetime.now(tz = tz.tzlocal())
or the tz parameter of datetime object via datetime.datetime.astimezone():
from datetime import datetime
from dateutil import tz
unlocalisedDatetime = datetime.now()
localisedDatetime = unlocalisedDatetime.astimezone(tz = tz.tzlocal())
Getting offset from UTC as timedelta:
from datetime import datetime, timezone
now = datetime.now()
now.replace(tzinfo=timezone.utc) - now.astimezone(timezone.utc)
Or like this (more obscure but also works):
datetime.now(timezone.utc).astimezone().tzinfo.utcoffset(None)
Both solutions give the same result. For example: datetime.timedelta(seconds=7200)
import tzlocal
tz_info = tzlocal.get_localzone() # 'US/Central' or 'Asia/Calcutta'
dt = datetime.now() # 2023-01-15 15:17:24.412430
print(tz_info.localize(dt) # 2023-01-15 15:17:24.412430-06:00
with tzlocal we will be able to get the local timezone.

Converting datetime to POSIX time

How do I convert a datetime or date object into a POSIX timestamp in python? There are methods to create a datetime object out of a timestamp, but I don't seem to find any obvious ways to do the operation the opposite way.
import time, datetime
d = datetime.datetime.now()
print time.mktime(d.timetuple())
For UTC calculations, calendar.timegm is the inverse of time.gmtime.
import calendar, datetime
d = datetime.datetime.utcnow()
print calendar.timegm(d.timetuple())
Note that Python now (3.5.2) includes a built-in method for this in datetime objects:
>>> import datetime
>>> now = datetime.datetime(2020, 11, 18, 18, 52, 47, 874766)
>>> now.timestamp() # Local time
1605743567.874766
>>> now.replace(tzinfo=datetime.timezone.utc).timestamp() # UTC
1605725567.874766 # 5 hours delta (I'm in UTC-5)
In python, time.time() can return seconds as a floating point number that includes a decimal component with the microseconds. In order to convert a datetime back to this representation, you have to add the microseconds component because the direct timetuple doesn't include it.
import time, datetime
posix_now = time.time()
d = datetime.datetime.fromtimestamp(posix_now)
no_microseconds_time = time.mktime(d.timetuple())
has_microseconds_time = time.mktime(d.timetuple()) + d.microsecond * 0.000001
print posix_now
print no_microseconds_time
print has_microseconds_time
Best conversion from posix/epoch to datetime timestamp and the reverse:
this_time = datetime.datetime.utcnow() # datetime.datetime type
epoch_time = this_time.timestamp() # posix time or epoch time
this_time = datetime.datetime.fromtimestamp(epoch_time)
It depends
Is your datetime object timezone aware or naive?
Timezone Aware
If it is aware it's simple
from datetime import datetime, timezone
aware_date = datetime.now(tz=timezone.utc)
posix_timestamp = aware_date.timestamp()
as date.timestamp() gives you "POSIX timestamp"
NOTE: more accurate to call it an epoch/unix timestamp as it may not be POSIX compliant
Timezone Naive
If it's not timezone aware (naive), then you'd need to know what timezone it was originally in so we can use replace() to convert it into a timezone aware date object. Let's assume that you've stored/retrieved it as UTC Naive. Here we create one, as an example:
from datetime import datetime, timezone
naive_date = datetime.utcnow() # this date is naive, but is UTC based
aware_date = naive_date.replace(tzinfo=timezone.utc) # this date is no longer naive
# now we do as we did with the last one
posix_timestamp = aware_date.timestamp()
It's always better to get to a timezone aware date as soon as you can to prevent issues that can arise with naive dates (as Python will often assume they are local times and can mess you up)
NOTE: also be careful with your understanding of the epoch as it is platform dependent

Categories

Resources