{"title":"Time zones","version":"3.0","locale":"zh-hans","docname":"topics/i18n/timezones","url":"/zh-hans/3.0/topics/i18n/timezones/","canonical":"https://djangodocs.dev/zh-hans/3.0/topics/i18n/timezones/","summary":"当启用了时区支持，Django 在数据库里以 UTC 存储日期信息，在内部使用时区感知日期对象，并且在模板和表单中转换为最终用户的时区。","html":"<h1>Time zones<a class=\"heading-anchor\" href=\"#time-zones\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<section id=\"overview\">\n<span id=\"time-zones-overview\"></span><h2>概况<a class=\"heading-anchor\" href=\"#overview\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>当启用了时区支持，Django 在数据库里以 UTC 存储日期信息，在内部使用时区感知日期对象，并且在模板和表单中转换为最终用户的时区。</p>\n<p>如果用户居住在多个时区时，这会很方便。你要根据用户的时间来显示日期信息。</p>\n<p>即便你的网站只在一个时区可用，在数据库中以 UTC 来存储数据是个好习惯。主要原因是夏令时。很多地方都有夏令时系统，时钟在春季向前调整，秋季向后调整。如果你以当地时间起居，那么时区转换时，每年都可能会遇到两次错误。也许这对你的博客没什么影响，但是每年两次，一次一小时多收或是少收用户的费用，这就是个问题。解决办法就是在代码里使用 UTC，并且在与最终用户交互时，使用当地时间。</p>\n<p>时区支持模式默认是关闭的，如果要启用它，在配置文件里设置  <a class=\"reference internal\" href=\"/zh-hans/3.0/ref/settings/#std-setting-USE_TZ\"><code class=\"xref std std-setting docutils literal notranslate\">USE_TZ = True</code></a> 。时区支持模式使用  <a class=\"reference external\" href=\"http://pytz.sourceforge.net/\">pytz</a> ，在安装 Django 的时候就已经安装好它了。</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>方便起见，在执行 <a class=\"reference internal\" href=\"/zh-hans/3.0/ref/django-admin/#django-admin-startproject\"><code class=\"xref std std-djadmin docutils literal notranslate\">django-admin startproject</code></a> 后创建默认的 <code class=\"file docutils literal notranslate\">settings.py</code> 文件包含 <a class=\"reference internal\" href=\"/zh-hans/3.0/ref/settings/#std-setting-USE_TZ\"><code class=\"xref std std-setting docutils literal notranslate\">USE_TZ = True</code></a> 。</p>\n</aside>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>还有一个有关 <a class=\"reference internal\" href=\"/zh-hans/3.0/ref/settings/#std-setting-USE_L10N\"><code class=\"xref std std-setting docutils literal notranslate\">USE_L10N</code></a> 的设置，用来控制 Django 是否激活本地格式化。查看 <a class=\"reference internal\" href=\"/zh-hans/3.0/topics/i18n/formatting/\"><span class=\"doc\">本地格式化</span></a> 获取更多细节。</p>\n</aside>\n<p>如果你在解决一个特定问题，从阅读 <a class=\"reference internal\" href=\"#time-zones-faq\"><span class=\"std std-ref\">time zone FAQ</span></a> 开始。</p>\n</section>\n<section id=\"concepts\">\n<h2>概念<a class=\"heading-anchor\" href=\"#concepts\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<section id=\"naive-and-aware-datetime-objects\">\n<span id=\"naive-vs-aware-datetimes\"></span><h3>Naive 日期对象与 Aware 日期对象<a class=\"heading-anchor\" href=\"#naive-and-aware-datetime-objects\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Python 的 <a class=\"reference external\" href=\"https://docs.python.org/3/library/datetime.html#datetime.datetime\" title=\"(in Python v3.14)\"><code class=\"xref py py-class docutils literal notranslate\">datetime.datetime</code></a> 对象有一个 <code class=\"docutils literal notranslate\">tzinfo</code> 属性，它可以存储时区信息，表示为 <a class=\"reference external\" href=\"https://docs.python.org/3/library/datetime.html#datetime.tzinfo\" title=\"(in Python v3.14)\"><code class=\"xref py py-class docutils literal notranslate\">datetime.tzinfo</code></a> 子类的一个实例。当设置这个属性并描述了偏移量后，日期对象就是 <strong>aware</strong> 的，否则就是 <strong>naive</strong> 的。</p>\n<p>你可以使用 <a class=\"reference internal\" href=\"/zh-hans/3.0/ref/utils/#django.utils.timezone.is_aware\" title=\"django.utils.timezone.is_aware\"><code class=\"xref py py-func docutils literal notranslate\">is_aware()</code></a> 和 <a class=\"reference internal\" href=\"/zh-hans/3.0/ref/utils/#django.utils.timezone.is_naive\" title=\"django.utils.timezone.is_naive\"><code class=\"xref py py-func docutils literal notranslate\">is_naive()</code></a> 来决定日期是 aware 还是 naive 的。</p>\n<p>当关闭了时区支持，Django 会在本地时间里使用原生日期对象。这对很多用例来说足够了。在这个模式下，如果你想获取当前时间，你可以这么写：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">import</span> <span class=\"nn\">datetime</span>\n\nnow <span class=\"o\">=</span> datetime<span class=\"o\">.</span>datetime<span class=\"o\">.</span>now<span class=\"p\">()</span>\n</code></pre></div>\n<p>当启用了时区支持 (<a class=\"reference internal\" href=\"/zh-hans/3.0/ref/settings/#std-setting-USE_TZ\"><code class=\"xref std std-setting docutils literal notranslate\">USE_TZ=True</code></a>) ，Django 使用 time-zone-aware 日期对象。如果你的代码创建了日期对象，她们应该也是 aware 的。在这个模式下，上面的例子变成：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.utils</span> <span class=\"kn\">import</span> timezone\n\nnow <span class=\"o\">=</span> timezone<span class=\"o\">.</span>now<span class=\"p\">()</span>\n</code></pre></div>\n<aside class=\"admonition admonition-warning\" role=\"note\">\n<p class=\"admonition-title\">Warning</p>\n<p>处理 aware 日期对象并不一直都是直观的。比如，标准日期构造函数的``tzinfo`` 参数对于使用 DST 的时区并不可靠。使用 UTC 一般是安全的；如果你正在使用其他时区，你应该认真地看一下 <a class=\"reference external\" href=\"http://pytz.sourceforge.net/\">pytz</a> 文档。</p>\n</aside>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>Python 的 <a class=\"reference external\" href=\"https://docs.python.org/3/library/datetime.html#datetime.time\" title=\"(in Python v3.14)\"><code class=\"xref py py-class docutils literal notranslate\">datetime.time</code></a> 对象还具有 <code class=\"docutils literal notranslate\">tzinfo</code> 属性，PostgreSQL 具有匹配 <code class=\"docutils literal notranslate\">带有时区时间</code> 的类型。但是，正如 PostgreSQL 所描述的，这个类型 &quot;表现出导致问题的可用性问题&quot;。</p>\n<p>Django 只支持 naive 时间对象，如果打算保存 aware 时间对象会引发异常，因为没有关联日期的时区的时间是没有意义的。</p>\n</aside>\n</section>\n<section id=\"interpretation-of-naive-datetime-objects\">\n<span id=\"naive-datetime-objects\"></span><h3>Naive 日期对象的说明<a class=\"heading-anchor\" href=\"#interpretation-of-naive-datetime-objects\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>当 <a class=\"reference internal\" href=\"/zh-hans/3.0/ref/settings/#std-setting-USE_TZ\"><code class=\"xref std std-setting docutils literal notranslate\">USE_TZ</code></a> 为 <code class=\"docutils literal notranslate\">True</code> 时，Django 仍然接受 naive 日期对象，以保持向后兼容。当数据库层收到一个日期对象，会试着让日期对象在 <a class=\"reference internal\" href=\"#default-current-time-zone\"><span class=\"std std-ref\">default time zone</span></a> 里进行解释将其变为 aware 日期对象，并发出警告。</p>\n<p>不幸的是，在 DST 转换期间，一些日期时间不存在或不明确。在这些情况下，<a class=\"reference external\" href=\"http://pytz.sourceforge.net/\">pytz</a> 会引发一个异常。这就是为什么当启用时区支持的时候，需要始终创建 aware 时间对象的原因。</p>\n<p>实际上，这种情况很罕见。Django 在模型和表单里为你提供了 aware 日期对象，并且在大部分时候，新的日期对象是通过 <a class=\"reference external\" href=\"https://docs.python.org/3/library/datetime.html#datetime.timedelta\" title=\"(in Python v3.14)\"><code class=\"xref py py-class docutils literal notranslate\">timedelta</code></a> 算法从现有的对象创建的。常在应用代码里创建的日期时间是当前时间，<a class=\"reference internal\" href=\"/zh-hans/3.0/ref/utils/#django.utils.timezone.now\" title=\"django.utils.timezone.now\"><code class=\"xref py py-func docutils literal notranslate\">timezone.now()</code></a> 会自动完成这个操作。</p>\n</section>\n<section id=\"default-time-zone-and-current-time-zone\">\n<span id=\"default-current-time-zone\"></span><h3>默认时区和当前时区<a class=\"heading-anchor\" href=\"#default-time-zone-and-current-time-zone\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p><strong>默认时区</strong> 是通过 <a class=\"reference internal\" href=\"/zh-hans/3.0/ref/settings/#std-setting-TIME_ZONE\"><code class=\"xref std std-setting docutils literal notranslate\">TIME_ZONE</code></a> 定义的时区。</p>\n<p><strong>当前时区</strong> 是用来渲染的时区。</p>\n<p>你应该使用 <a class=\"reference internal\" href=\"/zh-hans/3.0/ref/utils/#django.utils.timezone.activate\" title=\"django.utils.timezone.activate\"><code class=\"xref py py-func docutils literal notranslate\">activate()</code></a> 将当前时区设置为最终用户的实际时区。</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>如 <a class=\"reference internal\" href=\"/zh-hans/3.0/ref/settings/#std-setting-TIME_ZONE\"><code class=\"xref std std-setting docutils literal notranslate\">TIME_ZONE</code></a> 文档描述，Django 设置了环境变量，因此它的进程在默认时区里运行。无论  <a class=\"reference internal\" href=\"/zh-hans/3.0/ref/settings/#std-setting-USE_TZ\"><code class=\"xref std std-setting docutils literal notranslate\">USE_TZ</code></a> 的值和当前时区如何，都会发生这种情况。</p>\n<p>当 <a class=\"reference internal\" href=\"/zh-hans/3.0/ref/settings/#std-setting-USE_TZ\"><code class=\"xref std std-setting docutils literal notranslate\">USE_TZ</code></a> 设置为 <code class=\"docutils literal notranslate\">True</code> 时，这样有助于保持仍然需要依赖当地时间的应用程序的后端兼容性。然而，就像前面所说（<a class=\"reference internal\" href=\"#naive-datetime-objects\"><span class=\"std std-ref\">as explained above</span></a>），这样并不完全可靠，你应该始终在代码里使用 UTC 里的 aware 日期来工作。比如，使用 <a class=\"reference external\" href=\"https://docs.python.org/3/library/datetime.html#datetime.datetime.fromtimestamp\" title=\"(in Python v3.14)\"><code class=\"xref py py-meth docutils literal notranslate\">fromtimestamp()</code></a> 并且将 <code class=\"docutils literal notranslate\">tz</code> 参数设置为 <a class=\"reference internal\" href=\"/zh-hans/3.0/ref/utils/#django.utils.timezone.utc\" title=\"django.utils.timezone.utc\"><code class=\"xref py py-data docutils literal notranslate\">utc</code></a> 。</p>\n</aside>\n</section>\n<section id=\"selecting-the-current-time-zone\">\n<h3>选择当前时区<a class=\"heading-anchor\" href=\"#selecting-the-current-time-zone\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>当前时区相当于转换  current <a class=\"reference internal\" href=\"/zh-hans/3.0/topics/i18n/#term-locale-name\"><span class=\"xref std std-term\">locale</span></a> 。但是，Django 没有可用于自动确定用户时区的  <code class=\"docutils literal notranslate\">Accept-Language</code> HTTP header 。相反，Django 提供了时区选择函数（ <a class=\"reference internal\" href=\"/zh-hans/3.0/ref/utils/#time-zone-selection-functions\"><span class=\"std std-ref\">time zone selection functions</span></a> ）。使用它们来建立对你有用的时区选择逻辑。</p>\n<p>很多关心用户时区的站点会询问用户所在的时区，并且把这个信息保存在用户资料里。对于匿名用户，他们使用网站主要受众群体的时区或者 UTC。<a class=\"reference external\" href=\"http://pytz.sourceforge.net/\">pytz</a> 提供了帮助（ <a class=\"reference external\" href=\"http://pytz.sourceforge.net/#helpers\">helpers</a> ），例如每个国家时区的列表，这样你可以预先选择最有可能的选项。</p>\n<p>这里有个在会话(session)里存储当前时区的例子。（为简单起见，它完全跳过了错误处理）</p>\n<p>在 <a class=\"reference internal\" href=\"/zh-hans/3.0/ref/settings/#std-setting-MIDDLEWARE\"><code class=\"xref std std-setting docutils literal notranslate\">MIDDLEWARE</code></a>: 里添加下面的中间件：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">import</span> <span class=\"nn\">pytz</span>\n\n<span class=\"kn\">from</span> <span class=\"nn\">django.utils</span> <span class=\"kn\">import</span> timezone\n\n<span class=\"k\">class</span> <span class=\"nc\">TimezoneMiddleware</span><span class=\"p\">:</span>\n    <span class=\"k\">def</span> <span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> get_response<span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span>get_response <span class=\"o\">=</span> get_response\n\n    <span class=\"k\">def</span> <span class=\"fm\">__call__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> request<span class=\"p\">):</span>\n        tzname <span class=\"o\">=</span> request<span class=\"o\">.</span>session<span class=\"o\">.</span>get<span class=\"p\">(</span><span class=\"s1\">&#39;django_timezone&#39;</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> tzname<span class=\"p\">:</span>\n            timezone<span class=\"o\">.</span>activate<span class=\"p\">(</span>pytz<span class=\"o\">.</span>timezone<span class=\"p\">(</span>tzname<span class=\"p\">))</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            timezone<span class=\"o\">.</span>deactivate<span class=\"p\">()</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span>get_response<span class=\"p\">(</span>request<span class=\"p\">)</span>\n</code></pre></div>\n<p>创建一个可以设置当前时区的视图：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.shortcuts</span> <span class=\"kn\">import</span> redirect<span class=\"p\">,</span> render\n\n<span class=\"k\">def</span> <span class=\"nf\">set_timezone</span><span class=\"p\">(</span>request<span class=\"p\">):</span>\n    <span class=\"k\">if</span> request<span class=\"o\">.</span>method <span class=\"o\">==</span> <span class=\"s1\">&#39;POST&#39;</span><span class=\"p\">:</span>\n        request<span class=\"o\">.</span>session<span class=\"p\">[</span><span class=\"s1\">&#39;django_timezone&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> request<span class=\"o\">.</span>POST<span class=\"p\">[</span><span class=\"s1\">&#39;timezone&#39;</span><span class=\"p\">]</span>\n        <span class=\"k\">return</span> redirect<span class=\"p\">(</span><span class=\"s1\">&#39;/&#39;</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"k\">return</span> render<span class=\"p\">(</span>request<span class=\"p\">,</span> <span class=\"s1\">&#39;template.html&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;timezones&#39;</span><span class=\"p\">:</span> pytz<span class=\"o\">.</span>common_timezones<span class=\"p\">})</span>\n</code></pre></div>\n<p>在  <code class=\"docutils literal notranslate\">template.html</code>  包含了一个发送 <code class=\"docutils literal notranslate\">POST</code> 到视图的表单：</p>\n<div class=\"code-block\" data-language=\"html+django\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Django template</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Django template code\"><code><span class=\"cp\">{%</span> <span class=\"k\">load</span> <span class=\"nv\">tz</span> <span class=\"cp\">%}</span>\n<span class=\"cp\">{%</span> <span class=\"k\">get_current_timezone</span> <span class=\"k\">as</span> <span class=\"nv\">TIME_ZONE</span> <span class=\"cp\">%}</span>\n<span class=\"p\">&lt;</span><span class=\"nt\">form</span> <span class=\"na\">action</span><span class=\"o\">=</span><span class=\"s\">&quot;</span><span class=\"cp\">{%</span> <span class=\"k\">url</span> <span class=\"s1\">&#39;set_timezone&#39;</span> <span class=\"cp\">%}</span><span class=\"s\">&quot;</span> <span class=\"na\">method</span><span class=\"o\">=</span><span class=\"s\">&quot;POST&quot;</span><span class=\"p\">&gt;</span>\n    <span class=\"cp\">{%</span> <span class=\"k\">csrf_token</span> <span class=\"cp\">%}</span>\n    <span class=\"p\">&lt;</span><span class=\"nt\">label</span> <span class=\"na\">for</span><span class=\"o\">=</span><span class=\"s\">&quot;timezone&quot;</span><span class=\"p\">&gt;</span>Time zone:<span class=\"p\">&lt;/</span><span class=\"nt\">label</span><span class=\"p\">&gt;</span>\n    <span class=\"p\">&lt;</span><span class=\"nt\">select</span> <span class=\"na\">name</span><span class=\"o\">=</span><span class=\"s\">&quot;timezone&quot;</span><span class=\"p\">&gt;</span>\n        <span class=\"cp\">{%</span> <span class=\"k\">for</span> <span class=\"nv\">tz</span> <span class=\"k\">in</span> <span class=\"nv\">timezones</span> <span class=\"cp\">%}</span>\n        <span class=\"p\">&lt;</span><span class=\"nt\">option</span> <span class=\"na\">value</span><span class=\"o\">=</span><span class=\"s\">&quot;</span><span class=\"cp\">{{</span> <span class=\"nv\">tz</span> <span class=\"cp\">}}</span><span class=\"s\">&quot;</span><span class=\"cp\">{%</span> <span class=\"k\">if</span> <span class=\"nv\">tz</span> <span class=\"o\">==</span> <span class=\"nv\">TIME_ZONE</span> <span class=\"cp\">%}</span> <span class=\"na\">selected</span><span class=\"cp\">{%</span> <span class=\"k\">endif</span> <span class=\"cp\">%}</span><span class=\"p\">&gt;</span><span class=\"cp\">{{</span> <span class=\"nv\">tz</span> <span class=\"cp\">}}</span><span class=\"p\">&lt;/</span><span class=\"nt\">option</span><span class=\"p\">&gt;</span>\n        <span class=\"cp\">{%</span> <span class=\"k\">endfor</span> <span class=\"cp\">%}</span>\n    <span class=\"p\">&lt;/</span><span class=\"nt\">select</span><span class=\"p\">&gt;</span>\n    <span class=\"p\">&lt;</span><span class=\"nt\">input</span> <span class=\"na\">type</span><span class=\"o\">=</span><span class=\"s\">&quot;submit&quot;</span> <span class=\"na\">value</span><span class=\"o\">=</span><span class=\"s\">&quot;Set&quot;</span><span class=\"p\">&gt;</span>\n<span class=\"p\">&lt;/</span><span class=\"nt\">form</span><span class=\"p\">&gt;</span>\n</code></pre></div>\n</section>\n</section>\n<section id=\"time-zone-aware-input-in-forms\">\n<span id=\"time-zones-in-forms\"></span><h2>表单里的时区感知(aware)输入<a class=\"heading-anchor\" href=\"#time-zone-aware-input-in-forms\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>当启用了时区支持，Django 会解释当前时区中以表格形式输入的日期时间，并且在 <code class=\"docutils literal notranslate\">cleaned_data</code> 中返回 aware 日期对象。</p>\n<p>如果当前时区在夏令时转换（由 <a class=\"reference external\" href=\"http://pytz.sourceforge.net/\">pytz</a> 提供的时区）时因日期不存在或者不明确而引发了异常，此类日期时间将被报告为无效值。</p>\n</section>\n<section id=\"time-zone-aware-output-in-templates\">\n<span id=\"time-zones-in-templates\"></span><h2>模板中时区感知(aware)输出<a class=\"heading-anchor\" href=\"#time-zone-aware-output-in-templates\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>当启用了时区支持，Django 会在模板中渲染 aware 日期时间时，将其转换为当前时区。这非常类似于本地化格式（  <a class=\"reference internal\" href=\"/zh-hans/3.0/topics/i18n/formatting/\"><span class=\"doc\">format localization</span></a> ）。</p>\n<aside class=\"admonition admonition-warning\" role=\"note\">\n<p class=\"admonition-title\">Warning</p>\n<p>Django 不会转换 naive 日期对象，因为它们是不确定的，而且当开启了时区支持后，代码里绝不能生成 naive 日期。但是，你可以使用下面描述的模板过滤器那样强制转换。</p>\n</aside>\n<p>转换为本地时间并不总是合适的——你或许是为计算机而不是为人类生成输出。下面的过滤器和标签，由  <code class=\"docutils literal notranslate\">tz</code> 模板标签库支持，允许你控制时区转换。</p>\n<section id=\"template-tags\">\n<h3>模板标签<a class=\"heading-anchor\" href=\"#template-tags\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<section id=\"localtime\">\n<span id=\"std-templatetag-localtime\"></span><h4><code class=\"docutils literal notranslate\">localtime</code><a class=\"heading-anchor\" href=\"#localtime\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>在包含块里开启或关闭将 aware 日期时间对象的转换为当前时区。</p>\n<p>就模板引擎而言，该标签与 <a class=\"reference internal\" href=\"/zh-hans/3.0/ref/settings/#std-setting-USE_TZ\"><code class=\"xref std std-setting docutils literal notranslate\">USE_TZ</code></a> 具有完全相同的效果。它可以更精细地控制转换。</p>\n<p>要模板块激活或关闭转换，使用：</p>\n<div class=\"code-block\" data-language=\"html+django\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Django template</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Django template code\"><code><span class=\"cp\">{%</span> <span class=\"k\">load</span> <span class=\"nv\">tz</span> <span class=\"cp\">%}</span>\n\n<span class=\"cp\">{%</span> <span class=\"k\">localtime</span> <span class=\"nv\">on</span> <span class=\"cp\">%}</span>\n    <span class=\"cp\">{{</span> <span class=\"nv\">value</span> <span class=\"cp\">}}</span>\n<span class=\"cp\">{%</span> <span class=\"k\">endlocaltime</span> <span class=\"cp\">%}</span>\n\n<span class=\"cp\">{%</span> <span class=\"k\">localtime</span> <span class=\"nv\">off</span> <span class=\"cp\">%}</span>\n    <span class=\"cp\">{{</span> <span class=\"nv\">value</span> <span class=\"cp\">}}</span>\n<span class=\"cp\">{%</span> <span class=\"k\">endlocaltime</span> <span class=\"cp\">%}</span>\n</code></pre></div>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p><a class=\"reference internal\" href=\"/zh-hans/3.0/ref/settings/#std-setting-USE_TZ\"><code class=\"xref std std-setting docutils literal notranslate\">USE_TZ</code></a> 的值在 <code class=\"docutils literal notranslate\">{% localtime %}</code> 块内被忽略。</p>\n</aside>\n</section>\n<section id=\"timezone\">\n<span id=\"std-templatetag-timezone\"></span><h4><code class=\"docutils literal notranslate\">timezone</code><a class=\"heading-anchor\" href=\"#timezone\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>在包含块内设置或取消当前时区。当没有设置当前时区时，会使用默认时区。</p>\n<div class=\"code-block\" data-language=\"html+django\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Django template</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Django template code\"><code><span class=\"cp\">{%</span> <span class=\"k\">load</span> <span class=\"nv\">tz</span> <span class=\"cp\">%}</span>\n\n<span class=\"cp\">{%</span> <span class=\"k\">timezone</span> <span class=\"s2\">&quot;Europe/Paris&quot;</span> <span class=\"cp\">%}</span>\n    Paris time: <span class=\"cp\">{{</span> <span class=\"nv\">value</span> <span class=\"cp\">}}</span>\n<span class=\"cp\">{%</span> <span class=\"k\">endtimezone</span> <span class=\"cp\">%}</span>\n\n<span class=\"cp\">{%</span> <span class=\"k\">timezone</span> <span class=\"kp\">None</span> <span class=\"cp\">%}</span>\n    Server time: <span class=\"cp\">{{</span> <span class=\"nv\">value</span> <span class=\"cp\">}}</span>\n<span class=\"cp\">{%</span> <span class=\"k\">endtimezone</span> <span class=\"cp\">%}</span>\n</code></pre></div>\n</section>\n<section id=\"get-current-timezone\">\n<span id=\"std-templatetag-get_current_timezone\"></span><h4><code class=\"docutils literal notranslate\">get_current_timezone</code><a class=\"heading-anchor\" href=\"#get-current-timezone\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>使用 <code class=\"docutils literal notranslate\">get_current_timezone</code> 标签来获取当前时区的名称：</p>\n<div class=\"code-block\" data-language=\"html+django\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Django template</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Django template code\"><code><span class=\"cp\">{%</span> <span class=\"k\">get_current_timezone</span> <span class=\"k\">as</span> <span class=\"nv\">TIME_ZONE</span> <span class=\"cp\">%}</span>\n</code></pre></div>\n<p>另外，你可以激活 <a class=\"reference internal\" href=\"/zh-hans/3.0/ref/templates/api/#django.template.context_processors.tz\" title=\"django.template.context_processors.tz\"><code class=\"xref py py-func docutils literal notranslate\">tz()</code></a> 上下文处理器并使用 <code class=\"docutils literal notranslate\">TIME_ZONE</code> 上下文变量。</p>\n</section>\n</section>\n<section id=\"template-filters\">\n<h3>模板过滤器<a class=\"heading-anchor\" href=\"#template-filters\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>这些过滤器接受 aware 时间和 naive 时间。处于转换目的，它们假设 naive 时间在默认时区中。它们始终返回 aware 时间。</p>\n<section id=\"std-templatefilter-localtime\">\n<span id=\"id1\"></span><h4><code class=\"docutils literal notranslate\">localtime</code><a class=\"heading-anchor\" href=\"#std-templatefilter-localtime\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>单一值强制转换为当前时区。</p>\n<p>例如:</p>\n<div class=\"code-block\" data-language=\"html+django\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Django template</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Django template code\"><code><span class=\"cp\">{%</span> <span class=\"k\">load</span> <span class=\"nv\">tz</span> <span class=\"cp\">%}</span>\n\n<span class=\"cp\">{{</span> <span class=\"nv\">value</span><span class=\"o\">|</span><span class=\"nf\">localtime</span> <span class=\"cp\">}}</span>\n</code></pre></div>\n</section>\n<section id=\"utc\">\n<span id=\"std-templatefilter-utc\"></span><h4><code class=\"docutils literal notranslate\">utc</code><a class=\"heading-anchor\" href=\"#utc\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>单一值强制转换为 UTC 。</p>\n<p>例如:</p>\n<div class=\"code-block\" data-language=\"html+django\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Django template</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Django template code\"><code><span class=\"cp\">{%</span> <span class=\"k\">load</span> <span class=\"nv\">tz</span> <span class=\"cp\">%}</span>\n\n<span class=\"cp\">{{</span> <span class=\"nv\">value</span><span class=\"o\">|</span><span class=\"nf\">utc</span> <span class=\"cp\">}}</span>\n</code></pre></div>\n</section>\n<section id=\"std-templatefilter-timezone\">\n<span id=\"id2\"></span><h4><code class=\"docutils literal notranslate\">timezone</code><a class=\"heading-anchor\" href=\"#std-templatefilter-timezone\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>单一值强制转换为任意时区。</p>\n<p>参数必须是 <a class=\"reference external\" href=\"https://docs.python.org/3/library/datetime.html#datetime.tzinfo\" title=\"(in Python v3.14)\"><code class=\"xref py py-class docutils literal notranslate\">tzinfo</code></a> 子类实例或时区名。</p>\n<p>例如:</p>\n<div class=\"code-block\" data-language=\"html+django\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Django template</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Django template code\"><code><span class=\"cp\">{%</span> <span class=\"k\">load</span> <span class=\"nv\">tz</span> <span class=\"cp\">%}</span>\n\n<span class=\"cp\">{{</span> <span class=\"nv\">value</span><span class=\"o\">|</span><span class=\"nf\">timezone</span><span class=\"s2\">:&quot;Europe/Paris&quot;</span> <span class=\"cp\">}}</span>\n</code></pre></div>\n</section>\n</section>\n</section>\n<section id=\"migration-guide\">\n<span id=\"time-zones-migration-guide\"></span><h2>迁移指南<a class=\"heading-anchor\" href=\"#migration-guide\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>以下是迁移在 Django 支持时区之前已有项目的方法。</p>\n<section id=\"database\">\n<h3>数据库<a class=\"heading-anchor\" href=\"#database\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<section id=\"postgresql\">\n<h4>PostgreSQL<a class=\"heading-anchor\" href=\"#postgresql\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>PostgreSQL 后端存储将日期时间存储为 <code class=\"docutils literal notranslate\">带时区的时间戳</code> 。事实上，这意味着它在存储时会将日期从连接的时区转换为UTC，并在检索时将UTC转换为连接的时区。</p>\n<p>因此，如果你正在使用 PostgreSQL，你可以在 <code class=\"docutils literal notranslate\">USE_TZ = False</code> 和  <code class=\"docutils literal notranslate\">USE_TZ = True</code> 之间自由选择，数据库连接的时区将分别设置为 <a class=\"reference internal\" href=\"/zh-hans/3.0/ref/settings/#std-setting-TIME_ZONE\"><code class=\"xref std std-setting docutils literal notranslate\">TIME_ZONE</code></a> 或 <code class=\"docutils literal notranslate\">UTC</code> ，以便 Django 在所有情况下将得到正确的日期。你不需要执行任何数据转换。</p>\n</section>\n<section id=\"other-databases\">\n<h4>其他数据库<a class=\"heading-anchor\" href=\"#other-databases\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>其他后端存储没有时区信息的日期。如果你的选择从 <code class=\"docutils literal notranslate\">USE_TZ = False</code> 变为 <code class=\"docutils literal notranslate\">USE_TZ = True</code> ，你必须将你的数据从本地时间转换为UTC —— 如果你的当地时间有夏令时时，则不确定。</p>\n</section>\n</section>\n<section id=\"code\">\n<h3>邮政编码<a class=\"heading-anchor\" href=\"#code\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>第一步是将 <a class=\"reference internal\" href=\"/zh-hans/3.0/ref/settings/#std-setting-USE_TZ\"><code class=\"xref std std-setting docutils literal notranslate\">USE_TZ = True</code></a> 添加到你的配置文件里。在这点上，大多数情况下都应该起作用。如果你在代码里创建 naive 日期时间对象，Django 会在必要时将它们转换为 aware 日期时间对象。</p>\n<p>然而，这些转换有可能在夏令时转换时失败，这意味着你并有获得时区支持的所有好处。而且，在运行的时候很可能会遇到一些问题，因为它无法将 naive 日期时间和 aware 日期时间进行比较。由于 Django 现在为你提供了  aware 时间，你在比较来自模型或表单的日期与代码里创建的naive日期时间时，会遇到一些异常。</p>\n<p>第二步是重构你在任何地方实例化的日期时间，将它们转换为 aware 日期时间。这可以逐步完成。<a class=\"reference internal\" href=\"/zh-hans/3.0/ref/utils/#module-django.utils.timezone\" title=\"django.utils.timezone: Timezone support.\"><code class=\"xref py py-mod docutils literal notranslate\">django.utils.timezone</code></a> 为了代码兼容性而定义了一些方法：<a class=\"reference internal\" href=\"/zh-hans/3.0/ref/utils/#django.utils.timezone.now\" title=\"django.utils.timezone.now\"><code class=\"xref py py-func docutils literal notranslate\">now()</code></a>, <a class=\"reference internal\" href=\"/zh-hans/3.0/ref/utils/#django.utils.timezone.is_aware\" title=\"django.utils.timezone.is_aware\"><code class=\"xref py py-func docutils literal notranslate\">is_aware()</code></a>, <a class=\"reference internal\" href=\"/zh-hans/3.0/ref/utils/#django.utils.timezone.is_naive\" title=\"django.utils.timezone.is_naive\"><code class=\"xref py py-func docutils literal notranslate\">is_naive()</code></a>, <a class=\"reference internal\" href=\"/zh-hans/3.0/ref/utils/#django.utils.timezone.make_aware\" title=\"django.utils.timezone.make_aware\"><code class=\"xref py py-func docutils literal notranslate\">make_aware()</code></a>, 和 <a class=\"reference internal\" href=\"/zh-hans/3.0/ref/utils/#django.utils.timezone.make_naive\" title=\"django.utils.timezone.make_naive\"><code class=\"xref py py-func docutils literal notranslate\">make_naive()</code></a> 。</p>\n<p>最后，为了帮助你定位需要升级的代码，Django 会在你试图保存 naive 日期代码到数据库的时候，引发一个告警。</p>\n<div class=\"code-block\" data-language=\"python\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"ne\">RuntimeWarning</span><span class=\"p\">:</span> DateTimeField ModelName<span class=\"o\">.</span>field_name received a naive\ndatetime <span class=\"p\">(</span><span class=\"mi\">2012</span><span class=\"o\">-</span><span class=\"mi\">01</span><span class=\"o\">-</span><span class=\"mi\">01</span> <span class=\"mi\">00</span><span class=\"p\">:</span><span class=\"mi\">00</span><span class=\"p\">:</span><span class=\"mi\">00</span><span class=\"p\">)</span> <span class=\"k\">while</span> time zone support <span class=\"ow\">is</span> active<span class=\"o\">.</span>\n</code></pre></div>\n<p>在开发期间，你可以通过在配置文件中添加下面的代码，使得此类警告变成异常，方便追踪：</p>\n<div class=\"code-block\" data-language=\"python\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"kn\">import</span> <span class=\"nn\">warnings</span>\nwarnings<span class=\"o\">.</span>filterwarnings<span class=\"p\">(</span>\n    <span class=\"s1\">&#39;error&#39;</span><span class=\"p\">,</span> <span class=\"sa\">r</span><span class=\"s2\">&quot;DateTimeField .* received a naive datetime&quot;</span><span class=\"p\">,</span>\n    <span class=\"ne\">RuntimeWarning</span><span class=\"p\">,</span> <span class=\"sa\">r</span><span class=\"s1\">&#39;django\\.db\\.models\\.fields&#39;</span><span class=\"p\">,</span>\n<span class=\"p\">)</span>\n</code></pre></div>\n</section>\n<section id=\"fixtures\">\n<h3>辅助工具<a class=\"heading-anchor\" href=\"#fixtures\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>当序列化 aware 日期时间时，会包含 UTC 偏移，如下：</p>\n<div class=\"code-block\" data-language=\"python\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"s2\">&quot;2011-09-01T13:20:30+03:00&quot;</span>\n</code></pre></div>\n<p>对于 naive 时间，它不能这样：</p>\n<div class=\"code-block\" data-language=\"python\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"s2\">&quot;2011-09-01T13:20:30&quot;</span>\n</code></pre></div>\n<p>对于带有 <a class=\"reference internal\" href=\"/zh-hans/3.0/ref/models/fields/#django.db.models.DateTimeField\" title=\"django.db.models.DateTimeField\"><code class=\"xref py py-class docutils literal notranslate\">DateTimeField</code></a> 的模型，这种差异使得编写一个支持和不支持时区的辅助工具变得不可能。</p>\n<p>使用 <code class=\"docutils literal notranslate\">USE_TZ = False</code> 生成辅助工具，或者 Django 1.4 版本之前，使用 &quot;naive&quot; 格式化。如果你的项目包含这些辅助工具，则在开始时区支持后，你将会在加载它们时，看到 <a class=\"reference external\" href=\"https://docs.python.org/3/library/exceptions.html#RuntimeWarning\" title=\"(in Python v3.14)\"><code class=\"xref py py-exc docutils literal notranslate\">RuntimeWarning</code></a> 。为了避免这些告警，你必须将辅助工具转换为 &quot;aware&quot; 格式。</p>\n<p>你可以先使用 <a class=\"reference internal\" href=\"/zh-hans/3.0/ref/django-admin/#django-admin-loaddata\"><code class=\"xref std std-djadmin docutils literal notranslate\">loaddata</code></a> 然后 <a class=\"reference internal\" href=\"/zh-hans/3.0/ref/django-admin/#django-admin-dumpdata\"><code class=\"xref std std-djadmin docutils literal notranslate\">dumpdata</code></a> 重新生成辅助工具。或者，如果它们足够小，你可以对它们编辑，与将匹配到 <a class=\"reference internal\" href=\"/zh-hans/3.0/ref/settings/#std-setting-TIME_ZONE\"><code class=\"xref std std-setting docutils literal notranslate\">TIME_ZONE</code></a> 的 UTC 偏移量添加到每个序列化日期时间。</p>\n</section>\n</section>\n<section id=\"faq\">\n<span id=\"time-zones-faq\"></span><h2>FAQ<a class=\"heading-anchor\" href=\"#faq\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<section id=\"setup\">\n<h3>安装<a class=\"heading-anchor\" href=\"#setup\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<ol class=\"arabic\">\n<li><p><strong>我不需要多时区服务。我应该开启时区支持吗？</strong></p>\n<p>是的。开启时区支持后，Django 会使用更准确的本地时间模型，这样使得你在夏令时转换时避免一些微秒、不可复制的错误。</p>\n<p>开启时区支持后，会遇到一些错误，因为你使用 naive 日期时间，而 Django 期望使用 aware 日期时间。这些错误在测试的时候会显示出来。</p>\n<p>另一方面，由于缺乏时区支持导致的bug很难预防、诊断和修复。任何涉及计划任务或日期计算的事务都有可能是潜在的bug。</p>\n<p>基于这些原因，在新项目时要启用时区支持，除非有很好的理由，否则应该保留它。</p>\n</li>\n<li><p><strong>我已经开启了时区支持。我安全了吗？</strong></p>\n<p>也许吧。你可以更好地避免夏令时相关错误，但你仍然可以把 naive 日期时间转换为 aware 日期时间，反之亦然。</p>\n<p>如果你的应用连接了其他系统——比如，查询一个web服务——请确保正确指定日期时间。为了便于安全地传输时间，它们的描述应该包含 UTC 偏移量，或者它们的值应该在UTC中（或者二者都包括）。</p>\n<p>最后，我们的日历系统在计算上有一些有意思的陷阱：</p>\n<div class=\"code-block\" data-language=\"python\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span> <span class=\"nn\">datetime</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">def</span> <span class=\"nf\">one_year_before</span><span class=\"p\">(</span>value<span class=\"p\">):</span>       <span class=\"c1\"># DON&#39;T DO THAT!</span>\n<span class=\"gp\">... </span>    <span class=\"k\">return</span> value<span class=\"o\">.</span>replace<span class=\"p\">(</span>year<span class=\"o\">=</span>value<span class=\"o\">.</span>year <span class=\"o\">-</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>one_year_before<span class=\"p\">(</span>datetime<span class=\"o\">.</span>datetime<span class=\"p\">(</span><span class=\"mi\">2012</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">))</span>\n<span class=\"go\">datetime.datetime(2011, 3, 1, 10, 0)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>one_year_before<span class=\"p\">(</span>datetime<span class=\"o\">.</span>datetime<span class=\"p\">(</span><span class=\"mi\">2012</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">29</span><span class=\"p\">,</span> <span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">))</span>\n<span class=\"gt\">Traceback (most recent call last):</span>\n<span class=\"c\">...</span>\n<span class=\"gr\">ValueError</span>: day is out of range for month\n</code></pre></div>\n<p>（为了实现这个功能，你必须判断 2012-02-29 减去1年的结果是2011-02-28还是2011-03-01，这取决于你的业务需求。）</p>\n</li>\n<li><p><strong>我改如何与存储本地日期时间的数据库进行交互？</strong></p>\n<p>在 <a class=\"reference internal\" href=\"/zh-hans/3.0/ref/settings/#std-setting-DATABASES\"><code class=\"xref std std-setting docutils literal notranslate\">DATABASES</code></a> 里将:setting:TIME_ZONE &lt;DATABASE-TIME_ZONE&gt; 选项设置为适合该数据库的时区。</p>\n<p>当 <a class=\"reference internal\" href=\"/zh-hans/3.0/ref/settings/#std-setting-USE_TZ\"><code class=\"xref std std-setting docutils literal notranslate\">USE_TZ</code></a> 为 <code class=\"docutils literal notranslate\">True</code> 时，这对连接到不支持时区以及不受 Django 管理的数据库很有用。</p>\n</li>\n</ol>\n</section>\n<section id=\"troubleshooting\">\n<h3>错误调试<a class=\"heading-anchor\" href=\"#troubleshooting\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<ol class=\"arabic\">\n<li><p><strong>我的程序因不能比较带有偏移的 naive 日期时间与带有偏移的 aware 日期时间而崩溃——怎么回事？</strong></p>\n<p>我们通过比较 naive 时间和 aware 时间来重现一下这个错误：</p>\n<div class=\"code-block\" data-language=\"python\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span> <span class=\"nn\">datetime</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span> <span class=\"nn\">django.utils</span> <span class=\"kn\">import</span> timezone\n<span class=\"gp\">&gt;&gt;&gt; </span>naive <span class=\"o\">=</span> datetime<span class=\"o\">.</span>datetime<span class=\"o\">.</span>utcnow<span class=\"p\">()</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>aware <span class=\"o\">=</span> timezone<span class=\"o\">.</span>now<span class=\"p\">()</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>naive <span class=\"o\">==</span> aware\n<span class=\"gt\">Traceback (most recent call last):</span>\n<span class=\"c\">...</span>\n<span class=\"gr\">TypeError</span>: can&#39;t compare offset-naive and offset-aware datetimes\n</code></pre></div>\n<p>如果遇到这个错误，很可能你的代码正在比较这两件事：</p>\n<ul class=\"simple\">\n<li><p>Django 支持的日期——比如，读取来自表单或模型字段的值。因为你开启了时区支持，所以它是 aware 的。</p></li>\n<li><p>通过代码生成了日期，它是 naive 的（或者你不会读取它）。</p></li>\n</ul>\n<p>一般来说，正确的解决办法是修改代码，用 aware 日期时间代替它。</p>\n<p>如果你正在编写可插拔的应用独立于 <a class=\"reference internal\" href=\"/zh-hans/3.0/ref/settings/#std-setting-USE_TZ\"><code class=\"xref std std-setting docutils literal notranslate\">USE_TZ</code></a> 的值运行，你会发现 <a class=\"reference internal\" href=\"/zh-hans/3.0/ref/utils/#django.utils.timezone.now\" title=\"django.utils.timezone.now\"><code class=\"xref py py-func docutils literal notranslate\">django.utils.timezone.now()</code></a>  很有用。这个函数会在 <code class=\"docutils literal notranslate\">USE_TZ = False</code>  时将当前日期和时间作为 naive 返回，并且在 <code class=\"docutils literal notranslate\">USE_TZ = True</code> 时将当前日期和时间作为 aware 返回。你可以在需要时添加或减少 <a class=\"reference external\" href=\"https://docs.python.org/3/library/datetime.html#datetime.timedelta\" title=\"(in Python v3.14)\"><code class=\"xref py py-class docutils literal notranslate\">datetime.timedelta</code></a> 。</p>\n</li>\n<li><p><strong>我发现了很多告警：在时区支持激活后，DateTimeField 收到了 naive 日期时间((YYYY-MM-DD HH:MM:SS)) ——这样不好吗？</strong></p>\n<p>当启用时区支持后，数据库层会期望仅从你的代码里收到 aware 日期。这个告警发生在数据库收到 naive 日期时间时。这表明你没有为时区支持而完成代码移植。请参考 <a class=\"reference internal\" href=\"#time-zones-migration-guide\"><span class=\"std std-ref\">migration guide</span></a> 来获取此过程的提示。</p>\n<p>在这期间，为了向后兼容，日期时间被认为处于默认时区内，通常这是你期望的。</p>\n</li>\n<li><p><strong>为什么 ``now.date()`` 方法得到的结果是昨天（或明天）？</strong></p>\n<p>如果你一直在使用 naive 日期时间，你或许相信可以通过调用 <a class=\"reference external\" href=\"https://docs.python.org/3/library/datetime.html#datetime.datetime.date\" title=\"(in Python v3.14)\"><code class=\"xref py py-meth docutils literal notranslate\">date()</code></a> 方法来将日期时间转换为日期。你也认为 <a class=\"reference external\" href=\"https://docs.python.org/3/library/datetime.html#datetime.date\" title=\"(in Python v3.14)\"><code class=\"xref py py-class docutils literal notranslate\">date</code></a> 和 <a class=\"reference external\" href=\"https://docs.python.org/3/library/datetime.html#datetime.datetime\" title=\"(in Python v3.14)\"><code class=\"xref py py-class docutils literal notranslate\">datetime</code></a> 很像，除了它的准确性较差。</p>\n<p>在 aware 日期的环境里，这些都不是正确的：</p>\n<div class=\"code-block\" data-language=\"python\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span> <span class=\"nn\">datetime</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span> <span class=\"nn\">pytz</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>paris_tz <span class=\"o\">=</span> pytz<span class=\"o\">.</span>timezone<span class=\"p\">(</span><span class=\"s2\">&quot;Europe/Paris&quot;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>new_york_tz <span class=\"o\">=</span> pytz<span class=\"o\">.</span>timezone<span class=\"p\">(</span><span class=\"s2\">&quot;America/New_York&quot;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>paris <span class=\"o\">=</span> paris_tz<span class=\"o\">.</span>localize<span class=\"p\">(</span>datetime<span class=\"o\">.</span>datetime<span class=\"p\">(</span><span class=\"mi\">2012</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">30</span><span class=\"p\">))</span>\n<span class=\"go\"># This is the correct way to convert between time zones with pytz.</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>new_york <span class=\"o\">=</span> new_york_tz<span class=\"o\">.</span>normalize<span class=\"p\">(</span>paris<span class=\"o\">.</span>astimezone<span class=\"p\">(</span>new_york_tz<span class=\"p\">))</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>paris <span class=\"o\">==</span> new_york<span class=\"p\">,</span> paris<span class=\"o\">.</span>date<span class=\"p\">()</span> <span class=\"o\">==</span> new_york<span class=\"o\">.</span>date<span class=\"p\">()</span>\n<span class=\"go\">(True, False)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>paris <span class=\"o\">-</span> new_york<span class=\"p\">,</span> paris<span class=\"o\">.</span>date<span class=\"p\">()</span> <span class=\"o\">-</span> new_york<span class=\"o\">.</span>date<span class=\"p\">()</span>\n<span class=\"go\">(datetime.timedelta(0), datetime.timedelta(1))</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>paris\n<span class=\"go\">datetime.datetime(2012, 3, 3, 1, 30, tzinfo=&lt;DstTzInfo &#39;Europe/Paris&#39; CET+1:00:00 STD&gt;)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>new_york\n<span class=\"go\">datetime.datetime(2012, 3, 2, 19, 30, tzinfo=&lt;DstTzInfo &#39;America/New_York&#39; EST-1 day, 19:00:00 STD&gt;)</span>\n</code></pre></div>\n<p>如这个例子所示，相同 datetime 有不同的 date，这取决于它所代表的时区。但真实问题更重要。</p>\n<p>一个 datetime 代表一个 <strong>时间点</strong>。它是客观存在的，不依赖任何事物。另一方面，一个 date 是一个 <strong>日历概念</strong> 。它是一个时间段，其范围取决于 date 所在的时区。如你所见，这两个概念在根本上是不同的，将 datetime 转换为 date 并不是确定性的操作。</p>\n<p>这在实践中意味着什么？</p>\n<p>通常，你应该避免将 <a class=\"reference external\" href=\"https://docs.python.org/3/library/datetime.html#datetime.datetime\" title=\"(in Python v3.14)\"><code class=\"xref py py-class docutils literal notranslate\">datetime</code></a> 转换为 <a class=\"reference external\" href=\"https://docs.python.org/3/library/datetime.html#datetime.date\" title=\"(in Python v3.14)\"><code class=\"xref py py-class docutils literal notranslate\">date</code></a> 。比如，你可以使用 <a class=\"reference internal\" href=\"/zh-hans/3.0/ref/templates/builtins/#std-templatefilter-date\"><code class=\"xref std std-tfilter docutils literal notranslate\">date</code></a> 模板过滤器来只展示 datetime 的 date 部分。这个过滤器在格式化之前将 datetime 转换为为 当前时间，确保显示正确的结果。</p>\n<p>如果你确实需要自己进行转换，你必须首先确保 datetime 转换为合适的时区。通常，这将是当前时区：</p>\n<div class=\"code-block\" data-language=\"python\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span> <span class=\"nn\">django.utils</span> <span class=\"kn\">import</span> timezone\n<span class=\"gp\">&gt;&gt;&gt; </span>timezone<span class=\"o\">.</span>activate<span class=\"p\">(</span>pytz<span class=\"o\">.</span>timezone<span class=\"p\">(</span><span class=\"s2\">&quot;Asia/Singapore&quot;</span><span class=\"p\">))</span>\n<span class=\"go\"># For this example, we set the time zone to Singapore, but here&#39;s how</span>\n<span class=\"go\"># you would obtain the current time zone in the general case.</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>current_tz <span class=\"o\">=</span> timezone<span class=\"o\">.</span>get_current_timezone<span class=\"p\">()</span>\n<span class=\"go\"># Again, this is the correct way to convert between time zones with pytz.</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>local <span class=\"o\">=</span> current_tz<span class=\"o\">.</span>normalize<span class=\"p\">(</span>paris<span class=\"o\">.</span>astimezone<span class=\"p\">(</span>current_tz<span class=\"p\">))</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>local\n<span class=\"go\">datetime.datetime(2012, 3, 3, 8, 30, tzinfo=&lt;DstTzInfo &#39;Asia/Singapore&#39; SGT+8:00:00 STD&gt;)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>local<span class=\"o\">.</span>date<span class=\"p\">()</span>\n<span class=\"go\">datetime.date(2012, 3, 3)</span>\n</code></pre></div>\n</li>\n<li><p><strong>收到“你的数据库安装时区定义了吗？”的错误</strong></p>\n<p>如果你正在使用 MySQL，查看  <a class=\"reference internal\" href=\"/zh-hans/3.0/ref/databases/#mysql-time-zone-definitions\"><span class=\"std std-ref\">Time zone definitions</span></a>  部分，以获取有关加载时区定义的说明。</p>\n</li>\n</ol>\n</section>\n<section id=\"usage\">\n<h3>用法<a class=\"heading-anchor\" href=\"#usage\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<ol class=\"arabic\">\n<li><p><strong>有一个字符串</strong> <code class=\"docutils literal notranslate\">&quot;2012-02-21 10:28:45&quot;</code> <strong>并且时区是</strong> <code class=\"docutils literal notranslate\">&quot;Europe/Helsinki&quot;</code> <strong>。我该如何将其转换为 aware 日期时间？</strong></p>\n<p>这正是 <a class=\"reference external\" href=\"http://pytz.sourceforge.net/\">pytz</a> 的用途。</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span> <span class=\"nn\">django.utils.dateparse</span> <span class=\"kn\">import</span> parse_datetime\n<span class=\"gp\">&gt;&gt;&gt; </span>naive <span class=\"o\">=</span> parse_datetime<span class=\"p\">(</span><span class=\"s2\">&quot;2012-02-21 10:28:45&quot;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span> <span class=\"nn\">pytz</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>pytz<span class=\"o\">.</span>timezone<span class=\"p\">(</span><span class=\"s2\">&quot;Europe/Helsinki&quot;</span><span class=\"p\">)</span><span class=\"o\">.</span>localize<span class=\"p\">(</span>naive<span class=\"p\">,</span> is_dst<span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">)</span>\n<span class=\"go\">datetime.datetime(2012, 2, 21, 10, 28, 45, tzinfo=&lt;DstTzInfo &#39;Europe/Helsinki&#39; EET+2:00:00 STD&gt;)</span>\n</code></pre></div>\n<p>注意 <code class=\"docutils literal notranslate\">localize</code> 是 <a class=\"reference external\" href=\"https://docs.python.org/3/library/datetime.html#datetime.tzinfo\" title=\"(in Python v3.14)\"><code class=\"xref py py-class docutils literal notranslate\">tzinfo</code></a> 的 pytz 扩展。另外，你或许想捕捉 <code class=\"docutils literal notranslate\">pytz.InvalidTimeError</code>。pytz 的文档包含了很多例子（ <a class=\"reference external\" href=\"http://pytz.sourceforge.net/#example-usage\">more examples</a> ）。你应该在尝试操作 aware 日期时间之前看一下它。</p>\n</li>\n<li><p><strong>如何在当前时区里获取当地时间？</strong></p>\n<p>好吧，首先要问下自己，你真的需要这么做吗？</p>\n<p>当与用户进行交互的时候，你只能使用当地时间，并且在模板层提供过滤器和标签，将日期时间转换为你所选择的时区。</p>\n<p>而且，Python 知道如何去比较 aware 日期时间，并在必要时考虑 UTC 偏移量。使用 UTC 编写所有模型和视图代码里很容易（并且可能很快）。因此，在大部分情况下，由 <a class=\"reference internal\" href=\"/zh-hans/3.0/ref/utils/#django.utils.timezone.now\" title=\"django.utils.timezone.now\"><code class=\"xref py py-func docutils literal notranslate\">django.utils.timezone.now()</code></a> 返回的 UTC 日期时间足够了。</p>\n<p>但是，为了完整性，如果你真的想在当前时区里获取当地时间，你可以这么做：</p>\n<div class=\"code-block\" data-language=\"python\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span> <span class=\"nn\">django.utils</span> <span class=\"kn\">import</span> timezone\n<span class=\"gp\">&gt;&gt;&gt; </span>timezone<span class=\"o\">.</span>localtime<span class=\"p\">(</span>timezone<span class=\"o\">.</span>now<span class=\"p\">())</span>\n<span class=\"go\">datetime.datetime(2012, 3, 3, 20, 10, 53, 873365, tzinfo=&lt;DstTzInfo &#39;Europe/Paris&#39; CET+1:00:00 STD&gt;)</span>\n</code></pre></div>\n<p>在这个例子里，当前时区是 <code class=\"docutils literal notranslate\">&quot;Europe/Paris&quot;</code> 。</p>\n</li>\n<li><p>如何查看所有可用时区？</p>\n<p><a class=\"reference external\" href=\"http://pytz.sourceforge.net/\">pytz</a> 提供了 <a class=\"reference external\" href=\"http://pytz.sourceforge.net/#helpers\">helpers</a> ，包含当前时区列表以及所有可用时区列表 —— 其中一些时区仅具有历史意义。</p>\n</li>\n</ol>\n</section>\n</section>","rootId":"time-zones","toc":[{"title":"概况","anchor":"overview","children":[]},{"title":"概念","anchor":"concepts","children":[{"title":"Naive 日期对象与 Aware 日期对象","anchor":"naive-and-aware-datetime-objects","children":[]},{"title":"Naive 日期对象的说明","anchor":"interpretation-of-naive-datetime-objects","children":[]},{"title":"默认时区和当前时区","anchor":"default-time-zone-and-current-time-zone","children":[]},{"title":"选择当前时区","anchor":"selecting-the-current-time-zone","children":[]}]},{"title":"表单里的时区感知(aware)输入","anchor":"time-zone-aware-input-in-forms","children":[]},{"title":"模板中时区感知(aware)输出","anchor":"time-zone-aware-output-in-templates","children":[{"title":"模板标签","anchor":"template-tags","children":[{"title":"localtime","anchor":"localtime","children":[]},{"title":"timezone","anchor":"timezone","children":[]},{"title":"get_current_timezone","anchor":"get-current-timezone","children":[]}]},{"title":"模板过滤器","anchor":"template-filters","children":[{"title":"localtime","anchor":"std-templatefilter-localtime","children":[]},{"title":"utc","anchor":"utc","children":[]},{"title":"timezone","anchor":"std-templatefilter-timezone","children":[]}]}]},{"title":"迁移指南","anchor":"migration-guide","children":[{"title":"数据库","anchor":"database","children":[{"title":"PostgreSQL","anchor":"postgresql","children":[]},{"title":"其他数据库","anchor":"other-databases","children":[]}]},{"title":"邮政编码","anchor":"code","children":[]},{"title":"辅助工具","anchor":"fixtures","children":[]}]},{"title":"FAQ","anchor":"faq","children":[{"title":"安装","anchor":"setup","children":[]},{"title":"错误调试","anchor":"troubleshooting","children":[]},{"title":"用法","anchor":"usage","children":[]}]}],"breadcrumbs":[{"docname":"topics/index","title":"使用 Django","url":"/zh-hans/3.0/topics/"},{"docname":"topics/i18n/index","title":"国际化和本地化","url":"/zh-hans/3.0/topics/i18n/"}],"prev":{"docname":"topics/i18n/formatting","title":"本地格式化","url":"/zh-hans/3.0/topics/i18n/formatting/"},"next":{"docname":"topics/logging","title":"日志","url":"/zh-hans/3.0/topics/logging/"},"formats":{"html":"/zh-hans/3.0/topics/i18n/timezones/","markdown":"/zh-hans/3.0/topics/i18n/timezones.md","json":"/zh-hans/3.0/topics/i18n/timezones.json"},"source":"https://github.com/django/django/blob/stable/3.0.x/docs/topics/i18n/timezones.txt","official":"https://docs.djangoproject.com/zh-hans/3.0/topics/i18n/timezones/","inVersions":["6.1","6.0","5.2","5.1","5.0","4.2","4.1","4.0","3.2","3.1","3.0","2.2","2.1","2.0"],"inLocales":["en","zh-hans","fr","ja","id","pt-br","ko","es","el","pl"]}