停止Django将时间转换为UTC [英] Stop Django translating times to UTC

查看:140
本文介绍了停止Django将时间转换为UTC的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

时区让我发疯.每次我想通了,都会有人改变时钟,我会遇到很多错误.我认为我终于到了要存储正确值的地步.我的时间是带有时区的时间戳,并且在保存之前,我不会删除时区.

  TIME_ZONE ='欧洲/伦敦'USE_I18N = USE_L10N = USE_TZ =真 

这是从Postgres到dbshel​​l的特定值:

  =>选择从bookings_booking开始,其中id = 280825;2019-04-09 11:50:00 + 01 

但这是通过shell_plus的相同记录

  Booking.objects.get(pk = 280825).startdatetime.datetime(2019、4、9、10、50,tzinfo =< UTC>) 

DAMMIT DJANGO,现在还不是UTC时间!

这些时间在template/admin/etc中可以 fine 起作用,但是当我生成PDF和电子表格报告时,所有这些都不可用,我突然不得不手动重新定位时间.我不明白为什么我必须这样做.数据已本地化.在查询数据库和获取数据之间发生了什么?

我经常碰到这些问题,所以我对这里的我自己完全没有信心-对于一位高级开发人员来说,这非常令人不安-因此我将自己放在了你的脚下.我该怎么办?

解决方案

您误解了这一点.数据库大部分时间存储UTC时间.如果使用PostgreSQL,数据库可以存储带有时区信息的时间,但出于实用目的(*),最简单的做法是认为数据库中的时间存储为UTC(即可以转换为任何时间的绝对时间)区域),当 USE_TZ = True 时.它始终代表一个正确的时间点,您无需记住或假定任何时区.据我所知,Django将始终将时间存储为UTC时区中的时间.

因此,当您使用 psql 中的 select 获取时间对象时,您将获得计算机本地时区(您所在的时区)中的时间.正在运行psql).如果"America/New_York"中的某人将运行相同的选择查询,则她将看到-04时间戳.如果日期为2019-03-20,您会看到 2019-03-20 10:50:00 + 00 ,因为在该日期,欧洲/伦敦和UTC相同.

在将 DateTimeField 的值作为python datetime.datetime 对象获取时,Django始终会获取UTC值,因为:

处理有意识的日期时间对象并不总是很直观.为了实例,标准datetime构造函数的tzinfo参数在具有DST的时区不能正常工作.通常使用UTC安全的;如果您使用的是其他时区,则应查看pytz仔细记录文档.

这可以更轻松地在python代码中使用这些datetime对象:它们始终是UTC时间.

如果要在PDF中打印这些值,请使用Django用于模板渲染的相同方法:

来自django.utils的

 导入时区打印(timezone.template_localtime(Booking.objects.get(pk = 280825).start)) 

这将在默认时区(如果您 activate()在其他时区,则在当前时区)中呈现日期时间.

(*)注意:为什么您不应该对保存在数据库中的时区赋予任何意义,而只是将其视为所有UTC:如果要在不同时区中运行服务器,则实际上可能最终会节省时间戳记在不同的时区.它们仍然都是正确的(绝对时间戳),并且可以转换为任何其他时区.因此,基本上,用于保存的时区是没有意义的.

Timezones are driving me crazy. Every time I think I've got it figured out, somebody changes the clocks and I get a dozen errors. I think I've finally got to the point where I'm storing the right value. My times are timestamp with time zone and I'm not stripping the timezone out before they're saved.

TIME_ZONE = 'Europe/London'
USE_I18N = USE_L10N = USE_TZ = True

Here's a specific value from Postgres through dbshell:

=> select start from bookings_booking where id = 280825;
2019-04-09 11:50:00+01

But here's the same record through shell_plus

Booking.objects.get(pk=280825).start
datetime.datetime(2019, 4, 9, 10, 50, tzinfo=<UTC>)

DAMMIT DJANGO, IT WASN'T A UTC TIME!

These times work fine in templates/admin/etc but when I'm generating PDF and spreadsheet reports, this all goes awry and I'm suddenly have to re-localise the times manually. I don't see why I have to do this. The data is localised. What is happening between the query going to the database and me getting the data?

I bump into these issues so often I have absolutely no confidence in myself here —something quite unnerving for a senior dev— so I lay myself at your feet. What am I supposed to do?

解决方案

You're interpreting this wrongly. The database stores a UTC time most of the time. If you use PostgreSQL, the database can store a time with time zone info, but for practical purposes (*) it's easiest to just think the time in your db is stored as UTC (i.e. as an absolute time that can be converted to any time zone) when USE_TZ = True. It always represents a correct point in time for which you don't need to remember or assume any timezone. And as far as I know, Django will always store the time as time-aware in UTC timezone.

So when you're fetching the time object using select in psql, you're getting back the time in your machine's local time zone (the time zone where you're running psql). If someone in "America/New_York" would run the same select query, she would see a -04 timestamp. Had the date been 2019-03-20, you'd have seen 2019-03-20 10:50:00+00 because on that date, Europe/London and UTC were the same.

When fetching the value of a DateTimeField as a python datetime.datetime object, Django always fetches the UTC value, because:

Dealing with aware datetime objects isn’t always intuitive. For instance, the tzinfo argument of the standard datetime constructor doesn’t work reliably for time zones with DST. Using UTC is generally safe; if you’re using other time zones, you should review the pytz documentation carefully.

This makes it easier to work with these datetime objects in your python code: They're always UTC times.

If you want to print these values in a PDF, use the same methods Django uses for the template rendering:

from django.utils import timezone
print(timezone.template_localtime(Booking.objects.get(pk=280825).start))

This renders the datetime in the default timezone (or if you activate() a different timezone, in the current timezone).

(*) Note: Why you should not give any meaning to the timezone saved in your db and just think about it as if it's all UTC: If you were to run servers in various timezones, you might actually end up saving timestamps in different timezones. They are still all correct (absolute timestamps) and can be converted to any other timezone. So basically the timezone used for saving is meaningless.

这篇关于停止Django将时间转换为UTC的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