TIME ZONE DJANGO SAVE DATETIMEFIELD

777 views
Skip to first unread message

Serena

unread,
Aug 31, 2015, 4:49:07 PM8/31/15
to Django users
Hello is the first time I write on the list, I have little time learning Django and presented me a drawback. I have a model called Bill, which has a field called date of sale, and I need to store the date and time of the sale but the client time, and now it is keeping the server time. As I keep the date and time correctly in the model?
I have some variables in established settings:

USE_TZ = True
TIME_ZONE = 'America / Caracas'

/********************models.py   ***********/

class Factura(models.Model):
      fecha = models.DateTimeField()

James Schneider

unread,
Aug 31, 2015, 5:09:16 PM8/31/15
to django...@googlegroups.com
Have you validated that the time being stored is incorrect? I'm
willing to bet that the date and time in the database is actually
being stored in UTC, but the output in the templates is being
displayed with the undesired offset. Check out this page on handling
output of DateTime fields:

https://docs.djangoproject.com/en/1.8/topics/i18n/timezones/#time-zone-aware-output-in-templates

https://docs.djangoproject.com/en/1.8/topics/i18n/timezones/#default-time-zone-and-current-time-zone

Actually that whole page is a good read. Basically you need to ensure
that your DateTime is being saved in UTC (or at the very least,
everything being stored has an offset attached to it so that the
correct date/time/timezone can be calculated). Django is probably
already doing that, but you'll need to set the current time zone for a
particular user so that the templates output the right DateTime.

-James

Serena

unread,
Aug 31, 2015, 5:58:03 PM8/31/15
to Django users
No doubt that django is acting correctly. I understand what you tell me about it, then I know I can do conversions to the date shown in the templates have my time zone, but it is not what I want. Because when I do queries on bills for closing Z does not work, even when I have to close and tell me which corresponds to another day. by the same gap that you commented.
If you do the cierreZ day: 2015/08/30 19:00 (client time), with the gap that I have tells me the date is 2015/08/31 1:00 (server time), that is already being done the next day, which is incorrect.

Ah, excuse my English.

James Schneider

unread,
Aug 31, 2015, 7:11:00 PM8/31/15
to django...@googlegroups.com


On Aug 31, 2015 2:58 PM, "Serena" <sereni...@gmail.com> wrote:
>
> No doubt that django is acting correctly. I understand what you tell me about it, then I know I can do conversions to the date shown in the templates have my time zone, but it is not what I want. Because when I do queries on bills for closing Z does not work, even when I have to close and tell me which corresponds to another day. by the same gap that you commented.
> If you do the cierreZ day: 2015/08/30 19:00 (client time), with the gap that I have tells me the date is 2015/08/31 1:00 (server time), that is already being done the next day, which is incorrect.
>

Is it possible that is correct? If you are saying that 2015/08/30 19:00 [server timezone] is the same date/time as 2015/08/31 1:00 [other timezone], then what you are seeing appears to be correct. Without actual offsets to work with and what you were expecting, it is a bit difficult to say for sure.

Can you answer the following?

  • How are you controlling the user timezone for display purposes?
  • Are the users entering naive date/times (with no timezone specifier) in forms, and is the server [possibly incorrectly] assuming that the data entered is in the servers' timezone, when the user intended that the date/time is their own local time? Or is the timezone selector in your form being ignored?
  • Have you validated that the server is storing the correct date/times in the database, either as the default timezone or (preferably) as the correct UTC? For example, 2015/08/30 19:00 in America/Caracas -4:30 is actually stored in the database as 2015/08/30 23:30 UTC. 
  • When you are displaying a bill, what time was entered by the user (including TZ), what time was stored in the database, what time is being displayed, and what were you expecting to be displayed?

At this point it is a matter of troubleshooting what you are putting in vs. what you are getting out of the system, and figuring out where the breakdown is. Dates/times are not easy to deal with, and all of us have probably run into a similar issue at some point.

> Ah, excuse my English.
>

No worries, you're doing pretty well.

-James

Serena

unread,
Aug 31, 2015, 8:37:20 PM8/31/15
to Django users
I understand what you say, when I started working with Django I thought exactly the same, it is more convenient that the date is saved with a time zone and then the conversions are made, and also knew that the gap was precisely because those 4:30 in my timezone, but the problem is not to show the data to the user, but as I make my queries so that the filtered data is correct, since my dates are obvious questions, I'll put my concern examples:

The date does not place the customer, we do not control them. Each time an invoice is added, the date placed in my controller using:
   >> factura = Factura()
   >> factura.fecha = timezone.now ()
   >> factura.save ()

For example I consult my templates from sales day, and was shown to the customer in my template:
     1. Add invoice number 6 on August 31, 2015 at 18:48
     2. Add Invoice Number 7 on August 31, 2015 at 18:48
     3. Add Invoice Number 8 on August 31, 2015 at 19:32

But Database I remain as follows:
     1. Invoice number 6 Date: 08/31/2015 23:18:07
     2. Invoice number 6 Date: 08/31/2015 23:31:25
     3. Invoice number 6 Date: 01/09/2015 00:02:17


