django compare time fields - python

I am trying to compare two date fields for the time. Here is what I am doing. My output when I print. I can see it is the same, but comparison result is False! Any pointers to what I am doing wrong?
for appt in appointment_detail:
print(appt['start_time'])
print(slot_time)
print(slot_time == appt['start_time'])
Result:
2018-09-22 11:00:00+00:00
2018-09-22 11:00:00
False
Thanks

Since one DateTime is timezone aware and one is not, they are not equal
To compare or to check equivalence, you have to convert both to standard unit/format
Here I'm removing timezone info of both datetime.
wo_tz_slot_time = slot_time.replace(tzinfo=None)
wo_tz_appt_start_time = appt['start_time'].replace(tzinfo=None)
print(wo_tz_slot_time == wo_tz_appt_start_time)

You compare a datetime with time zone with a datetime that unaware about time zone, you can add time zone to unaware datetime like bellow:
import pytz
from datetime import datetime
time_zone_str = '2018-09-22 11:00:00+00:00'
date_time_str = '2018-09-22 11:00:00'
time_zone = datetime.strptime(''.join(time_zone_str.rsplit(':', 1)), '%Y-%m-%d %H:%M:%S%z')
date_time = datetime.strptime(date_time_str, '%Y-%m-%d %H:%M:%S')
date_time_with_time_zone = pytz.utc.localize(date_time)
print(date_time_with_time_zone == time_zone)
more info on python timezone.

Related

How to solve datetime comparing issue in python

My goal is to compare the datetime now with another datetime given to my program from a json.
After comparing the two datetimes , the result is different from the reality.
The timezone is tz = pytz.timezone('Europe/Athens') which is UTC+3
The json time initially is in string format and after handling I turn the format into datetime
"start_time": "2020-08-11T20:13:00+03:00", the json data
start_time = data.get('start_time')
start_datetime = dateutil.parser.parse(start_time), #datetime format
Now after calling a function in order to check which datetime is bigger than the other, with
the information that the date now is:
2020-08-11 14:51:21.713511+03:00
and start_date is :
2020-08-11 13:00:00+03:00
the function returns True which is wrong since the start_datetime is not bigger than the datetime now.
Here is the function:
def check_start_datetime_bigger_than_now(start_datetime):
tz = pytz.timezone('Europe/Athens')
dts = start_datetime.replace(tzinfo=tz)
dtnow = datetime.now(pytz.timezone('Europe/Athens'))
print(dts)
print(dtnow)
#compare the datetimes
if dts >= dtnow:
return True
else:
return False
Can anyone help me on clarifying what's happening?
before the compare the print of datetimes is giving:
2020-08-11 20:13:00+01:35
2020-08-11 15:06:55.397784+03:00
Why the start date is giving +01:35
You should not use datetime.replace to change the timezone of a datetime instance. It is not smart and cannot handle anything other than simple timezones like UTC. Use datetime.astimezone to convert an existing aware datetime to another timezone, or use tz.localize to add a timezone to a naïve datetime instance.
But really, if start_datetime already has a timezone, you do not need to change its timezone for it to be comparable to dtnow. Datetimes from two different timezones are still comparable. Only a mix of naïve and aware datetimes aren't comparable.

Python string to Django timezone (aware datetime)

