Customizing timezones shown to users with pytz, datetime and Python 3 - python

I have a list of users:
tom, 0530, eastern
dick, 0745, pacific
harry, 0915, central
ect...
I need to send them an email at that specific time (or within 5 minutes) for their timezone. I've been working on a python script that I would run with cron every 5 minutes.
## pseudo code:
for user in users:
if difference of usertime and utctime is <= 5 minutes:
send email
I'm getting close, but doing the math with the converted timezones is where I'm stuck now.
code:
import datetime
import pytz
today = datetime.datetime.now().date()
user1 = pytz.timezone('US/Eastern').localize(datetime.datetime(today.year, today.month, today.day, 5, 30))
now_utc = datetime.datetime.now(pytz.timezone('UTC'))
user1_converted = user1.astimezone(pytz.timezone('UTC'))
now_utc - user1_converted
##maths

We call this "making a mountain out of a mole hill" :)
It sounds like you have user preferences for the time they would like to be emailed, and the time zone they are part of.
E.g. tom = ('US/Eastern', "09:15")
When your script runs the first thing it must do is establish the current time in UTC.
from datetime import datetime
current_time = datetime.utcnow()
Then you need to convert the user's current time, and preference time, into UTC time. From this question.
tz = timezone('US/Pacific')
def toUTC(d):
return tz.normalize(tz.localize(d)).astimezone(pytz.utc)
After you have done this you can subtract one from the other and compare to your set threshold (5 minutes) to see if it's the right time to send the email.

Related

Subtract Time from Datetime Field in Django/Python

This question seems obvious and easy but I am getting my head stretched out here. Problem is I have datetime field in model and I want to subtract time from another attribute.
here is my code I have tried so far.
#property
def boarding_time(self):
print('---------------------------')
time = self.schedule.travel_date_time.time()
print()
time_added = self.schedule.bus_company_route.routeboardingpoint_set.get(
point=self.boarding_point
).time_added
time1 = timedelta(hours=time.hour, minutes=time.minute, seconds=time.second)
time2 = timedelta(hours=time_added.hour, minutes=time_added.minute, seconds=time_added.second)
return (time1-time2)
I am actually trying to find the time delay the vehicle reaches to certain destination. Suppose vehicle was supposed to move at 8 am but the vehicle departed from bus park at 8:15 am and passenger waiting will have 15 min added to their location but I am getting error as
'datetime.timedelta' object has no attribute 'isoformat'
Im not sure if this answers your question but you can try:
from datetime import datetime, date
datetime.combine(date.today(), exit) - datetime.combine(date.today(), enter)
combine builds a datetime, that can be subtracted. Your can google about it for more...
https://docs.python.org/3/library/datetime.html
At a high level, the adjusted boarding time is derived from taking scheduled boarding time and adding to it the amount of time that lapsed between the scheduled departure time and the actual departure time from the previous destination.
Here is a simplified example that hopefully illustrates the key concepts to help you piece together a solution for your more complex problem:
from datetime import datetime, timedelta
scheduled_boarding_time = datetime.fromisoformat("2021-01-12T10:00")
departure_delay_in_minutes = 15
adjusted_boarding_time = scheduled_boarding_time + timedelta(minutes=delay_in_minutes)
print(adjusted_boarding_time.isoformat())
2021-01-12T10:15:00
The solution to your question lies in the way you handle the time stamp format. You have your date time in AM/PM for this you have to format you date accordingly. Here is something what you can do instead of what you are doing right now
from datetime import datetime
time = '2021/1/13 8:15 am' #your date format
time_added = '2021/1/13 8:45 am' #your date format
format = '%Y/%m/%d %H:%M %p' #will format your date for further computation
time = datetime.strptime(time, format)
time
o/p
datetime.datetime(2021, 1, 13, 8, 15)
time_added = datetime.strptime(time_added, format)
time_added
o/p
datetime.datetime(2021, 1, 13, 8, 45)
time2 = time_added-time1 # this will give you time difference in seconds
divmod(time2.total_seconds(), 60)[0] #use this to get difference in minutes
o/p
30.0
This same you return in your function and it will solve your problem

How to compute the time difference between two time zones in python?

