Django - 'datetime.date' object has no attribute 'tzinfo' - python-2.7

Here is my code that I use to make the datetime timezone aware. I tried to use the recommended approach from the Django docs.
tradeDay = day.trade_date + timedelta(hours=6)
td1 = pytz.timezone("Europe/London").localize(tradeDay, is_dst=None)
tradeDay = td1.astimezone(pytz.utc)
I get the tz_info error. How can I datetime a tz_info attribute?
USE_TZ = True in settings.py

It looks as though day.trade_date is actually a datetime.date object rather than a datetime.datetime so trying to localize it will cause an error.
Try converting day.trade_date to a datetime.datetime first using combine(). You can then add 6 hours and localize it.
# Convert to a datetime first
tradeDate = datetime.combine(day.trade_date, datetime.min.time())
# Now the date can be localized
tradeDay = tradeDate + timedelta(hours=6)
td1 = pytz.timezone("Europe/London").localize(tradeDay, is_dst=None)
tradeDay = td1.astimezone(pytz.utc)

Related

Django: Trying to add 'SHORT_TIME_FORMAT' somehow changes time zone to Chicargo

I required some extra date/time formats in addition to ones Django ships with, sI created these new formats:
SHORT_TIME_FORMAT
FILE_DATETIME_FORMAT
ISO8601_DATETIME_FORMAT.
So that I could use them in templates like this:
{{ value|date:"SHORT_DATE_FORMAT" }}
And In code like this:
from django.utils import formats
formats.date_format(value, `SHORT_TIME_FORMAT`)
I created the following code in utils/time/formats.py:
from collections import ChainMap
from django.utils import formats
DJANGO_DATETIME_FORMATS = {
'DATETIME_FORMAT': 'd M Y, H:i',
'DATE_FORMAT': 'j M Y',
'TIME_FORMAT': 'H:i:s',
'SHORT_DATETIME_FORMAT': 'Y-m-d H:i:s',
'SHORT_DATE_FORMAT': 'Y-m-d',
'MONTH_DAY_FORMAT': 'd M',
'YEAR_MONTH_FORMAT': 'Y M',
}
EXTRA_DATETIME_FORMATS = {
'SHORT_TIME_FORMAT': 'H:i',
'FILE_DATETIME_FORMAT': 'Y-m-d H.i.s',
'ISO8601_DATETIME_FORMAT': 'c', # Compatible with Javascript passing
}
def set_formats(globals_dict):
"""Returns a set of datetime formats for use across the whole project
Contains a union of the default formats along with the additional ones.
To add a new format, one has to perform the following two actions:
1. Add the name of the format to formats.FORMAT_SETTINGS
2. Add a variable with the same name as the variable to the settings.py
file with the value assigned to the required format.
globals_dict is the globals from the settings.py file
"""
formats.FORMAT_SETTINGS = frozenset(formats.FORMAT_SETTINGS | EXTRA_DATETIME_FORMATS.keys())
all_formats = ChainMap(DJANGO_DATETIME_FORMATS, EXTRA_DATETIME_FORMATS)
for setting, value in all_formats.items():
globals_dict[setting] = value
However when I add it to my settings.py file as so:
# settings.py
from utils.time.formats import set_formats
set_formats(globals())
My timezone changes to Chicargo, even though in settings.py I have:
TIME_ZONE = 'Africa/Johannesburg'
After research I found out that Django's default timezone is Chicargo, which is 7 Hrs behind me (I am UTC+02).
I can test it like this:
$ python manage.py shell
> from django.utils import timezone
> from django.conf import settings
> print(f"The settings.py TIME_ZONE value is: {settings.TIME_ZONE=}")
The settings.py TIME_ZONE value is: settings.TIME_ZONE='Africa/Johannesburg'
> print("Using Django local time, now is:")
Using Django local time, now is:
> print(timezone.localtime())
2022-07-27 20:54:35.293958+02:00
If I don't use set_formats, the datetime is correctly in my local time, if I add my set_formats function, then datetime is 7 Hrs off, and in the admin interface and other date/times on my website are all 7 hours off, even though settings.TIME_ZONE reports Africa/Johannesburg.
this code used to work, but at some point recently stopped working. I did change from pytz to zoneinfo, so that might be the reason, but I was a little bit sure it worked after the change.
Why is the timezone changing? How can I add a date/time format so it can be used in templates and in code with the django.utils.formats.date_format function?

