英文:
Why is timezone.now showing a future date when being applied as a default value to DateField in django
问题
以下是我项目中相关的设置:
settings.py
TIME_ZONE = "US/Mountain"
USE_TZ = True
models.py
(使用timezone.now
)
class Submission(models.Model):
date_created = models.DateField(
default=timezone.now,
blank=True,
)
datetime_created = models.DateTimeField(
default=timezone.now,
)
如果我在2023年03月01日的下午5点MST创建一个Submission
,那么以下是我得到的值:
date_created
: "2023-03-02"datetime_created
: "2023-03-01 17:00:00-07:00"
为什么date_created
会使用后续日期的日期?
英文:
Here are the relevant settings in my project:
settings.py
TIME_ZONE = "US/Mountain"
USE_TZ = True
models.py
(using timezone.now
)
class Submission(models.Model):
date_created = models.DateField(
default=timezone.now,
blank=True,
)
datetime_created = models.DateTimeField(
default=timezone.now,
)
If I create a Submission
at 5PM MST on 03/01/2023 these are the values I get:
date_created
: "2023-03-02"datetime_created
: "2023-03-01 17:00:00-07:00"
Why would date_created
be using the date of the following date?
答案1
得分: 1
我认为发生这种情况的原因是因为"日期"(没有时间)不是时区感知的。
您可以在DateField源代码中看到Django自动将日期时间转换为UTC的地方:
def _check_fix_default_value(self):
"""
Warn that using an actual date or datetime value is probably wrong;
it's only evaluated on server startup.
"""
if not self.has_default():
return []
value = self.default
if isinstance(value, datetime.datetime):
value = _to_naive(value).date() # <————— 在这里!
elif isinstance(value, datetime.date):
pass
else:
# 没有显式的日期/日期时间值--不需要检查
return []
# 在这一点上,value是一个日期对象。
return self._check_if_value_fixed(value)
个人建议使用DateTimeField
,以便保留时区信息,仅在需要时访问.date
,但如果出于某种原因不想使用auto_now_add
选项,您也可以使用datetime.date.today
:
import datetime
class Submission(models.Model):
date_created = models.DateField(
default=datetime.date.today,
blank=True,
)
英文:
I think the reason this happens is because the "date" (without the time) isn't timezone aware.
You can see in the DateField source where Django automatically converts a datetime back to UTC:
def _check_fix_default_value(self):
"""
Warn that using an actual date or datetime value is probably wrong;
it's only evaluated on server startup.
"""
if not self.has_default():
return []
value = self.default
if isinstance(value, datetime.datetime):
value = _to_naive(value).date() # <————— HERE!
elif isinstance(value, datetime.date):
pass
else:
# No explicit date / datetime value -- no checks necessary
return []
# At this point, value is a date object.
return self._check_if_value_fixed(value)
Personally I would use a DateTimeField
so you keep the timezone information, and just access .date
when you need it, but you should be able to use datetime.date.today
(assuming you don't want to use the auto_now_add
option for some reason):
import datetime
class Submission(models.Model):
date_created = models.DateField(
default=datetime.date.today,
blank=True,
)
答案2
得分: 0
如果您希望date_created
字段存储正确的创建日期,可以使用以下代码修改默认值:default=timezone.now().date()
.date()
方法返回DateTime对象的日期部分,这将将date_created
字段设置为"2023-03-01"(在您的情况下,需要创建新的数据库条目),这是正确的创建日期。
因此,您可以按照以下方式尝试代码:
class Submission(models.Model):
date_created = models.DateField(
default=timezone.now().date(),
blank=True,
)
datetime_created = models.DateTimeField(
default=timezone.now,
)
date_created
字段被设置为"2023-03-02"的原因是DateField类型仅存储日期,不包含时间信息,因此当您将默认值设置为timezone.now
时,它将采用settings.py文件中指定的时区信息。
由于您在settings.py
文件中将时区设置为"US/Mountain",它比UTC时间晚7小时。因此,当数据记录发生在2023年03月01日下午5点MST时,实际的UTC日期为2023年02月01日(MST和UTC之间的时差)。这就是为什么date_created
的值被设置为"2023-03-02"的原因。
英文:
If you want the date_created
field to store the correct date of creation, you can modify the default value with this: default=timezone.now().date()
The .date()
method returns the date portion of a DateTime object and this will set the date_created
field to "2023-03-01" (In your case - New DB Entry will require), which is the correct date of creation.
So you can try the code as per below:
class Submission(models.Model):
date_created = models.DateField(
default=timezone.now().date(),
blank=True,
)
datetime_created = models.DateTimeField(
default=timezone.now,
)
The reason of the date_created field is set to "2023-03-02
" is that the DateField type only stores the date, without the time information so when you set the default value to timezone.now
it will take the time zone information specified in your settings.py file.
As you have set the time zone to "US/Mountain" on settings.py
file, which is 7 hours behind UTC. Since the TIME_ZONE setting was set to "US/Mountain" when the data entry happens at 5 PM MST on 03/01/2023
, the actual date in UTC was 02/01/2023
(time difference between MST and UTC). This is the reason why the value for date_created was set to "2023-03-02
" for you.
You can check timezone converter
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论