How can I compute the time differential between two time zones in Python? That is, I don't want to compare TZ-aware datetime objects and get a timedelta; I want to compare two TimeZone objects and get an offset_hours. Nothing in the datetime library handles this, and neither does pytz.
Here is a solution using the Python library Pytz which solves the issue of ambiguous times at the end of daylight saving time.
from pytz import timezone
import pandas as pd
def tz_diff(date, tz1, tz2):
'''
Returns the difference in hours between timezone1 and timezone2
for a given date.
'''
date = pd.to_datetime(date)
return (tz1.localize(date) -
tz2.localize(date).astimezone(tz1))\
.seconds/3600
The examples below calculate the difference in hours between UTC and Australia time for the first of January and first of June respectively. Notice how daylight savings are taken into consideration.
utc = timezone('UTC')
aus = timezone('Australia/Sydney')
tz_diff('2017-01-01', utc, aus)
# 11.0
tz_diff('2017-06-01', utc, aus)
# 10.0
Thanks
The first thing you have to know is that the offset between two time zones depends not only on the time zones in question, but on the date you're asking about. For example, the dates on which Daylight Savings Time began and ended changed in the US in 2007. While fundamental time zone logistics change only infrequently in any single location, the rate of change globally is impossible to ignore. Therefore, you have to incorporate the date in question into your function.
Having completed the necessary preface, the actual function isn't too hard to write if you take advantage of the pendulum library. It should look something like this:
import pendulum
def tz_diff(home, away, on=None):
"""
Return the difference in hours between the away time zone and home.
`home` and `away` may be any values which pendulum parses as timezones.
However, recommended use is to specify the full formal name.
See https://gist.github.com/pamelafox/986163
As not all time zones are separated by an integer number of hours, this
function returns a float.
As time zones are political entities, their definitions can change over time.
This is complicated by the fact that daylight savings time does not start
and end on the same days uniformly across the globe. This means that there are
certain days of the year when the returned value between `Europe/Berlin` and
`America/New_York` is _not_ `6.0`.
By default, this function always assumes that you want the current
definition. If you prefer to specify, set `on` to the date of your choice.
It should be a `Pendulum` object.
This function returns the number of hours which must be added to the home time
in order to get the away time. For example,
```python
>>> tz_diff('Europe/Berlin', 'America/New_York')
-6.0
>>> tz_diff('Europe/Berlin', 'Asia/Kabul')
2.5
```
"""
if on is None:
on = pendulum.today()
diff = (on.set(tz=home) - on.set(tz=away)).total_hours()
# what about the diff from Tokyo to Honolulu? Right now the result is -19.0
# it should be 5.0; Honolulu is naturally east of Tokyo, just not so around
# the date line
if abs(diff) > 12.0:
if diff < 0.0:
diff += 24.0
else:
diff -= 24.0
return diff
As stated in the documentation, you may not get a stable result for this between any two given locations as you sweep across the days of the year. However, implementing a variant which chooses the median result over the days of the current year is an exercise left for the reader.
Here's another solution:
from datetime import datetime
from pytz import timezone
from dateutil.relativedelta import relativedelta
utcnow = timezone('utc').localize(datetime.utcnow()) # generic time
here = utcnow.astimezone(timezone('US/Eastern')).replace(tzinfo=None)
there = utcnow.astimezone(timezone('Asia/Ho_Chi_Minh')).replace(tzinfo=None)
offset = relativedelta(here, there)
offset.hours
Here what we're doing is converting a time to two different time zones. Then, we remove the time zone information so that when you calculate the difference between the two using relativedelta, we trick it into thinking that these are two different moments in time instead of the same moment in different time zones.
The above result will return -11, however this amount can change throughout the year since US/Eastern observes DST and Asia/Ho_Chi_Minh does not.
I created two functions to deal with timezone.
import datetime
import pytz
def diff_hours_tz(from_tz_name, to_tz_name, negative=False):
"""
Returns difference hours between timezones
res = diff_hours_tz("UTC", "Europe/Paris") : 2
"""
from_tz = pytz.timezone(from_tz_name)
to_tz = pytz.timezone(to_tz_name)
utc_dt = datetime.datetime.now(datetime.timezone.utc)
dt_from = dt_to = datetime.datetime.utcnow()
dt_from = from_tz.localize(dt_from)
dt_to = to_tz.localize(dt_to)
from_d = dt_from - utc_dt
if from_d.days < 0:
return diff_hours_tz(to_tz_name, from_tz_name, True)
dt_delta = dt_from - dt_to
negative_int = -1 if negative else 1
return int(dt_delta.seconds/3600)*negative_int
def dt_tz_to_tz(dt, from_tz_name, to_tz_name):
"""
Apply difference hours between timezones to a datetime object
dt_new = dt_tz_to_tz(datetime.datetime.now(), "UTC", "Europe/Paris")
"""
hours = diff_hours_tz(from_tz_name, to_tz_name)
return dt+datetime.timedelta(hours=hours)
# Usage example
res = diff_hours_tz("Europe/Paris", "America/New_York")
# Result : -6
res = diff_hours_tz("UTC", "Europe/Paris")
# Result : 2
now = datetime.datetime.now()
# Result : 2019-06-18 15:10:31.720105
dt_new = dt_tz_to_tz(now, "UTC", "Europe/Paris")
# Result : 2019-06-18 17:10:31.720105
dt_new = dt_tz_to_tz(now, "Europe/Paris", "America/New_York")
# Result : 2019-06-18 09:10:31.720105
dt_new = dt_tz_to_tz(now, "America/New_York", "Europe/Paris")
# Result : 2019-06-18 21:10:31.720105
I hope it will help !
Here is a code snippet to get the difference between UTC and US/Eastern, but it should work for any two timezones.
# The following algorithm will work no matter what is the local timezone of the server,
# but for the purposes of this discussion, let's assume that the local timezone is UTC.
local_timestamp = datetime.now()
# Assume that utc_timestamp == 2019-01-01 12:00.
utc_timestamp = pytz.utc.localize(local_timestamp)
# If it was 12:00 in New York, it would be 20:00 in UTC. So us_eastern_timestamp is a UTC
# timestamp with the value of 2019-01-01 20:00.
us_eastern_timestamp = timezone("US/Eastern").localize(local_timestamp).astimezone(pytz.utc)
# delta is a Python timedelta object representing the interval between the two timestamps,
# which, in our example, is -8 hours.
delta = utc_timestamp - us_eastern_timestamp
# In the last line, we convert the timedelta into an integer representing the number of
# hours.
print round(delta.total_seconds() / 60.0 / 60.0)
(tz_from.localize(date) - tz_to.localize(date)).seconds/3600.0
Where tz_from and tz_to are the starting and ending timezones. You must specify a particular date.
from datetime import datetime
from zoneinfo import ZoneInfo
dt = datetime.now() # 2020-09-13
tz0, tz1 = "Europe/Berlin", "US/Eastern" # +2 vs. -4 hours rel. to UTC
utcoff0, utcoff1 = dt.astimezone(ZoneInfo(tz0)).utcoffset(), dt.astimezone(ZoneInfo(tz1)).utcoffset()
print(f"hours offset between {tz0} -> {tz1} timezones: {(utcoff1-utcoff0).total_seconds()/3600}")
>>> hours offset between Europe/Berlin -> US/Eastern timezones: -6.0
a way to do this with Python 3.9's standard library.

