I've implemented a REST webservice using flask. It stores and provides events information.
While storing information, I do the following steps:
Take the date, time and timezone.
Localize into the provided timezone
Then convert it into utc timezone
Finally get the utc timestamp and store it in the db.
def __get_timestamp(_datetime):
"""Returns the timestamp from datetime
"""
return time.mktime(_datetime.timetuple())
def __strptime(formatted_dt, tzinfo):
"""Returns the utc timestamp after conversion from entered timezone to utc
"""
tzinfo_dt = tzinfo.localize(datetime.datetime(formatted_dt['year'], formatted_dt['month'], formatted_dt['day'], formatted_dt['hour'], formatted_dt['minute']), is_dst=True)
utc = get_tzinfo()
utc_tz = utc.normalize(tzinfo_dt.astimezone(utc))
return __get_timestamp(utc_tz)
def get_tzinfo(user_timezone="UTC"):
"""Return pytz timezone
"""
return pytz.timezone(user_timezone)
While retrieving information
Retrieve the utc timestamp
Localize it into the utc
Convert it into the required timezone
Return with the required format
def get_tzinfo(user_timezone="UTC"):
"""Return pytz timezone
"""
return pytz.timezone(user_timezone)
def __strftime(ts, tzinfo, format='%Y-%m-%d %I:%M %p'):
"""Return the formatted datetime after converting utc timestamp to required timezone
"""
utc = get_tzinfo()
utc_dt = utc.localize(datetime.datetime.fromtimestamp(ts), is_dst=True)
tzinfo_dt = tzinfo.normalize(utc_dt.astimezone(tzinfo))
formatted_dt = tzinfo_dt.strftime(format)
return formatted_dt
The sequence goes like this
Entered datetime = 2014-03-21 14:00
TimeZone = "Asia/Kathmandu" --> (GMT+05:45) Kathmandu
Resulting timestamp = 1395407700
Final Formatted Output = "2014-03-21 03:00 PM"
The problem seems to be with daylight saving because the same code gives the correct result when tested locally.
Currently the webservice is being run on Openshift
whose server has "EDT" timezone,
while my local settings has "NPT".
How can this be resolved?
Related
I created a form with a DateField and a TimeField. When printing these from the routes.py I get these example values:
TimeField: 17:30:00
DateField: 2021-07-12
How can I turn those values into a datetime object, which I can submit to my Postgres Database? The required object format is DateTime. The Postgres Table is set up as TIMESTAMPTZ. I tried replace() to add the time to the DateField Data. But that does not work. I am new to datetimes and such, so please excuse my ignorance. How do the Timezones work? because I probably need to add the timezone somehow for the TIMESTAMPTZ, right?
Below is the minimal code for the functioning
forms.py
class CreateEvent(Form):
dt = DateField('DateTimePicker')
start_time = TimeField('Start')
submit = SubmitField("Submit")
models.py
class Events(db.Model):
__tablename__='events'
eid = db.Column(db.Integer, primary_key = True)
event_day = db.Column(db.DateTime, nullable=False)
start_time = db.Column(db.DateTime, nullable=False)
def __init__(self, event_day, start_time):
self.event_day = event_day
self.start_time = start_time
routes.py
if request.method == 'POST':
if form.validate() == False:
return render_template('create.html', form=form)
else:
event_day = form.dt.data
start_time = form.start_time.data
print(start_time)
print(event_day)
start_time = event_day.replace(time=start_time)
newevent = Events(event_day, start_time)
db.session.add(newevent)
db.session.commit()
return "Success"
Just in case, here is the Postgres Create Statement for the table:
CREATE TABLE events (
eid serial PRIMARY KEY NOT NULL,
event_day TIMESTAMPTZ NOT NULL,
start_time TIMESTAMPTZ NOT NULL,
);
pip install dateutil:
https://dateutil.readthedocs.io/en/stable/
then:
from dateutil.parser import parse
TimeField = "17:30:00"
DateField = "2021-07-12"
parse(DateField + ' ' + TimeField)
datetime.datetime(2021, 7, 12, 17, 30)
You probably don't need to add a timezone, Postgres will use the timezone setting for the server. Postgres does not actually store the timezone in a timestamptz field. It just uses the timezone setting to rotate the value to a UTC time for storage.
Not tested but as an example, and you may have to install pytz from PIP (if not already present on your system). Python knows so-called naive datetime objects (that have no timezone context), and time zone-aware datetime objects.
So the goal is to build a string with the date and the time, then parse it into a datetime object. Next, we add the desired time zone (in this example it is assumed US/Pacific so change as appropriate).
import datetime
import pytz
TimeField = "17:30:00"
DateField = "2021-07-12"
current_tz = pytz.timezone('US/Pacific')
# parse string into naive datetime object
dt_naive = datetime.datetime.strptime(f"{DateField} {TimeField}", "%Y-%m-%d %H:%M:%S")
# convert to time zone-aware datetime
dt_aware = current_tz.localize(dt_naive)
I want to get current time in GMT, like 2015-08-21 05:13:13+00:00 Here you can see that correction is made like 00:00 for GMT, In django they are using from django.utils import timezone and date_to = timezone.now() to calculate the current time. How I will get the same functionality in flask, Formate of time should be like 2015-08-21 05:13:13+00:00 not like 2015-03-30 07:19:06.746037+02. I got this link but they are using 2015-03-30 07:19:06+02. I don't want. Just GTM time
Following code is in Django, I want same in Flask, Here they are using from django.utils import timezone. In Flask what is equivalent of it, which gives current time in this format 2015-08-21 05:13:13+00:00
import datetime
import pytz
from django.utils import timezone
def calc_date_args(date_from, date_to, date_options):
try:
date_to = timezone.now()
print 'calc_date_args, date_to', date_to #calc_date_args, date_to 2015-08-21 05:13:13.615541+00:00
date_from = date_to - datetime.timedelta(days=float(date_options))
except Exception:
raise ValueError(_("The time delta must be a number representing "
"the time span in days"))
return date_from, date_to
Not sure if you mean UTC time instead of GMT, as most machines consume UTC and most timestamps are in UTC.
In Python 3 to get UTC timezone-aware timestamp:
import datetime
def now():
"""Get timezone-aware UTC timestamp."""
return datetime.datetime.now(datetime.timezone.utc)
I am trying to all the record for a certain day with the following:
entered_at = request.session['entered_at']
entered_at = datetime.strptime(entered_at, "%m-%d-%Y")
day_start = entered_at.replace(hour=00, minute=00)
day_end = entered_at.replace(hour=23, minute=59)
entries = Entry.objects.filter(
customer=customer,
entered_at__lt=day_end,
entered_at__gte=day_start
)
When I do this I get the following warning in my console:
DateTimeField received a naive datetime while time zone support is
active.
I know I can add something like: , day_start = entered_at.replace(hour=00, minute=00, tzinfo=<UTC>)
however, this will not make the range from midnight to 11:59pm relative to the users timezone if I use UTC.
How can I express a full day relative to the users timezone?
I believe you want something like this, using the pytz library. See How to make an unaware datetime timezone aware in python:
import pytz
entered_at = request.session['entered_at']
entered_at = datetime.strptime(entered_at, "%m-%d-%Y")
day_start = entered_at.replace(hour=00, minute=00)
day_end = entered_at.replace(hour=23, minute=59)
timezone = pytz.timezone("America/Los_Angeles")
day_start = timezone.localize(day_start)
day_end = timezone.localize(day_end)
entries = Entry.objects.filter(customer=customer,
entered_at__lt=day_end,
entered_at__gte=day_start)
I am writing a method in a Python module which tries to make live easier to the users. This method implements the creation of events in that calendar.
def update_event(start_datetime=None, end_datetime=None, description=None):
'''
Args:
start_date: string datetime in the format YYYY-MM-DD or in RFC 3339
end_date: string datetime in the format YYYY-MM-DD or in RFC 3339
description: string with description (\n are transforrmed into new lines)
'''
If the user specifies the start_date or the end_date a check up should be made in order to determine if the date is in YYYY-MM-DD format or in the datetime RFC 3339 format.
if (start_date is not None):
# Check whether we have an date or datetime value
# Whole day events are represented as YYYY-MM-DD
# Other events are represented as 2014-04-25T10:47:00.000-07:00
whole_day_event = False
try:
new_start_time = datetime.datetime.strptime(start_date,'YYYY-MM-DD')
# Here the event date is updated
try:
new_start_time = datetime.datetime.strptime(start_date,'%Y-%m-%dT%H:%M:%S%z')
#Here the event date is updated
except ValueError:
return (ErrorCodeWhatever)
except ValueError:
return (ErrorCodeWhatever)
Is this a good way of doing this? Can I check what kind of date I am receiving in a nicer way?
Thanks!
dateutil.parser.parse can be used to attempt to parse strings into datetime objects for you.
from dateutil.parser import parse
def update_event(start_datetime=None, end_datetime=None, description=None):
if start_datetime is not None:
new_start_time = parse(start_datetime)
return new_start_time
d = ['23/04/2014', '24-04-2013', '25th April 2014']
new = [update_event(i) for i in d]
for date in new:
print(date)
# 2014-04-23 00:00:00
# 2013-04-24 00:00:00
# 2014-04-25 00:00:00
Extending #Ffisegydd answer you can also specify your target datetime format that you want like this :-
from dateutil.parser import parse
def update_event(start_datetime=None, end_datetime=None, description=None):
if start_datetime is not None:
new_start_time = parse(start_datetime)
return new_start_time
d = ['06/07/2021 06:40:23.277000','06/07/2021 06:40','06/07/2021']
new = [update_event(i) for i in d]
for date in new:
print(date.strftime('%Y/%m/%d %H:%M:%S.%f'))
I'm attempting to craft a function that takes a time object and converts it to UTC time. The code below appears to be off by one hour. When i run noon through the converter, i get back 18:00:00. But when i run the same data through online converters, i get 17:00:00.
What am i doing wrong here? Any help would be greatly appreciated.
import pytz, datetime
def convert_to_utc(time, tz):
now_dt = datetime.datetime.utcnow()
#get a date object
date_dt = now_dt.date()
#combine the current date object with our given time object
dt = datetime.datetime.combine(date_dt, time)
#get an timezone object for the source timezone
src_tz = pytz.timezone(str(tz))
#stamp the source datetime object with the src timezone
src_dt = dt.replace(tzinfo=src_tz)
#get the offset from utc to given timezone
offset = str(int(src_dt.strftime("%z"))).rstrip('0')
#convert the source datetime object to
utc_dt = src_dt.astimezone(pytz.utc)
#return the converted time and the offset in integer format
return (utc_dt.time(), int(offset))
time = datetime.datetime.strptime('12:00:00', "%H:%M:%S").time()
(TIME, offset) = convert_to_utc(time, 'America/Chicago')
print TIME.strftime("%H:%M:%S")
**EDIT**
Here's the updated(and functional) code in case anyone else needs help converting to/from UTC.
Thanks everyone for your help!
import pytz, datetime
def convert_to_utc(time, tz): #this returns the offset in int form as well
now_dt = datetime.datetime.utcnow()
#get a date object
date_dt = now_dt.date()
#combine the current date object with our given time object
dt = datetime.datetime.combine(date_dt, time)
#get an timezone object for the source timezone
src_tz = pytz.timezone(str(tz))
#stamp the source datetime object with the src timezone
src_dt = src_tz.localize(dt)
#get the offset from utc to given timezone
offset = str(int(src_dt.strftime("%z"))).rstrip('0')
#convert the source datetime object to
utc_dt = src_dt.astimezone(pytz.utc)
#return the converted time and the offset in integer format
return (utc_dt.time(), int(offset))
def convert_from_utc(time, tz):
now_dt = datetime.datetime.now()
date = now_dt.date()
dt = datetime.datetime.combine(date, time)
dest = pytz.timezone(str(tz))
dt = dt.replace(tzinfo=pytz.utc)
dest_dt = dt.astimezone(dest)
return dest_dt.time()
time = datetime.datetime.strptime('12:00:00', "%H:%M:%S").time()
(TIME, offset) = convert_to_utc(time, 'America/Chicago')
print TIME.strftime("%H:%M:%S")
utc_time = datetime.datetime.strptime('17:00:00', "%H:%M:%S").time()
TIME = convert_from_utc(utc_time, 'America/Chicago')
print TIME.strftime("%H:%M:%S")
Change
src_dt = dt.replace(tzinfo=src_tz)
to
src_dt = src_tz.localize(dt)
Using localize adjusts for Daylight Savings Time, while replace does not.
See the section entitled "Localized times and date arithmetic" in the docs.
To convert time in given timezone to UTC time:
from datetime import datetime
import pytz
def convert_to_utc(time, tzname, date=None, is_dst=None):
tz = pytz.timezone(tzname)
if date is None: # use date from current local time in tz
date = datetime.now(tz).date()
dt = tz.localize(datetime.combine(date, time), is_dst=is_dst)
return dt.astimezone(pytz.utc).time(), dt.utcoffset().total_seconds()
if is_dst is None it raises an exception for ambiguous local times.
To convert UTC time to local time in given timezone:
def convert_from_utc(time, tzname, date=None):
tz = pytz.timezone(tzname)
if date is None: # use date from current time in utc
date = datetime.utcnow().date()
dt = datetime.combine(date, time).replace(tzinfo=pytz.utc)
return tz.normalize(dt.astimezone(tz)).time()
Example:
time = datetime.strptime('12:00:00', "%H:%M:%S").time()
utc_time, offset = convert_to_utc(time, 'America/Chicago')
print utc_time.strftime("%H:%M:%S"), offset # -> 17:00:00 -18000.0
utc_time = datetime.strptime('17:00:00', "%H:%M:%S").time()
time = convert_from_utc(utc_time, 'America/Chicago')
print time.strftime("%H:%M:%S") # -> 12:00:00
In general it is preferable to work with full datetime objects to avoid ambiguity with what is the correct date i.e., pass and return datetime objects.
By using the replace method on the datetime, you're not allowing the time zone to be adjusted for daylight savings time. Try using one of the documented methods from the pytz documentation:
src_dt = src_tz.localize(dt)