Django datetimefield timezone aware CET - python

I saw this post Is Django corrupting timezone-aware DateTimeField when saving it to the Database? but it specifically uses pytz and mysql and what not where I don't use pytz and use SQLite (incase it might have an impact).
I have the following model
class ScheduleItem(models.Model):
work_date = models.DateTimeField('Work date')
And I insert data as follows:
from isoweek import Week
from dateutil import parser
from django.utils import timezone
def foo()
year = 2016 #hardcoded for example purpose
wknr = 2 #hardcoded for example purpose
dateObj = parser.parse(Week(year, wknr).day(0).isoformat() + " 00:00:00")
print(dateObj) # 2016-01-11 00:00:00 as expected
final = timezone.make_aware(dateObj)
print(final) # 2016-01-11 00:00:00+01:00 as expected
return final
workdate = foo()
si = ScheduleItem(work_date=workdate)
si.save()
The print statements give me the right output, however once I look in the database (SQLite) I see 2016-01-10 23:00:00
My django settings say
TIME_ZONE = 'CET'
USE_TZ = True
Retrieving the data I get:
datetime.datetime(2016, 1, 10, 23, 0, tzinfo=<UTC>)
Why is it storing the data in another format then I specify and why if Django is set to be timezone aware do I get a UTC timezone back? I mean before insertion the datetime object says: datetime.datetime(2016, 1, 11, 0, 0, tzinfo=<DstTzInfo 'CET' CET+1:00:00 STD>)
update -
I found a work around in the meantime by setting TIME_ZONE on the database as described in the Django documentation here. This gives me the right timezone/date in the database, but according to that documentation I shouldn't need it because my DB is managed by Django
This allows interacting with third-party databases that store datetimes in local time rather than UTC. To avoid issues around DST changes, you shouldn’t set this option for databases managed by Django.
It is still unclear to me why Django does convert a datetime object with a CET timezone to UTC when storing it in the database, but isn't smart enough to convert it back to CET when retrieving.

Django uses UTC time internally. TIME_ZONE will be used "for your views and models" (https://docs.djangoproject.com/en/1.9/ref/settings/#std:setting-TIME_ZONE)
You started with 2016-01-11 00:00 CET, which is 2016-01-10 23:00 UTC! Your datetime was correctly saved to the database and later restored, so everything is working as expected.

Related

How to Convert a Date to Django Timezone Aware Datetime

I am trying to convert a DateTime with the UTC time zone to Django datetime that respects the time zone of my date.
Here is my settings.py:
TIME_ZONE = 'US/Pacific'
USE_TZ = True
Here is the date I am trying to convert to the right time zone for django: datetime.datetime(2020, 2, 20, 8, 55, 48, 846000)
I used the make_aware function provided by Django but I can see the date isn't converted to the time zone in my settings.py when I save the Django Modal with a DateTime field
from django.utils.timezone import make_aware
Django doc
When time zone support is enabled (USE_TZ=True), Django uses time-zone-aware datetime objects. If your code creates datetime objects, they should be aware too. In this mode, the example above becomes:

Django DATETIME_FORMAT incorrect (by one year) for specific dates

For a client I am storing event logs in a postgres database. Each event has a date that is stored as a timestamp with time zone in postgres. The date is automatically populated using Djangos' built in auto_now_add attribute in the model definition.
In settings.py I have set the following:
TIME_ZONE = 'UTC'
USE_TZ = True
DATETIME_FORMAT = 'd/m/o H:i:s'
DATE_FORMAT = 'd/m/o'
TIME_FORMAT = 'H:i:s'
SHORT_DATE_FORMAT = 'd/m/o'
SHORT_DATETIME_FORMAT = 'd/m/o H:i'
I have lots of experience with this mechanism and it never caused problems until now. The client actually pointed out that there were a number of entries with a date lying in the future (impossible for event log).
After checking the front-end as well as the admin I can verify that there are invalid dates e.g.(30/12/2020 and 31/12/2020) appearing (all invalid dates are in this range, other dates before and after are displaying correctly). When I check the database (Postgres) I can verify that the dates stored are actually both in 2019 having the following timestamp values: 2019-12-30 10:23:07.451674+00 and 2019-12-31 08:12:26.635693+00.
The template in use in the frontend uses {{ log_item.date }} to display the date.
What am I missing? Any hints appreciated.
Use DATE_FORMAT = 'd/m/Y' instead of DATE_FORMAT = 'd/m/o'. When you using o formating for year it's return week-numbering year. Since 30 and 31 december was in first week of 2020 year, it give you 2020.

Display a time using a given timezone in Django

I'm developing a Django app for logging dives and each dive has a datetime and a timezone in it. I'm using the django-timezone-field app for the timezone.
class Dive(models.Model):
...
date_time_in = models.DateTimeField(default=timezone.now)
timezone = TimeZoneField(default=timezone.get_current_timezone_name())
So the user is able to enter a datetime string ("2016-07-11 14:00") and select a timezone ("Asia/Bangkok" - UTC+0700), I then set the timezone of the datetime to the one given in my view like this:
def log_dive(request):
if request.method == 'POST':
form = DiveForm(request.POST)
if form.is_valid():
dive = form.save(commit=False)
date = dive.date_time_in
date = date.replace(tzinfo=None)
dive.date_time_in = dive.timezone.localize(date)
dive.save()
The database then stores the datetime as UTC in the database (SELECT statement gives it in my local timezone):
# SELECT date_time_in, timezone FROM divelog_dive ORDER BY number DESC;
date_time_in | timezone
------------------------+------------------
2014-07-11 17:00:00+10 | Asia/Bangkok
Now there are two things I'm struggling with:
1) I want to display the dates in the given timezone, however I can't seem to stop it defaulting to the TIME_ZONE setting.
2) If the user edits the record, the time displayed in the edit field should be the one they originally entered (14:00), instead it's showing it in the current timezone (17:00).
Check your timezone setting in settings.py
Do you have USE_TZ = true in your settings file? If you created your app using the djangoadmin-startproject command, it is set by default.
Also, I struggled with timezones at my last job but found that using pytz really helped. Have you tried that package yet?
EDIT: Ok man I may be way off, but since noone else has answered and I feel the timezone struggle, here is something I noticed...
You are replacing the date object with tz_info=None, but wouldn't you want to instead replace that with the timezone from the database? So you would get that timezone and do a replace using the valid format (tzinfo=blah...)?
Like I said I may be way off but if that helps there you go.
Sorry, I don't think I explained my problem very well. I finally figured this out, so I'll answer my own question.
1) turned out to be easy, Django have a template tag for displaying times in a given zone:
{{ dive.date_time_in|timezone:dive.timezone|date:"Y-m-d H:i e" }}
For 2), I came across [1] which lead me to this solution: In the view, after getting the object from the database, I use astimezone(...) to convert the date value (which the DB stores as UTC) into the given timezone. I then use replace(tzinfo=None) to make it naive and then it displays correctly on my form.
def edit_dive(request, dive_id=None):
dive = None
if dive_id != None:
dive = get_object_or_404(Dive, pk=dive_id)
local_date = dive.date_time_in.astimezone(timezone(str(dive.timezone)))
dive.date_time_in = local_date.replace(tzinfo=None)
[1] http://www.saltycrane.com/blog/2009/05/converting-time-zones-datetime-objects-python/