TL;DR;
How to convert 2016-01-01 to Django timezone?
Full version:
I receive a query string parameter from a form and I wanna get that string and use it as a datetime filter in Django.
The problem is that when I convert the string to a datetime, it's not making an aware datetime and so I lose a few hours due to timezone different. Maybe I'm losing myself in the formatting, but I'm not being able to do it.
I have pytz, I have USE_TZ = True in my settings as well.
example:
from datetime import date
# Example from what I receive as GET querystring parameter
start_date, end_date = '15-01-2016', '16-01-2016'
DATE_FORMAT = '%Y-%m-%d'
start_date = start_date.split('-')
start_date = date(int(start_date[2]), int(start_date[1]), int(start_date[0]))
sd_filter = start_date.strftime(DATE_FORMAT)
end_date = end_date.split('-')
end_date = date(int(end_date[2]), int(end_date[1]), int(end_date[0]))
ed_filter = end_date.strftime(DATE_FORMAT)
#query
my_list = MyModel.objects.filter(created_at__range=(sd_filter, ed_filter))
the problem lies in the filter. I'm losing a few hours due to timezone from Django settings.
UPDATE: I don't need to convert a datetime.now() to my time. I need to convert a string to datetime.
I know this is old but maybe will be helpful since I got into this situation as well:
What about using make_aware() ?
from datetime import datetime
from django.utils.timezone import make_aware
date = '22-05-2018'
aware = make_aware(datetime.strptime(date, '%d-%m-%Y'))
This will use the currently active timezone (activated by timezone.activate). If no timezone is activated explicitly, it would use the default timezone -- TIME_ZONE specified in settings.py.
You are comparing time-zone unaware Python Date objects with the time-zone aware DateTimeField fields in your database. It is probably more intuitive to use DateTime objects - and these can be made time-zone aware easily as follows:
import datetime
import pytz
start_date = '15-01-2016'
end_date = '16-01-2016'
date_format = '%d-%m-%Y'
unaware_start_date = datetime.datetime.strptime(start_date, date_format)
aware_start_date = pytz.utc.localize(unaware_start_date)
unaware_end_date = datetime.datetime.strptime(end_date, date_format)
aware_end_date = pytz.utc.localize(unaware_end_date)
my_list = MyModel.objects.filter(created_at__range=(aware_start_date, aware_end_date))
This creates unaware_start_date and unaware_end_date DateTime objects using strptime(). It then uses pytz.utc.localize to make the objects time-zone aware (you will need to replace utc with your relevant time-zone).
You can then have time-zone aware DateTime objects - aware_start_date and aware_end_date. Feeding these into your filter should yield the desired results.
from django.utils import timezone
timestamp_raw = timezone.now() #current time, or use whatever time you have
date_format = '%Y-%m-%d %H:%M:%S' #time format day-month-year hour:minutes:seconds
timestamp = timezone.datetime.strftime(timestamp_raw, date_format)
Or Using the new f-string formatter
f"{timezone:%Y-%m-%d %H:%M:%S %p}"

Python Convert time to UTC format

from django.utils import timezone
time_zone = timezone.get_current_timezone_name() # Gives 'Asia/Kolkata'
date_time = datetime.time(12,30,tzinfo=pytz.timezone(str(time_zone)))
Now I need to convert this time to UTC format and save it in Django model. I am not able to use date_time.astimezone(pytz.timezone('UTC')). How can I convert the time to UTC. Also Back to 'time_zone'.
This is a use case when user type time in a text box and we need to save time time in UTC format. Each user will also select his own time zone that we provide from Django timezone module.
Once the user request back the saved time it must be shown back to him in his selected time zone.
These things are always easier using complete datetime objects, e.g.:
import datetime
import pytz
time_zone = pytz.timezone('Asia/Kolkata')
# get naive date
date = datetime.datetime.now().date()
# get naive time
time = datetime.time(12, 30)
# combite to datetime
date_time = datetime.datetime.combine(date, time)
# make time zone aware
date_time = time_zone.localize(date_time)
# convert to UTC
utc_date_time = date_time.astimezone(pytz.utc)
# get time
utc_time = utc_date_time.time()
print(date_time)
print(utc_date_time)
print(utc_time)
Yields:
2014-07-13 12:30:00+05:30
2014-07-13 07:00:00+00:00
07:00:00
right now for me.
set the timezone to UTC in your settings.py. Get the user input of time and timezone in certain format. Suppose you get the user time as 'Jul-7-2014 12:35PM:30' (consider using date input in your html).
from datetime import datetime, timedelta
// convert the time to standard format
user_date = datetime.strptime('Jul-7-2014 12:35PM:30', '%b-%d-%Y %I:%M%p:%S')
user_date_string = user_date.strftime('%Y-%m-%d %H:%M:%S')
// save the time to model with users timezone
// now when user asks back for his time, add the timezone with timedelta
user_date = datetime.strptime(user_date_string, '%Y-%m-%d %H:%M:%S')
user_date = user_date + timedelta(hours = 5, minutes = 30)
// finally display it
print user_data.strftime('%Y-%m-%d %H:%M:%S')
*this is not considering django inbuild datetime functions which returns datetime object for datetime model field. If implemented that it will be more simple