Moved time zones now datetime.utcnow() is incorrect

I'm working on a Python application that fires notifications at certain times. I started working on this project in Italy and the program worked fine, but now that I'm back in the U.S., the time is completely wrong. There's a four hour time difference between the actual time and the time that is shown, which is weird, because Italy is 6 hours ahead.
For example, the time that datetime.utcnow() shows is 2016-05-10T18:55:47.920001Z but the time is actually 2016-05-10T14:55:47.920001Z
now = datetime.datetime.utcnow().isoformat() + 'Z' # 'Z' indicates UTC time
I tried using pytz to set the time zone (which gives me the correct time), but the API that I'm sending the current time to (Google Calendar), won't accept it. This time isn't accepted but the line of code above is, but the time is wrong.
eastern = pytz.timezone("America/New_York")
now = datetime.datetime.now(tz=eastern).isoformat() + 'Z' # 'Z' indicates UTC time
How can I get datetime.datetime.utcnow() to reflect my current time?
.utcnow() returns time in UTC. It returns the exact same value wherever you are. UTC time is the same in Italy and in US.
To generate rfc3339 timestamp: .utcnow().isoformat() + 'Z' is correct.
datetime.now(eastern).isoformat() + 'Z' is wrong. Use just datetime.now(eastern).isoformat():
>>> from datetime import datetime
>>> import pytz
>>> eastern = pytz.timezone('America/New_York')
>>> datetime.utcnow().isoformat()+'Z', datetime.now(eastern).isoformat()
('2016-05-11T15:25:18.857833Z', '2016-05-11T11:25:18.857860-04:00')
Both return the same time (if we ignore microseconds). Today, 15:25UTC is the same time as 11:25 in New York:
<local time> == <utc time> + <utc offset>
11:25 == 15:25 + (-04:00)
Try:
from datetime import datetime, timezone
# 'Z' indicates UTC time
now = datetime.now(timezone.utc).astimezone().isoformat() + 'Z'
print(now)

How to resolve created events' time mismatches due to Calendar API upgrade?