django postgres datetime field to python datetime

I have the following model class
class Transaction(models.Model):
quantity = models.IntegerField(default=0)
sell_time = models.DateTimeField()
When I fetch "sell_time" from the model, I am getting datetime in the following format
2014-10-01 08:09:46.251563+00:00
my question is, if it is not in the format like
year-month-day hour:minutes:seconds
how can I convert to python datetime object like
datetime.datetime(2014, 10, 1, 08, 09, 46, 540535)
many thanks
Did you print it? If you print a datetime object, it is serialized to a string but it is a datetime. You can use it as any other datetime.
You are seeing that because you did not set the correct time zone. Use the UTC time and then you can format .strftime("format") the time accordingly to each locale, you can install pytz and enable it in the settings to handle all the hustle. Always use UTC datetime object because then you can get what ever time you want knowing the zone your user is in. Documentation from Django

save time zone in Django Models

I am creating a form in Django. I have to put a input type field, which only stores the timezone in database(which will be chosen by a user from a drop Down list at form). I am not able to find out any approach to create this timezone model and how it will return the local time according to saved timezone. I choose following field but it stores also minute hours and second also
timestamp = models.DateTimeField()
Drop down list should be in form of :
...
GMT +5:30
GMT +6:00...and so on.
I think the above answers are all correct, but I leave mine here as an simple example...
class UserProfile(models.Model):
import pytz
TIMEZONES = tuple(zip(pytz.all_timezones, pytz.all_timezones))
# ...
timezone = models.CharField(max_length=32, choices=TIMEZONES,
default='UTC')
# ...
Neither django nor python provide a set of timezones for you to use.
For that, you will need an additional module like pytz. You can get a list of all timezones like this:
>>> import pytz
>>> pytz.all_timezones ['Africa/Abidjan', 'Africa/Accra', 'Africa/Addis_Ababa', 'Africa/Algiers', 'Africa/Asmara',
'Africa/Asmera'....
You can their store the timezone name in a CharField.
By the way, choosing a timezone by "GMT +6:00" is not a good idea. For example, EST is usually 5 hours behind GMT, but for 2 weeks around daylight savings time changes, the offset is different. Also, at some times of year someone in Queensland and someone in New South Wales both have the same GMT offset, but because NSW has DST and Queensland doesn't, for half the year their GMT offsets are different. The only safe way to list timezones is to list the actual geographic timezones.
django-timezone-field is an app that handles this nicely.
The way I do this is using pytz valid timezone names. I adjusted my list to reflect only the ones I need, i.e.
TIMEZONES = (
'Canada/Atlantic',
'Canada/Central',
'Canada/Eastern',
'Canada/Mountain',
'Canada/Pacific',
)
I then have a location class which sets the timezone as a Char Field as such:
class Location(models.Model):
....
time_zone = models.CharField(max_length=100, blank=True, null=True, choices=TIMEZONES) # 64 min
....
Notice I set blank & null to True to make the field optional. Take a look at django-timezone-field fields.py for further ideas.
To use this in my code with pytz, I import timezone:
from pytz import timezone
import datetime
from locations.models import Location # my object that has the time_zone field
loc = Location.objects.get(pk=1) #get existing location or your object that has time_zone field
utc = pytz.utc
some_utc_date = datetime.datetime(2002, 10, 27, 6, 0, 0).replace(tzinfo=utc) #tz aware
some_date.astimezone(timezone(loc.time_zone))
Replace datetime.datetime(2002, 10, 27, 6, 0, 0) with the datetime field that corresponds to your location or specific object that has the time_zone field. In my case I store all my date fields in UTC format in a MongoDB collection. When I retrieve the data and want to create human readable output, I use the above method to show the date in the output. You can also create a custom tag to handle this in templates. See pytz doc for more details.
If you are migrating from pytz to zoneinfo:
try:
import zoneinfo
except ImportError:
from backports import zoneinfo
class UserProfile(models.Model):
TIMEZONE_CHOICES = ((x, x) for x in sorted(zoneinfo.available_timezones(), key=str.lower))
timezone = models.CharField("Timezone", choices=TIMEZONE_CHOICES, max_length=250, default='Etc/GMT+2')

Categories

Resources