So if I want to consult the invoices (today August 31, 2015):

 >> Factura.objects.filter (fecha__startswith = timezone.now (). Date ())
 
only leave me the invoice number 6 and number 7 because the number 8 corresponds to another day.

Is there any way of making the request and that django conversion made directly (with some function)? or I have to do the conversion?

I hope I was more explicit. And much I appreciate your time.

James Schneider

unread,
Sep 1, 2015, 2:24:36 AM9/1/15
to django...@googlegroups.com
On Mon, Aug 31, 2015 at 5:37 PM, Serena <sereni...@gmail.com> wrote:
> I understand what you say, when I started working with Django I thought
> exactly the same, it is more convenient that the date is saved with a time
> zone and then the conversions are made, and also knew that the gap was
> precisely because those 4:30 in my timezone, but the problem is not to show
> the data to the user, but as I make my queries so that the filtered data is
> correct, since my dates are obvious questions, I'll put my concern examples:
>
> The date does not place the customer, we do not control them. Each time an
> invoice is added, the date placed in my controller using:
> >> factura = Factura()
> >> factura.fecha = timezone.now ()
> >> factura.save ()
>
> For example I consult my templates from sales day, and was shown to the
> customer in my template:
> 1. Add invoice number 6 on August 31, 2015 at 18:48
> 2. Add Invoice Number 7 on August 31, 2015 at 18:48
> 3. Add Invoice Number 8 on August 31, 2015 at 19:32
>
> But Database I remain as follows:
> 1. Invoice number 6 Date: 08/31/2015 23:18:07
> 2. Invoice number 6 Date: 08/31/2015 23:31:25
> 3. Invoice number 6 Date: 01/09/2015 00:02:17
>

This helped my understanding immensely. Thank you.

You know what is odd though, the DB entries for 2 and 3 seem to be
using a different format (MM/DD/YYYY and DD/MM/YYYY respectively). It
may be right if the data for 3 is really from January, though.

>
> So if I want to consult the invoices (today August 31, 2015):
>
> >> Factura.objects.filter (fecha__startswith = timezone.now (). Date ())
>
> only leave me the invoice number 6 and number 7 because the number 8
> corresponds to another day.


Ahh, there's the problem. You are performing a string match against
the beginning of the date string, not an actual comparison of dates
and times (ie is 04:00 later than 05:00, etc.). This is both slow, and
inaccurate, as you've experienced. Django will perform a numerical
comparison of the datetime's behind the scenes within the database,
which should yield faster and accurate results.

>
> Is there any way of making the request and that django conversion made
> directly (with some function)? or I have to do the conversion?
>
> I hope I was more explicit. And much I appreciate your time.

Django will do the hard stuff, but you need to feed it the right
information in order to do so. My understanding is that you want to
see all of the bills (class Factura) that have a date falling in
between 00:00 and 23:59 (a 24 hour period for 1 day) in your local
timezone (or more specifically, the default timezone of the server).

I'm no timezone expert, but here is how I came up with performing the query:

import datetime
from django.utils import timezone

# date today, default (server) timezone
d = timezone.localtime(timezone.now(),
timezone=timezone.get_default_timezone()).date()

# grab the date, stripping away the current time
naive_start_date = datetime.datetime(d.year, d.month, d.day)

# create a timezone aware datetime object with a time of 00:00
(beginning of the day) by only providing the date
local_start_datetime = timezone.make_aware(naive_start_date,
timezone=timezone.get_default_timezone())

# create a timedelta object of 1 day
one_day = datetime.timedelta(days=1)

# calculate 1 day in the future from the start datetime
local_end_datetime = local_start_datetime + one_day

# query, use >= for start time since we start at 00:00 and < since
we use 00:00 of next day
bills = Factura.objects.filter(fecha__gte=local_start_datetime,
fecha__lt=local_end_datetime)


Most of this is just generating a date for the right
calendar/numerical day (based on the local timezone) and creating a
datetime for midnight (morning) of that day. The rest is pretty
simple. Hopefully this also accounts for DST and other timezone
anomalies beyond my comprehension.

I would also highly recommend that you install the pytz module. Django
will use it if it is available, and will make your timezone handling
even more accurate. (See #3
https://docs.djangoproject.com/en/1.8/topics/i18n/timezones/#faq )

Hopefully you can just copy/paste that into your shell and it'll come
up with the right results. Seems to work on my local machine.
Obviously if you want a different day you'll just need to come up with
a different naive_start_date.

Well, I learned a lot answering your question, hope you do too, lol.

-James

Serena

unread,
Sep 1, 2015, 9:10:24 PM9/1/15
to Django users
Thank you very much, now if I work. And besides I also served to enhance most of my consultations with dates. It is strange that I have not tried that way, if a large part of my consultations I had done that way, well, the important thing is that it works and I understand the reason. Thanks for the time spent and probably will call me here more often, either working or asking.
Reply all
Reply to author
Forward
0 new messages