pytz and astimezone() cannot be applied to a naive datetime

I have a date and I need to make it time zone aware.
local_tz = timezone('Asia/Tokyo')
start_date = '2012-09-27'
start_date = datetime.strptime(start_date, "%Y-%m-%d")
start_date = start_date.astimezone(local_tz)
now_utc = datetime.now(timezone('UTC'))
local_now = now_utc.astimezone(local_tz)
I need to find if this is true:
print start_date>local_now
But I get this error.
start_date = start_date.astimezone(local_tz)
ValueError: astimezone() cannot be applied to a naive datetime
I convert utc to tokyo with no issue. I need to make start_date timezone aware ad well in tokyo.
Thanks
For pytz timezones, use their .localize() method to turn a naive datetime object into one with a timezone:
start_date = local_tz.localize(start_date)
For timezones without a DST transition, the .replace() method to attach a timezone to a naive datetime object should normally also work:
start_date = start_date.replace(tzinfo=local_tz)
See the localized times and date arithmetic of the pytz documentation for more details.
You could use local_tz.localize(naive_dt, is_dst=None) to convert a naive datetime object to timezone-aware one.
from datetime import datetime
import pytz
local_tz = pytz.timezone('Asia/Tokyo')
start_date = local_tz.localize(datetime(2012, 9, 27), is_dst=None)
now_utc = datetime.utcnow().replace(tzinfo=pytz.utc)
print start_date > now_utc
is_dst=None forces .localize() to raise an exception if given local time is ambiguous.
If you are using Django Rest Framework you could override the DateTimeField class like:
class DateTimeFieldOverridden(serializers.DateTimeField):
def to_representation(self, value):
local_tz = pytz.timezone(TIME_ZONE)
value = local_tz.localize(value)
return super(DateTimeFieldOverridden, self).to_representation(value)
And you use it like this in your serializer:
date_time = DateTimeFieldOverridden(format='%d-%b-%Y', read_only=True)
Hope this helps someone.

Checking if date is in UTC format

Im using the pytz module to translate a date in America/Los_Angeles timezone to utc by the code below :
TZ = 'America/Los_Angeles'
from = pytz.timezone(TZ)
utc = from.localize(original_date).astimezone(pytz.utc)
Now,i want to test if utc value is actually in UTC format or not. How to do that with pytz or datetime ?
Please Help
Thank You
utc.tzinfo == pytz.utc # returns True if utc in UTC
Example:
now = datetime.datetime.now(pytz.utc)
now.tzinfo == pytz.utc # returns True
now = now.astimezone(pytz.timezone('America/Los_Angeles'))
now.tzinfo == pytz.utc # returns False
The accepted answer will not work for anything else as pytz objects. As pytz is actually pretty bad at doing conversions[1] (e.g. properly doing daylight savings etc) it is probably better to do a cross-implementation check.
now = datetime.datetime.now(pytz.utc)
if now.tzinfo:
now.utcoffset().total_seconds() == 0 # returns true
[1] https://pendulum.eustace.io/blog/a-faster-alternative-to-pyz.html
You can do it simply like this:
from datetime import datetime, timezone
lunch_time = datetime.now(timezone.utc)
if lunch_time.format('%Z') == 'UTC':
print("Eat food")
This will also work with a naive time object because lunch_time.format('%Z') will return an empty string. This method will also work with pytz or any other module because you are simply checking the timezone as string not as an object (the accepted answer won't work with the above timezone module case, only pytz).
from datetime import datetime
import pytz
dinner_time = datetime.now(pytz.timezone('UTC'))
if dinner_time.format('%Z') == 'UTC':
print("Hungry!")
Note: This will also eliminate the possibility of the timezone being GMT timezone rather than UTC timezone. The other answer now.utcoffset().total_seconds() == 0 will be True for GMT which may not be what you want.
The %Z specifier is documented here:
https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior

Categories

Resources