For reference, my timezone is Eastern - New York.
I am inserting events from a PostgreSQL database to a Google Calendar. I have been using UTC-4 since early June, when I finally got my app moved from v2 to v3, and for a couple of years in v2. Up until the August 18 that has worked giving me the correct time. On August 18 the time was off by one hour so I changed the setting to UTC-5. That worked for about 2 hours and then I have had to reset it back to UTC-4.
Now today, August 21, it is off an hour again and I have set the UTC back to -5. The events are getting inserted as they should with the exception of an event being an hour off and the UTC needing to be changed sometimes. The system time is correct on my server.
Any ideas on what is happening?
Some of my code snippets:
#get an event from a PostgreSQL database to insert into a Google Calendar
curs.execute("SELECT c_event_title,c_name,c_event_date,c_event_starttime,c_event_endtime,c_department,seat_arrange,c_attendee_count from sched_421 where sched_id_421=%i;" %recnum)
mit=curs.fetchall() # mit IS NOW ALL THE RESULTS OF THE QUERY
for myrec in mit: # FOR THE ONE RECORD (EVENT) IN THE QUERY RESULTS
myend_time = time.strftime("%I:%M %p", time.strptime(str(myrec[4]),"%H:%M:%S"))
if myend_time[0]=='0': # Remove leading zero for 01:00 - 09:00
myend_time = myend_time[1:]
title = ' - %s %s - Group:%s' %(myend_time,myrec[0],myrec[5])
mycontent = myrec[0]+' - '+ myrec[5]
content = mycontent
where = where_dict[room_calendar]
# THIS IS WHERE THE UTC IS, SOMETIMES 4 WORKS SOMETIMES 5 WORKS
start_time = '%sT%s-05:00' %(myrec[2],myrec[3]) # Google format
end_time = '%sT%s-05:00' %(myrec[2],myrec[4]) # Google format
myend_time = '%s' %myrec[4] # User format (am/pm)
seat_arrange = '\nSeating - %s' %str(myrec[6])
attendee_count = '\nNumber of participants: %s' %str(myrec[7])
descript = str(myrec[0]) + ' ' + seat_arrange + attendee_count+ "\n Created By: me#somewhere.com"
# upload the event to the calendar
created_event = service.events().insert(calendarId=calendar_dict[room_calendar], body=event).execute()
Are the dates you are looking at on different sides of the daylight savings switch?
Eastern Time Zone is UTC-4:00 from March to November and UTC-5:00 from November to March.
Hard-coding the TZ Offset like that is a bad idea, especially in a TZ that uses daylight savings. It would be best to store all the times as UTC and just apply the TZ information at the endpoints (data input and data display).
At the very least, you will want to have something calculate the correct TZ offset, based on the date, like a helper function or some block of logic.
I'm not sure how much control you have over the data in the database, so that would dictate which path you choose.
Ideally, you could change the 3 fields (date, start time, end time) in the database into 2 (start datetime UTC, end datetime UTC)
I have had to change this code:
# THIS IS WHERE THE UTC IS, SOMETIMES 4 WORKS SOMETIMES 5 WORKS
start_time = '%sT%s-05:00' %(myrec[2],myrec[3]) # Google format
end_time = '%sT%s-05:00' %(myrec[2],myrec[4]) # Google format
to (check to see if the event is in daylight savings time or not, this was not necessary with v2)
if bool (pytz.timezone('America/New_York').dst(datetime.datetime(myrec[2].year,myrec[2].month,myrec[2].day), is_dst=None)):
utc_offset = '4'
else:
utc_offset = '5'
start_time = '%sT%s-0%s:00' %(myrec[2],myrec[3],utc_offset)
end_time = '%sT%s-0%s:00' %(myrec[2],myrec[4],utc_offset)

Convert Facebook Event start/end times to UTC

I'm having trouble getting event start in end times in UTC format from facebook.
I'm using the Facebook Python library, I am running these queries to retrieve events:
fb_events = graph.get_connections(fb_user["id"], "events", args=["date_format=U"])
for item in fb_events['data']:
curr_event = graph.get_object(item['id'], args=["date_format=U"])
The last line of the code is where I actually get the event containing the start and end times. The arg: "date_format=U" is supposed to specify the time format in unix time, which is already in UTC, however, this code still returns normal Facebook time stamps, in local time.
How can I get this information in UTC time, or in some sort of time that is consistent across time zones?
Thanks!
The following might help you to do the conversion:
import pytz, datetime, time
import os
originalTimeStamp = os.stat("/tmp/file-from-us-west-coast").st_mtime
# prints e.g. 2010-03-31 13:01:18
print "original:",datetime.datetime.fromtimestamp(originalTimeStamp)
# re-interpret
originalTimeZone = "America/Los_Angeles"
targetTimeZone = "Europe/Paris"
newTimeStamp = pytz.timezone(originalTimeZone).localize(datetime.datetime.fromtimestamp(originalTimeStamp)).astimezone(pytz.timezone(targetTimeZone))
# prints e.g. 2010-03-31 22:01:18+02:00
print "new: ",newTimeStamp
# convert back to seconds since epoch
newTimeStamp = time.mktime(newTimeStamp.timetuple())
# print time difference in hours
print (newTimeStamp - originalTimeStamp) / 3600.0
See this link for more information: http://pytz.sourceforge.net/
Another example of the code
from datetime import *
from pytz import timezone
import pytz
[...]
if (not isinstance(pacificTime, int)):
pacificTime = int(pacificTime)
originalTimeZone = "America/Los_Angeles"
print datetime.fromtimestamp(pacificTime, pytz.timezone(originalTimeZone))

Categories

Resources