{"title":"时区","version":"5.2","locale":"zh-hans","docname":"topics/i18n/timezones","url":"/zh-hans/5.2/topics/i18n/timezones/","canonical":"https://djangodocs.dev/zh-hans/5.2/topics/i18n/timezones/","summary":"When support for time zones is enabled, Django stores datetime information in UTC in the database, uses time-zone-aware datetime objects internally, and…","html":"<h1>时区<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>When support for time zones is enabled, Django stores datetime information in\nUTC in the database, uses time-zone-aware datetime objects internally, and\nconverts them to the end user's time zone in forms. Templates will use the\n<a class=\"reference internal\" href=\"#default-current-time-zone\"><span class=\"std std-ref\">default time zone</span></a>, but this can be updated\nto the end user's time zone through the use of <a class=\"reference internal\" href=\"#time-zones-in-templates\"><span class=\"std std-ref\">filters and tags</span></a>.</p>\n<p>如果用户居住在多个时区时，这会很方便。你要根据用户的时间来显示日期信息。</p>\n<p>即使你的网站只在一个时区提供服务，在你的数据库中用 UTC 存储数据仍然是一个好的做法。主要原因是夏令时（DST）。许多国家都有一个 DST 系统，春天的时钟会向前移动，秋天的时钟会向后移动。当转换发生时，如果你使用当地时间工作，你很可能会遇到一年两次的错误。这可能对你的博客并不重要，但如果你每年向客户多收或少收一个小时的费用，每年两次，这就是一个问题。解决这个问题的办法是在代码中使用 UTC，只在与终端用户互动时使用当地时间。</p>\n<p>时区支持默认启用。要禁用它，在你的设置文件中设置 <a class=\"reference internal\" href=\"/zh-hans/5.2/ref/settings/#std-setting-USE_TZ\"><code class=\"xref std std-setting docutils literal notranslate\">USE_TZ = False</code></a>。</p>\n<p>时区支持使用 <a class=\"reference external\" href=\"https://docs.python.org/3/library/zoneinfo.html#module-zoneinfo\" title=\"(in Python v3.14)\"><code class=\"xref py py-mod docutils literal notranslate\">zoneinfo</code></a>，它是从 Python 3.9 开始包含在 Python 标准库中的一部分。</p>\n<p>如果你正在解决一个特定问题，请从阅读 <a class=\"reference internal\" href=\"#time-zones-faq\"><span class=\"std std-ref\">时区常见问题</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>无时区日期时间对象与有时区日期对象<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>有时区</strong> 的，否则就是 <strong>无时区</strong> 的。</p>\n<p>你可以使用 <a class=\"reference internal\" href=\"/zh-hans/5.2/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/5.2/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> 来确定日期时间是有时区的还是无时区的。</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/5.2/ref/settings/#std-setting-USE_TZ\"><code class=\"xref std std-setting docutils literal notranslate\">USE_TZ=True</code></a>) ，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\">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>处理有时区日期时间对象并不总是直观的。例如，标准日期时间构造函数的 <code class=\"docutils literal notranslate\">tzinfo</code> 参数对于 DST 的时区并不可靠。使用 UTC 通常是安全的；如果你使用其他时区，你应该仔细查看 <a class=\"reference external\" href=\"https://docs.python.org/3/library/zoneinfo.html#module-zoneinfo\" title=\"(in Python v3.14)\"><code class=\"xref py py-mod docutils literal notranslate\">zoneinfo</code></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 只支持无时区时间对象，如果打算保存有时区时间对象会引发异常，因为没有关联日期的有时区时间是没有意义的。</p>\n</aside>\n</section>\n<section id=\"interpretation-of-naive-datetime-objects\">\n<span id=\"naive-datetime-objects\"></span><h3>无时区日期时间对象的说明<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/5.2/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 仍然接受无时区日期时间对象，以保持向后兼容。当数据库层收到一个无时区日期时间对象，会试着用 <a class=\"reference internal\" href=\"#default-current-time-zone\"><span class=\"std std-ref\">默认时区</span></a> 进行解释将其变为有时区日期对象，并发出警告。</p>\n<p>不幸的是，在 DST 转换期间，一些日期时间不存在或不明确。这就是为什么你应该在启用时区支持时创建有时区日期时间对象。（参见 <a class=\"reference external\" href=\"https://docs.python.org/3/library/zoneinfo.html#module-zoneinfo\" title=\"(in Python v3.14)\"><code class=\"xref py py-mod docutils literal notranslate\">zoneinfo 文档的使用 ZoneInfo 章节</code></a> ，了解使用 <code class=\"docutils literal notranslate\">fold</code> 属性来指定在 DST 过渡期间应该适用于日期时间的偏移量的例子。)</p>\n<p>实际上，这种情况很罕见。Django 在模型和表单里为你提供了有时区日期时间对象，并且在大部分时候，新的日期时间对象是通过 <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/5.2/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/5.2/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>你应该用 <code class=\"xref py py-func docutils literal notranslate\">activated()</code> 将当前时区设置为终端用户的实际时区。否则，将使用默认的时区。</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/5.2/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/5.2/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/5.2/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> 时，这对于与仍然依赖本地时间的应用程序保持向后兼容性是有用的。然而，正如上面所解释的，这并不完全可靠，你应该始终在你自己的代码中使用 UTC 的 aware datetimes。例如，使用 <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 external\" href=\"https://docs.python.org/3/library/datetime.html#datetime.timezone.utc\" title=\"(in Python v3.14)\"><code class=\"xref py py-attr 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>当前时区相当于当前 <a class=\"reference internal\" href=\"/zh-hans/5.2/topics/i18n/#term-locale-name\"><span class=\"xref std std-term\">区域</span></a> 。但是，Django 没有可用于自动确定用户时区的如  <code class=\"docutils literal notranslate\">Accept-Language</code> 的 HTTP 头。相反，Django 提供了 <a class=\"reference internal\" href=\"/zh-hans/5.2/ref/utils/#time-zone-selection-functions\"><span class=\"std std-ref\">时区选择函数</span></a> 。使用它们来建立对你有用的时区选择逻辑。</p>\n<p>大多数关心时区的网站都会询问用户居住在哪个时区，并将这些信息存储在用户的个人资料中。<a class=\"reference external\" href=\"https://docs.python.org/3/library/zoneinfo.html#zoneinfo.available_timezones\" title=\"(in Python v3.14)\"><code class=\"xref py py-func docutils literal notranslate\">zoneinfo.available_timezones()</code></a> 提供了一组可用的时区，你可以用它来建立一个从可能的地点到时区的映射。</p>\n<p>这里有个在会话(session)里存储当前时区的例子。（为简单起见，它完全跳过了错误处理）</p>\n<p>在 <a class=\"reference internal\" href=\"/zh-hans/5.2/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\">zoneinfo</span>\n\n<span class=\"kn\">from</span> <span class=\"nn\">django.utils</span> <span class=\"kn\">import</span> timezone\n\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=\"s2\">&quot;django_timezone&quot;</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>zoneinfo<span class=\"o\">.</span>ZoneInfo<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=\"c1\"># Prepare a map of common locations to timezone choices you wish to offer.</span>\ncommon_timezones <span class=\"o\">=</span> <span class=\"p\">{</span>\n    <span class=\"s2\">&quot;London&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Europe/London&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;Paris&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Europe/Paris&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;New York&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;America/New_York&quot;</span><span class=\"p\">,</span>\n<span class=\"p\">}</span>\n\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=\"s2\">&quot;POST&quot;</span><span class=\"p\">:</span>\n        request<span class=\"o\">.</span>session<span class=\"p\">[</span><span class=\"s2\">&quot;django_timezone&quot;</span><span class=\"p\">]</span> <span class=\"o\">=</span> request<span class=\"o\">.</span>POST<span class=\"p\">[</span><span class=\"s2\">&quot;timezone&quot;</span><span class=\"p\">]</span>\n        <span class=\"k\">return</span> redirect<span class=\"p\">(</span><span class=\"s2\">&quot;/&quot;</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=\"s2\">&quot;template.html&quot;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s2\">&quot;timezones&quot;</span><span class=\"p\">:</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\">city</span><span class=\"o\">,</span> <span class=\"nv\">tz</span> <span class=\"k\">in</span> <span class=\"nv\">timezones.items</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\">city</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>表单里有时区的输入<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会以 <a class=\"reference internal\" href=\"#default-current-time-zone\"><span class=\"std std-ref\">当前时区</span></a> 解释表单中输入的日期时间，并且在 <code class=\"docutils literal notranslate\">cleaned_data</code> 中返回有时区日期时间对象。</p>\n<p>转换后的数据时间如果不存在，或者因为属于夏令时过渡期而含糊不清，将被报告为无效的值。</p>\n</section>\n<section id=\"time-zone-aware-output-in-templates\">\n<span id=\"time-zones-in-templates\"></span><h2>模板中有时区的输出<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 会在模板中渲染有时区日期时间时，将其转换为当前时区。这非常类似于 <a class=\"reference internal\" href=\"/zh-hans/5.2/topics/i18n/formatting/\"><span class=\"doc\">格式本地化</span></a> 。</p>\n<aside class=\"admonition admonition-warning\" role=\"note\">\n<p class=\"admonition-title\">Warning</p>\n<p>Django 不会转换无时区日期时间对象，因为它们是含糊不清的，而且当开启了时区支持后，你的代码里绝不应该生成无时区日期时间。但是，你可以使用下面描述的模板过滤器来强制转换。</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>在包含块里开启或关闭将有时区日期时间对象的转换为当前时区。</p>\n<p>就模板引擎而言，该标签与 <a class=\"reference internal\" href=\"/zh-hans/5.2/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/5.2/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/5.2/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>这些过滤器接受有时区日期时间和无时区日期时间。出于转换目的，它们假设无时区日期时间在默认时区中。它们始终返回有时区日期时间。</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/5.2/ref/settings/#std-setting-DATABASE-TIME_ZONE\"><code class=\"xref std std-setting docutils literal notranslate\">DATABASE-TIME_ZONE</code></a> 或 <code class=\"docutils literal notranslate\">UTC</code>，这样 Django 在所有情况下都能获得正确的日期时间。您无需执行任何数据转换。</p>\n<aside class=\"admonition-time-zone-settings admonition\" role=\"note\">\n<p class=\"admonition-title\">时区设置</p>\n<p>在 <a class=\"reference internal\" href=\"/zh-hans/5.2/ref/settings/#std-setting-DATABASES\"><code class=\"xref std std-setting docutils literal notranslate\">DATABASES</code></a> 设置中配置的连接的时区与通用的 <a class=\"reference internal\" href=\"/zh-hans/5.2/ref/settings/#std-setting-DATABASE-TIME_ZONE\"><code class=\"xref std std-setting docutils literal notranslate\">TIME_ZONE</code></a> 设置是不同的。</p>\n</aside>\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/5.2/ref/settings/#std-setting-USE_TZ\"><code class=\"xref std std-setting docutils literal notranslate\">USE_TZ = True</code></a> 添加到你的配置文件里。在这点上，大多数情况下都应该起作用。如果你在代码里创建无时区日期时间对象，Django 会在必要时将它们转换为有时区日期时间对象。</p>\n<p>然而，这些转换有可能在夏令时转换时失败，这意味着你并没有获得时区支持的所有好处。而且，在运行的时候很可能会遇到一些问题，因为它无法将无时区日期时间和有时区日期时间进行比较。由于 Django 现在为你提供了 有时区时间，你在比较来自模型或表单的日期与代码里创建的无时区日期时间时，会遇到一些异常。</p>\n<p>第二步是重构你在任何地方实例化的日期时间，将它们转换为有时区日期时间。这可以逐步完成。<a class=\"reference internal\" href=\"/zh-hans/5.2/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/5.2/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/5.2/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/5.2/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/5.2/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/5.2/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>最后，为了帮助你找到需要升级的代码，当你尝试将一个 naive datetime 保存到数据库时，Django 会引发警告：</p>\n<div class=\"code-block\" data-language=\"pytb\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Pytb</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=\"Pytb code\"><code><span class=\"x\">RuntimeWarning: DateTimeField ModelName.field_name received a naive</span>\n<span class=\"x\">datetime (2012-01-01 00:00:00) while time zone support is active.</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\">import</span> <span class=\"nn\">warnings</span>\n\nwarnings<span class=\"o\">.</span>filterwarnings<span class=\"p\">(</span>\n    <span class=\"s2\">&quot;error&quot;</span><span class=\"p\">,</span>\n    <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>\n    <span class=\"sa\">r</span><span class=\"s2\">&quot;django\\.db\\.models\\.fields&quot;</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>当序列化有时区日期时间时，会包含 UTC 偏移，如下：</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=\"s2\">&quot;2011-09-01T13:20:30+03:00&quot;</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=\"s2\">&quot;2011-09-01T13:20:30&quot;</span>\n</code></pre></div>\n<p>对于带有 <a class=\"reference internal\" href=\"/zh-hans/5.2/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 版本之前，使用“无时区”格式化。如果你的项目包含这些辅助工具，则在开始时区支持后，你将会在加载它们时，看到 <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> 。为了避免这些警告，你必须将辅助工具转换为“有时区”格式。</p>\n<p>你可以先使用 <a class=\"reference internal\" href=\"/zh-hans/5.2/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/5.2/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/5.2/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>常见问题<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 会使用一个更准确的本地时间模型。这可以让你避免在夏令时（DST）转换时出现细微的、不可再现的错误。</p>\n<p>开启时区支持后，会遇到一些错误，因为你使用无时区日期时间，而 Django 期望使用有时区日期时间。这些错误在运行测试的时候会显示出来。你会很快学会如何避免错误的操作。</p>\n<p>另一方面，由于缺乏时区支持而导致的错误更难预防、诊断和修复。任何涉及到计划任务或日期时间运算的东西都是微妙错误的候选者，这些错误一年只影响你一次或两次。</p>\n<p>由于这些原因，时区支持在新项目中是默认启用的，除非你有非常好的理由不这样做，否则你应该保持它。</p>\n</li>\n<li><p><strong>我已经开启了时区支持。我安全了吗？</strong></p>\n<p>也许吧。你可以更好地避免与 DST 有关的错误，但你仍然可以通过不小心把无时区日期时间变成有时区日期时间，反之亦然。</p>\n<p>如果你的应用程序连接到其他系统——例如，如果它查询一个网络服务——请确保日期时间被正确指定。为了安全地传输日期，它们的表示应该包括 UTC 的偏移量，或者它们的值应该是 UTC 的（或者两者都是！）。</p>\n<p>最后，我们的日历系统包含一些有趣的边界情况。例如，你不能总是直接从给定的日期减去一年：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</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 console 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\"># Wrong example.</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\">...</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 减去一年是 2011-02-28 还是 2011-03-01，这取决于你的业务需求。</p>\n</li>\n<li><p><strong>我该如何与存储本地日期时间的数据库进行交互？</strong></p>\n<p>在 <a class=\"reference internal\" href=\"/zh-hans/5.2/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/5.2/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>我的程序因不能比较带有偏移的无时区日期时间与带有偏移的有时区日期时间而崩溃——怎么回事？</strong></p>\n<p>让我们通过比较一个 naive 和一个 aware datetime 来重现这个错误：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</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 console 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>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> timezone<span class=\"o\">.</span>make_naive<span class=\"p\">(</span>aware<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 支持的日期——比如，读取来自表单或模型字段的值。因为你开启了时区支持，所以它是有时区的。</p></li>\n<li><p>通过代码生成了日期时间，它是无时区的（否则你就不会读到这里）。</p></li>\n</ul>\n<p>一般来说，正确的解决办法是修改代码，用有时区日期时间代替它。</p>\n<p>如果你正在编写可插拔的应用独立于 <a class=\"reference internal\" href=\"/zh-hans/5.2/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/5.2/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>  时将当前日期和时间以无时区返回，并且在 <code class=\"docutils literal notranslate\">USE_TZ = True</code> 时将当前日期和时间以有时区返回。你可以在需要时添加或减少 <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>我发现了很多告警：</strong> <code class=\"docutils literal notranslate\">RuntimeWarning: DateTimeField received a naive datetime</code> <code class=\"docutils literal notranslate\">(YYYY-MM-DD HH:MM:SS)</code> <code class=\"docutils literal notranslate\">while time zone support is active</code> <strong>——这样不好吗？</strong></p>\n<p>当启用时区支持后，数据库层会期望仅从你的代码里收到有时区日期时间。这个告警发生在数据库收到无时区日期时间时。这表明你没有为时区支持而完成代码移植。请参考 <a class=\"reference internal\" href=\"#time-zones-migration-guide\"><span class=\"std std-ref\">迁移指南</span></a> 来获取此过程的提示。</p>\n<p>在这期间，为了向后兼容，日期时间被认为处于默认时区内，通常这是你期望的。</p>\n</li>\n<li><p><code class=\"docutils literal notranslate\">now.date()</code> 方法得到的结果 <strong>为什么是昨天（或明天）？</strong></p>\n<p>如果你一直在使用无时区日期时间，你或许相信可以通过调用 <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>在时区感知的环境中，这些都不成立：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</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 console 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\">zoneinfo</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>paris_tz <span class=\"o\">=</span> zoneinfo<span class=\"o\">.</span>ZoneInfo<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> zoneinfo<span class=\"o\">.</span>ZoneInfo<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> 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> tzinfo<span class=\"o\">=</span>paris_tz<span class=\"p\">)</span>\n<span class=\"go\"># This is the correct way to convert between time zones.</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>new_york <span class=\"o\">=</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=zoneinfo.ZoneInfo(key=&#39;Europe/Paris&#39;))</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>new_york\n<span class=\"go\">datetime.datetime(2012, 3, 2, 19, 30, tzinfo=zoneinfo.ZoneInfo(key=&#39;America/New_York&#39;))</span>\n</code></pre></div>\n<p>正如这个例子所显示的，同一个日期时间有不同的日期，这取决于它所代表的时区。但真正的问题是更基本的。</p>\n<p>一个日期时间代表一个 <strong>时间点</strong>。它是绝对的，不依赖任何事物。另一方面，一个日期是一个 <strong>计算概念</strong> 。它是一个时间段，其范围取决于日期所在的时区。如你所见，这两个概念在根本上是不同的，将日期时间转换为日期并不是确定性的操作。</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/5.2/ref/templates/builtins/#std-templatefilter-date\"><code class=\"xref std std-tfilter docutils literal notranslate\">date</code></a> 模板过滤器来只展示日期时间的日期部分。这个过滤器在格式化之前将日期时间转换为为当前时间，确保显示正确的结果。</p>\n<p>如果你真的需要自己进行转换，你必须确保首先将 datetime 转换为适当的时区。通常，这将是当前时区：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</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 console 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>zoneinfo<span class=\"o\">.</span>ZoneInfo<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=\"gp\">&gt;&gt;&gt; </span>local <span class=\"o\">=</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=zoneinfo.ZoneInfo(key=&#39;Asia/Singapore&#39;))</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/5.2/ref/databases/#mysql-time-zone-definitions\"><span class=\"std std-ref\">时区定义</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>。我该如何将其转换为有时区日期时间？</strong></p>\n<p>在这里，你需要创建所需的 <code class=\"docutils literal notranslate\">ZoneInfo</code> 实例并将其附加到 naive datetime：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</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 console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span> <span class=\"nn\">zoneinfo</span>\n<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>naive<span class=\"o\">.</span>replace<span class=\"p\">(</span>tzinfo<span class=\"o\">=</span>zoneinfo<span class=\"o\">.</span>ZoneInfo<span class=\"p\">(</span><span class=\"s2\">&quot;Europe/Helsinki&quot;</span><span class=\"p\">))</span>\n<span class=\"go\">datetime.datetime(2012, 2, 21, 10, 28, 45, tzinfo=zoneinfo.ZoneInfo(key=&#39;Europe/Helsinki&#39;))</span>\n</code></pre></div>\n</li>\n<li><p><strong>如何在当前时区里获取当地时间？</strong></p>\n<p>好吧，首先要问下自己，你真的需要这么做吗？</p>\n<p>当与用户进行交互的时候，你应该只使用当地时间，模板层提供了:ref:过滤器和标签 &lt;time-zones-in-templates&gt; 来将日期时间转换为你选择的时区。</p>\n<p>而且，Python 知道如何去比较有时区日期时间，并在必要时考虑 UTC 偏移量。使用 UTC 编写所有模型和视图代码里很容易（并且可能很快）。因此，在大部分情况下，由 <a class=\"reference internal\" href=\"/zh-hans/5.2/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=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</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 console 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=zoneinfo.ZoneInfo(key=&#39;Europe/Paris&#39;))</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=\"https://docs.python.org/3/library/zoneinfo.html#zoneinfo.available_timezones\" title=\"(in Python v3.14)\"><code class=\"xref py py-func docutils literal notranslate\">zoneinfo.available_timezones()</code></a> 为你的系统提供 IANA 时区的所有有效键集。关于使用注意事项，请参见文档。</p>\n</li>\n</ol>\n</section>\n</section>","rootId":"time-zones","toc":[{"title":"概况","anchor":"overview","children":[]},{"title":"概念","anchor":"concepts","children":[{"title":"无时区日期时间对象与有时区日期对象","anchor":"naive-and-aware-datetime-objects","children":[]},{"title":"无时区日期时间对象的说明","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":"表单里有时区的输入","anchor":"time-zone-aware-input-in-forms","children":[]},{"title":"模板中有时区的输出","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":"常见问题","anchor":"faq","children":[{"title":"安装","anchor":"setup","children":[]},{"title":"错误调试","anchor":"troubleshooting","children":[]},{"title":"用法","anchor":"usage","children":[]}]}],"breadcrumbs":[{"docname":"topics/index","title":"使用 Django","url":"/zh-hans/5.2/topics/"},{"docname":"topics/i18n/index","title":"国际化和本地化","url":"/zh-hans/5.2/topics/i18n/"}],"prev":{"docname":"topics/i18n/formatting","title":"本地格式化","url":"/zh-hans/5.2/topics/i18n/formatting/"},"next":{"docname":"topics/logging","title":"日志","url":"/zh-hans/5.2/topics/logging/"},"formats":{"html":"/zh-hans/5.2/topics/i18n/timezones/","markdown":"/zh-hans/5.2/topics/i18n/timezones.md","json":"/zh-hans/5.2/topics/i18n/timezones.json"},"source":"https://github.com/django/django/blob/stable/5.2.x/docs/topics/i18n/timezones.txt","official":"https://docs.djangoproject.com/zh-hans/5.2/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","sv","zh-hans","ga","fr","ja","id","it","pt-br","ko","es","el","pl"]}