Django/PostgreSQL custom TimeRangeField

I'm trying to create a TimeRangeField but am having some problems saving to the database (PostgreSQL version 9.5.23).
from psycopg2.extras import DateTimeRange
from django import forms
from django.contrib.postgres.forms import BaseRangeField
from django.contrib.postgres.fields.ranges import RangeField
from django.db import models
class TimeRangeFormField(BaseRangeField):
default_error_messages = {'invalid': 'Enter two valid times.'}
base_field = forms.TimeField
range_type = DateTimeRange
class TimeRangeField(RangeField):
base_field = models.TimeField
range_type = DateTimeRange
form_field = TimeRangeFormField
def db_type(self, connection):
return 'tsrange'
The error when saving seems pretty self explanatory - pretty sure I need to cast the time object to a string but I have no idea how to do that.
function tsrange(time without time zone, time without time zone, unknown) does not exist
LINE 1: ...('b9925dd3-d4a8-4914-8e85-7380d9a33de5'::uuid, 1, tsrange('1...
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
Here's the SQL:
INSERT INTO "fulfillment_deliveryslot"
(
"uuid",
"day_id",
"window",
"max_orders",
"is_active"
)
VALUES
(
'b9925dd3-d4a8-4914-8e85-7380d9a33de5'::uuid,
1,
tsrange('12:38:31'::time, '13:00:00'::time, '[)'),
5,
true
)
returning "fulfillment_deliveryslot"."id"
The issue is here: time without time zone. You are using tsrange and that needs a timestamp:
https://www.postgresql.org/docs/9.5/rangetypes.html
tsrange — Range of timestamp without time zone
In other words you are passing a time into something that needs a timestamp.

What does the Django "expected string or buffer" error indicate?

I've been stuck with this error for quite a while now and I just can't figure out what it means. It occurs when I try to save an object to my mysql database. Any ideas?
Thanks for the help!
Just ran into the same problem and resolved it. I instantiated a form like this:
data = {'date' : datetime.now} #this is the problem
form = MyForm(data)
That form was saved later on and django tried to set 'date' in the model. But datetime.now refers to a function rather than a date, obviously. What I wanted to do was datetime.now()
Maybe this helps anybody running into this in future.
This probably means that Python is trying to execute code which is expecting a certain datatype (bool, string, int, etc.), but an other, incorrect, datatype is provided.
In my case it was appears when I use "time" library to convert date string to datetime object. I just use "datetime.strptime" instead of "time.strptime"and problem vanished.
The datetime validator in django is in the file:
/path/to/project/venv/lib/python2.7/site-packages/django/utils/dateparse.py
or in the site-packages of your current python interpreter.
Have a look there to see the regular expressions. In my case, the way to solve it was:
ended=datetime.fromtimestamp(time.time())
other=datetime.fromtimestamp(time.time())
# in the model:
ended = models.DateTimeField(blank=True, null=True) # or
other = models.DateTimeField(auto_now_add=False, blank=True)
both working.
'expiration' is this field
expiration = models.DateTimeField(default=7)
And code with error was this one:
ex = timedelta(minutes=expiration)
authobj, created = cls.objects.update_or_create(
operator=operator,
defaults={'transport':transport,'token':cls.generate_key(40),'expiration':ex}
)
And it was solved by setting it like this (instead of timedelta, a date)
ex = datetime.now() + timedelta(minutes=expiration)
authobj, created = cls.objects.update_or_create(
operator=operator,
defaults={'transport':transport,'token':cls.generate_key(40),'expiration':ex}
)
str(yourvar)
Ou can convert sting your variables.

Why will these strings not be quoted by psycopg2 for the query?

Writing an app with django, using the psycopg2 engine. It doesn't always seem to want to quote my strings. Here is a test case:
>>> from pypvs.search.models import Addr2zip
>>> kwargs = {
... 'street_name__iexact': 'Common Ground',
... 'state_id__iexact': 'MT',
... }
>>> addrMatch = Addr2zip.objects.extra(
... where = ['ctystate.zip5 = addr2zip.zip5 AND ctystate.city_name = \'%s\'' % 'Philipsburg'],
... tables = ['ctystate', 'addr2zip']
... ).filter(**kwargs).order_by('zip5', 'street_name', 'primary_address_low', 'secondary_address_low')
>>> print addrMatch.query
SELECT "addr2zip"."addr2zip_id", "addr2zip"."zip5", "addr2zip"."zip4_low", "addr2zip"."zip4_high", "addr2zip"."street_direction", "addr2zip"."street_name", "addr2zip"."street_suffix", "addr2zip"."street_post_direction", "addr2zip"."primary_address_low", "addr2zip"."primary_address_high", "addr2zip"."primary_address_parity", "addr2zip"."secondary_address", "addr2zip"."secondary_address_low", "addr2zip"."secondary_address_high", "addr2zip"."secondary_address_parity", "addr2zip"."state_id", "addr2zip"."county_code", "addr2zip"."municipality_key", "addr2zip"."urbanization_key", "addr2zip"."record_type" FROM "addr2zip" , "ctystate" WHERE (ctystate.zip5 = addr2zip.zip5 AND ctystate.city_name = Philipsburg AND UPPER("addr2zip"."state_id"::text) = UPPER(MT) AND UPPER("addr2zip"."street_name"::text) = UPPER(Common Ground) ) ORDER BY "addr2zip"."zip5" ASC, "addr2zip"."street_name" ASC, "addr2zip"."primary_address_low" ASC, "addr2zip"."secondary_address_low" ASC
What could be the reason that these strings are not quoted? For instance, 'Common Ground':
AND UPPER("addr2zip"."street_name"::text) = UPPER(Common Ground)
Not sure if the problem is in my implementation, psycopg2, or the django ORM. I'd appreciate any ideas.
str(query) only returns an approximative representation of the query. Are you trying to pass it to the database?
The query issued with iexact seems correct with Django 1.2.3. The above would result in WHERE UPPER("addr2zip"."street_name"::text) = UPPER(E'Common Ground'). Which version are you using?
To get the query to be executed, use something like:
from django.db import DEFAULT_DB_ALIAS
queryset.query.get_compiler(DEFAULT_DB_ALIAS).as_sql()
But you just pasted it like that yourself:
where = ['ctystate.zip5 = addr2zip.zip5 AND ctystate.city_name = %s' % 'Philipsburg'],
so you got query string constructed with syntax error:
AND ctystate.city_name = Philipsburg

Django: Use of DATE_FORMAT, DATETIME_FORMAT, TIME_FORMAT in settings.py?

I would like to globally (through my entire site, admin and front-end) adjust the way dates and time are displayed to my likings, but I cannot figure out what is going on with the DATE_FORMAT, DATETIME_FORMAT and TIME_FORMAT variables in settings.py.
In this question it says that the settings are ignored. The question is over a year old though. In the Django documentation it says they can be used when you have USE_L10N = True and apparently something changed in Django 1.2. According to this however there might be a bug.
I am currently using Django 1.2 and when I have USE_L10N = True it just ignores the date(time) format in settings.py. When I have USE_L10N = False it also seems to ignore them.
Is there a way to globally customize the date and time display? Or should I create my own custom formats file as Karen suggests in the Django Users Google Group post?
Had same problem, solution is simple and documented. Whenever you render a date, you need to specify you want the template to render it as a date/time/short_date/datetime (e.g., {{ some_date_var | date }} and then it will render it as specified with DATE_FORMAT in your settings.py
Example:
>>> from django.conf import settings # imported to show my variables in settings.py
>>> settings.DATE_FORMAT # - showing my values; I modified this value
'm/d/Y'
>>> settings.TIME_FORMAT
'P'
>>> settings.DATETIME_FORMAT
'N j, Y, P'
>>> from django.template import Template, Context
>>> from datetime import datetime
>>> c = Context(dict(moon = datetime(1969, 7, 20, 20, 17, 39))) # Create context with datetime to render in a template
>>> print c['moon'] # This is the default format of a printing datetime object
1969-07-20 20:17:39
>>> print Template("default formatting : {{ moon }}\n"
"use DATE_FORMAT : {{ moon|date }}\n"
"use TIME_FORMAT : {{ moon|time }}\n"
"use DATETIME_FORMAT: {{ moon|date:'DATETIME_FORMAT' }}\n"
"use SHORT_DATETIME_FORMAT: {{ moon|date:'SHORT_DATETIME_FORMAT' }}"
).render(c)
default formatting : 1969-07-20 20:17:39
use DATE_FORMAT : 07/20/1969
use TIME_FORMAT : 8:17 p.m.
use DATETIME_FORMAT: July 20, 1969, 8:17 p.m.
use SHORT_DATETIME_FORMAT: 07/20/1969 8:17 p.m.
This makes sense; e.g., the template needs to know whether it should use the DATE_FORMAT or the SHORT_DATE_FORMAT or whatever.
Searching through the source shows that DATETIME_FORMAT, etc., are only used when django.utils.formats.localize() is called, and that only seems to be called when django.template.VariableNodes are rendered.
I'm not sure when exactly VariableNodes are used in template rendering, but I would guess that if you have settings.USE_L10N turned on and you have a VariableNode, it will be localized.
localize looks like this:
def localize(value):
"""
Checks if value is a localizable type (date, number...) and returns it
formatted as a string using current locale format
"""
if settings.USE_L10N:
if isinstance(value, (decimal.Decimal, float, int)):
return number_format(value)
elif isinstance(value, datetime.datetime):
return date_format(value, 'DATETIME_FORMAT')
elif isinstance(value, datetime.date):
return date_format(value)
elif isinstance(value, datetime.time):
return time_format(value, 'TIME_FORMAT')
return value
To answer your question, I'd probably write a quick context processor that called localize() on everything in the context.
You can override DATE_FORMAT, DATETIME_FORMAT, TIME_FORMAT and other date/time formats when USE_L10N = True by creating custom format files as described in Django documentation.
In summary:
Set FORMAT_MODULE_PATH = 'yourproject.formats' in settings.py
Create directory structure yourproject/formats/en (replacing en with the corresponding ISO 639-1 locale code if you are using other locale than English) and add __init__.py files to all directories to make it a valid Python module
Add formats.py to the leaf directory, containing the format definitions you want to override, e.g. DATE_FORMAT = 'j. F Y'.
Example from an actual project here.
A late response, but hopefully this will help anyone else searching for this.
By setting USE_L10N = True in your settings, Django looks for locale specific formats, giving them precedence over non-locale related settings.
The solution: (to display 30/12/2017 on a DateField)
from django.conf.locale.en import formats as en_formats
en_formats.DATE_FORMAT = "%d/%m/%Y"
and for inputs (to accept 30/12/2017 or 30-12-2017)
en_formats.DATE_INPUT_FORMATS = ['%d/%m/%Y', '%d-%m-%Y']
Reference: https://mounirmesselmeni.github.io/2014/11/06/date-format-in-django-admin/
*tested on Django==1.10.7