mirror of https://github.com/python/peps
1005 lines
91 KiB
HTML
1005 lines
91 KiB
HTML
|
||
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<meta name="color-scheme" content="light dark">
|
||
<title>PEP 495 – Local Time Disambiguation | peps.python.org</title>
|
||
<link rel="shortcut icon" href="../_static/py.png">
|
||
<link rel="canonical" href="https://peps.python.org/pep-0495/">
|
||
<link rel="stylesheet" href="../_static/style.css" type="text/css">
|
||
<link rel="stylesheet" href="../_static/mq.css" type="text/css">
|
||
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" media="(prefers-color-scheme: light)" id="pyg-light">
|
||
<link rel="stylesheet" href="../_static/pygments_dark.css" type="text/css" media="(prefers-color-scheme: dark)" id="pyg-dark">
|
||
<link rel="alternate" type="application/rss+xml" title="Latest PEPs" href="https://peps.python.org/peps.rss">
|
||
<meta property="og:title" content='PEP 495 – Local Time Disambiguation | peps.python.org'>
|
||
<meta property="og:type" content="website">
|
||
<meta property="og:url" content="https://peps.python.org/pep-0495/">
|
||
<meta property="og:site_name" content="Python Enhancement Proposals (PEPs)">
|
||
<meta property="og:image" content="https://peps.python.org/_static/og-image.png">
|
||
<meta property="og:image:alt" content="Python PEPs">
|
||
<meta property="og:image:width" content="200">
|
||
<meta property="og:image:height" content="200">
|
||
<meta name="description" content="Python Enhancement Proposals (PEPs)">
|
||
<meta name="theme-color" content="#3776ab">
|
||
</head>
|
||
<body>
|
||
|
||
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
|
||
<symbol id="svg-sun-half" viewBox="0 0 24 24" pointer-events="all">
|
||
<title>Following system colour scheme</title>
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
|
||
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<circle cx="12" cy="12" r="9"></circle>
|
||
<path d="M12 3v18m0-12l4.65-4.65M12 14.3l7.37-7.37M12 19.6l8.85-8.85"></path>
|
||
</svg>
|
||
</symbol>
|
||
<symbol id="svg-moon" viewBox="0 0 24 24" pointer-events="all">
|
||
<title>Selected dark colour scheme</title>
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
|
||
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||
<path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path>
|
||
</svg>
|
||
</symbol>
|
||
<symbol id="svg-sun" viewBox="0 0 24 24" pointer-events="all">
|
||
<title>Selected light colour scheme</title>
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
|
||
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<circle cx="12" cy="12" r="5"></circle>
|
||
<line x1="12" y1="1" x2="12" y2="3"></line>
|
||
<line x1="12" y1="21" x2="12" y2="23"></line>
|
||
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
|
||
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
|
||
<line x1="1" y1="12" x2="3" y2="12"></line>
|
||
<line x1="21" y1="12" x2="23" y2="12"></line>
|
||
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
|
||
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
|
||
</svg>
|
||
</symbol>
|
||
</svg>
|
||
<script>
|
||
|
||
document.documentElement.dataset.colour_scheme = localStorage.getItem("colour_scheme") || "auto"
|
||
</script>
|
||
<section id="pep-page-section">
|
||
<header>
|
||
<h1>Python Enhancement Proposals</h1>
|
||
<ul class="breadcrumbs">
|
||
<li><a href="https://www.python.org/" title="The Python Programming Language">Python</a> » </li>
|
||
<li><a href="../pep-0000/">PEP Index</a> » </li>
|
||
<li>PEP 495</li>
|
||
</ul>
|
||
<button id="colour-scheme-cycler" onClick="setColourScheme(nextColourScheme())">
|
||
<svg aria-hidden="true" class="colour-scheme-icon-when-auto"><use href="#svg-sun-half"></use></svg>
|
||
<svg aria-hidden="true" class="colour-scheme-icon-when-dark"><use href="#svg-moon"></use></svg>
|
||
<svg aria-hidden="true" class="colour-scheme-icon-when-light"><use href="#svg-sun"></use></svg>
|
||
<span class="visually-hidden">Toggle light / dark / auto colour theme</span>
|
||
</button>
|
||
</header>
|
||
<article>
|
||
<section id="pep-content">
|
||
<h1 class="page-title">PEP 495 – Local Time Disambiguation</h1>
|
||
<dl class="rfc2822 field-list simple">
|
||
<dt class="field-odd">Author<span class="colon">:</span></dt>
|
||
<dd class="field-odd">Alexander Belopolsky <alexander.belopolsky at gmail.com>, Tim Peters <tim.peters at gmail.com></dd>
|
||
<dt class="field-even">Discussions-To<span class="colon">:</span></dt>
|
||
<dd class="field-even"><a class="reference external" href="https://mail.python.org/archives/list/datetime-sig@python.org/">Datetime-SIG list</a></dd>
|
||
<dt class="field-odd">Status<span class="colon">:</span></dt>
|
||
<dd class="field-odd"><abbr title="Accepted and implementation complete, or no longer active">Final</abbr></dd>
|
||
<dt class="field-even">Type<span class="colon">:</span></dt>
|
||
<dd class="field-even"><abbr title="Normative PEP with a new feature for Python, implementation change for CPython or interoperability standard for the ecosystem">Standards Track</abbr></dd>
|
||
<dt class="field-odd">Created<span class="colon">:</span></dt>
|
||
<dd class="field-odd">02-Aug-2015</dd>
|
||
<dt class="field-even">Python-Version<span class="colon">:</span></dt>
|
||
<dd class="field-even">3.6</dd>
|
||
<dt class="field-odd">Resolution<span class="colon">:</span></dt>
|
||
<dd class="field-odd"><a class="reference external" href="https://mail.python.org/pipermail/datetime-sig/2015-September/000900.html">Datetime-SIG message</a></dd>
|
||
</dl>
|
||
<hr class="docutils" />
|
||
<section id="contents">
|
||
<details><summary>Table of Contents</summary><ul class="simple">
|
||
<li><a class="reference internal" href="#abstract">Abstract</a></li>
|
||
<li><a class="reference internal" href="#rationale">Rationale</a></li>
|
||
<li><a class="reference internal" href="#terminology">Terminology</a></li>
|
||
<li><a class="reference internal" href="#proposal">Proposal</a><ul>
|
||
<li><a class="reference internal" href="#the-fold-attribute">The “fold” attribute</a></li>
|
||
<li><a class="reference internal" href="#affected-apis">Affected APIs</a><ul>
|
||
<li><a class="reference internal" href="#attributes">Attributes</a></li>
|
||
<li><a class="reference internal" href="#constructors">Constructors</a></li>
|
||
<li><a class="reference internal" href="#methods">Methods</a></li>
|
||
<li><a class="reference internal" href="#c-api">C-API</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#affected-behaviors">Affected Behaviors</a><ul>
|
||
<li><a class="reference internal" href="#what-time-is-it">What time is it?</a></li>
|
||
<li><a class="reference internal" href="#conversion-from-naive-to-aware">Conversion from naive to aware</a></li>
|
||
<li><a class="reference internal" href="#conversion-from-posix-seconds-from-epoch">Conversion from POSIX seconds from EPOCH</a></li>
|
||
<li><a class="reference internal" href="#conversion-to-posix-seconds-from-epoch">Conversion to POSIX seconds from EPOCH</a></li>
|
||
<li><a class="reference internal" href="#aware-datetime-instances">Aware datetime instances</a></li>
|
||
<li><a class="reference internal" href="#combining-and-splitting-date-and-time">Combining and splitting date and time</a></li>
|
||
<li><a class="reference internal" href="#pickles">Pickles</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#implementations-of-tzinfo-in-the-standard-library">Implementations of tzinfo in the Standard Library</a></li>
|
||
<li><a class="reference internal" href="#guidelines-for-new-tzinfo-implementations">Guidelines for New tzinfo Implementations</a><ul>
|
||
<li><a class="reference internal" href="#ignorance-is-bliss">Ignorance is Bliss</a></li>
|
||
<li><a class="reference internal" href="#in-the-fold">In the Fold</a></li>
|
||
<li><a class="reference internal" href="#mind-the-gap">Mind the Gap</a></li>
|
||
<li><a class="reference internal" href="#summary-of-rules-at-a-transition">Summary of Rules at a Transition</a></li>
|
||
<li><a class="reference internal" href="#the-dst-transitions">The DST Transitions</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#temporal-arithmetic-and-comparison-operators">Temporal Arithmetic and Comparison Operators</a><ul>
|
||
<li><a class="reference internal" href="#aware-datetime-equality-comparison">Aware datetime Equality Comparison</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#backward-and-forward-compatibility">Backward and Forward Compatibility</a></li>
|
||
<li><a class="reference internal" href="#questions-and-answers">Questions and Answers</a><ul>
|
||
<li><a class="reference internal" href="#why-not-call-the-new-flag-isdst">Why not call the new flag “isdst”?</a><ul>
|
||
<li><a class="reference internal" href="#a-non-technical-answer">A non-technical answer</a></li>
|
||
<li><a class="reference internal" href="#a-technical-reason">A technical reason</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#why-fold">Why “fold”?</a></li>
|
||
<li><a class="reference internal" href="#what-is-first">What is “first”?</a></li>
|
||
<li><a class="reference internal" href="#are-two-values-enough">Are two values enough?</a><ul>
|
||
<li><a class="reference internal" href="#backward-compatibility">Backward Compatibility</a></li>
|
||
<li><a class="reference internal" href="#analogy-with-tm-isdst">Analogy with tm_isdst</a></li>
|
||
<li><a class="reference internal" href="#strict-invalid-time-checking">Strict Invalid Time Checking</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#implementation">Implementation</a></li>
|
||
<li><a class="reference internal" href="#copyright">Copyright</a></li>
|
||
<li><a class="reference internal" href="#picture-credit">Picture Credit</a></li>
|
||
</ul>
|
||
</details></section>
|
||
<section id="abstract">
|
||
<h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2>
|
||
<p>This PEP adds a new attribute <code class="docutils literal notranslate"><span class="pre">fold</span></code> to instances of the
|
||
<code class="docutils literal notranslate"><span class="pre">datetime.time</span></code> and <code class="docutils literal notranslate"><span class="pre">datetime.datetime</span></code> classes that can be used
|
||
to differentiate between two moments in time for which local times are
|
||
the same. The allowed values for the <code class="docutils literal notranslate"><span class="pre">fold</span></code> attribute will be 0 and 1
|
||
with 0 corresponding to the earlier and 1 to the later of the two
|
||
possible readings of an ambiguous local time.</p>
|
||
</section>
|
||
<section id="rationale">
|
||
<h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2>
|
||
<p>In most world locations, there have been and will be times when
|
||
local clocks are moved back. <a class="footnote-reference brackets" href="#id2" id="id1">[1]</a> In those times, intervals are
|
||
introduced in which local clocks show the same time twice in the same
|
||
day. In these situations, the information displayed on a local clock
|
||
(or stored in a Python datetime instance) is insufficient to identify
|
||
a particular moment in time. The proposed solution is to add an
|
||
attribute to the <code class="docutils literal notranslate"><span class="pre">datetime</span></code> instances taking values of 0 and 1 that
|
||
will enumerate the two ambiguous times.</p>
|
||
<a class="reference internal image-reference" href="../_images/pep-0495-daylightsavings.png"><img alt="A cartoon of a strong man struggling to stop the hands of a large clock. The caption reads: You can't stop time... but you can turn it back one hour at 2 a.m. Oct. 28 when daylight-saving time ends and standard time begins."" class="align-center" src="../_images/pep-0495-daylightsavings.png" style="width: 30%;" /></a>
|
||
<aside class="footnote-list brackets">
|
||
<aside class="footnote brackets" id="id2" role="doc-footnote">
|
||
<dt class="label" id="id2">[<a href="#id1">1</a>]</dt>
|
||
<dd>People who live in locations observing the Daylight Saving
|
||
Time (DST) move their clocks back (usually one hour) every Fall.<p>It is less common, but occasionally clocks can be moved back for
|
||
other reasons. For example, Ukraine skipped the spring-forward
|
||
transition in March 1990 and instead, moved their clocks back on
|
||
July 1, 1990, switching from Moscow Time to Eastern European Time.
|
||
In that case, standard (winter) time was in effect before and after
|
||
the transition.</p>
|
||
<p>Both DST and standard time changes may result in time shifts other
|
||
than an hour.</p>
|
||
</aside>
|
||
</aside>
|
||
</section>
|
||
<section id="terminology">
|
||
<h2><a class="toc-backref" href="#terminology" role="doc-backlink">Terminology</a></h2>
|
||
<p>When clocks are moved back, we say that a <em>fold</em> <a class="footnote-reference brackets" href="#id4" id="id3">[2]</a> is created in time.
|
||
When the clocks are moved forward, a <em>gap</em> is created. A local time
|
||
that falls in the fold is called <em>ambiguous</em>. A local time that falls
|
||
in the gap is called <em>missing</em>.</p>
|
||
<aside class="footnote-list brackets">
|
||
<aside class="footnote brackets" id="id4" role="doc-footnote">
|
||
<dt class="label" id="id4">[<a href="#id3">2</a>]</dt>
|
||
<dd>The term “fall-backward fold” was invented in 1990s by Paul Eggert
|
||
of UCLA who used it in various Internet discussions related to the C language
|
||
standard that culminated in a <a class="reference external" href="http://www.open-std.org/jtc1/sc22/wg14/docs/rr/dr_136.html">Defect Report #139</a>.</aside>
|
||
</aside>
|
||
</section>
|
||
<section id="proposal">
|
||
<h2><a class="toc-backref" href="#proposal" role="doc-backlink">Proposal</a></h2>
|
||
<section id="the-fold-attribute">
|
||
<h3><a class="toc-backref" href="#the-fold-attribute" role="doc-backlink">The “fold” attribute</a></h3>
|
||
<p>We propose adding an attribute called <code class="docutils literal notranslate"><span class="pre">fold</span></code> to instances of the
|
||
<code class="docutils literal notranslate"><span class="pre">datetime.time</span></code> and <code class="docutils literal notranslate"><span class="pre">datetime.datetime</span></code> classes. This attribute
|
||
should have the value 0 for all instances except those that represent
|
||
the second (chronologically) moment in time in an ambiguous case. For
|
||
those instances, the value will be 1. <a class="footnote-reference brackets" href="#id6" id="id5">[3]</a></p>
|
||
<aside class="footnote-list brackets">
|
||
<aside class="footnote brackets" id="id6" role="doc-footnote">
|
||
<dt class="label" id="id6">[<a href="#id5">3</a>]</dt>
|
||
<dd>An instance that has <code class="docutils literal notranslate"><span class="pre">fold=1</span></code> in a non-ambiguous case is
|
||
said to represent an invalid time (or is invalid for short), but
|
||
users are not prevented from creating invalid instances by passing
|
||
<code class="docutils literal notranslate"><span class="pre">fold=1</span></code> to a constructor or to a <code class="docutils literal notranslate"><span class="pre">replace()</span></code> method. This
|
||
is similar to the current situation with the instances that fall in
|
||
the spring-forward gap. Such instances don’t represent any valid
|
||
time, but neither the constructors nor the <code class="docutils literal notranslate"><span class="pre">replace()</span></code> methods
|
||
check whether the instances that they produce are valid. Moreover,
|
||
this PEP specifies how various functions should behave when given an
|
||
invalid instance.</aside>
|
||
</aside>
|
||
</section>
|
||
<section id="affected-apis">
|
||
<h3><a class="toc-backref" href="#affected-apis" role="doc-backlink">Affected APIs</a></h3>
|
||
<section id="attributes">
|
||
<h4><a class="toc-backref" href="#attributes" role="doc-backlink">Attributes</a></h4>
|
||
<p>Instances of <code class="docutils literal notranslate"><span class="pre">datetime.time</span></code> and <code class="docutils literal notranslate"><span class="pre">datetime.datetime</span></code> classes will
|
||
get a new attribute <code class="docutils literal notranslate"><span class="pre">fold</span></code> with two possible values: 0 and 1.</p>
|
||
</section>
|
||
<section id="constructors">
|
||
<h4><a class="toc-backref" href="#constructors" role="doc-backlink">Constructors</a></h4>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">__new__</span></code> methods of the <code class="docutils literal notranslate"><span class="pre">datetime.time</span></code> and
|
||
<code class="docutils literal notranslate"><span class="pre">datetime.datetime</span></code> classes will get a new keyword-only argument
|
||
called <code class="docutils literal notranslate"><span class="pre">fold</span></code> with the default value 0. The value of the
|
||
<code class="docutils literal notranslate"><span class="pre">fold</span></code> argument will be used to initialize the value of the
|
||
<code class="docutils literal notranslate"><span class="pre">fold</span></code> attribute in the returned instance.</p>
|
||
</section>
|
||
<section id="methods">
|
||
<h4><a class="toc-backref" href="#methods" role="doc-backlink">Methods</a></h4>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">replace()</span></code> methods of the <code class="docutils literal notranslate"><span class="pre">datetime.time</span></code> and
|
||
<code class="docutils literal notranslate"><span class="pre">datetime.datetime</span></code> classes will get a new keyword-only argument
|
||
called <code class="docutils literal notranslate"><span class="pre">fold</span></code>. It will behave similarly to the other <code class="docutils literal notranslate"><span class="pre">replace()</span></code>
|
||
arguments: if the <code class="docutils literal notranslate"><span class="pre">fold</span></code> argument is specified and given a value 0
|
||
or 1, the new instance returned by <code class="docutils literal notranslate"><span class="pre">replace()</span></code> will have its
|
||
<code class="docutils literal notranslate"><span class="pre">fold</span></code> attribute set to that value. In CPython, any non-integer
|
||
value of <code class="docutils literal notranslate"><span class="pre">fold</span></code> will raise a <code class="docutils literal notranslate"><span class="pre">TypeError</span></code>, but other
|
||
implementations may allow the value <code class="docutils literal notranslate"><span class="pre">None</span></code> to behave the same as
|
||
when <code class="docutils literal notranslate"><span class="pre">fold</span></code> is not given. <a class="footnote-reference brackets" href="#id8" id="id7">[4]</a> (This is
|
||
a nod to the existing difference in treatment of <code class="docutils literal notranslate"><span class="pre">None</span></code> arguments
|
||
in other positions of this method across Python implementations;
|
||
it is not intended to leave the door open for future alternative
|
||
interpretation of <code class="docutils literal notranslate"><span class="pre">fold=None</span></code>.) If the <code class="docutils literal notranslate"><span class="pre">fold</span></code> argument is not
|
||
specified, the original value of the <code class="docutils literal notranslate"><span class="pre">fold</span></code> attribute is copied to
|
||
the result.</p>
|
||
<aside class="footnote-list brackets">
|
||
<aside class="footnote brackets" id="id8" role="doc-footnote">
|
||
<dt class="label" id="id8">[<a href="#id7">4</a>]</dt>
|
||
<dd>PyPy and pure Python implementation distributed with CPython
|
||
already allow <code class="docutils literal notranslate"><span class="pre">None</span></code> to mean “no change to existing
|
||
attribute” for all other attributes in <code class="docutils literal notranslate"><span class="pre">replace()</span></code>.</aside>
|
||
</aside>
|
||
</section>
|
||
<section id="c-api">
|
||
<h4><a class="toc-backref" href="#c-api" role="doc-backlink">C-API</a></h4>
|
||
<p>Access macros will be defined to extract the value of <code class="docutils literal notranslate"><span class="pre">fold</span></code> from
|
||
<code class="docutils literal notranslate"><span class="pre">PyDateTime_DateTime</span></code> and <code class="docutils literal notranslate"><span class="pre">PyDateTime_Time</span></code> objects.</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nb">int</span> <span class="n">PyDateTime_DATE_GET_FOLD</span><span class="p">(</span><span class="n">PyDateTime_DateTime</span> <span class="o">*</span><span class="n">o</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Return the value of <code class="docutils literal notranslate"><span class="pre">fold</span></code> as a C <code class="docutils literal notranslate"><span class="pre">int</span></code>.</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nb">int</span> <span class="n">PyDateTime_TIME_GET_FOLD</span><span class="p">(</span><span class="n">PyDateTime_Time</span> <span class="o">*</span><span class="n">o</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Return the value of <code class="docutils literal notranslate"><span class="pre">fold</span></code> as a C <code class="docutils literal notranslate"><span class="pre">int</span></code>.</p>
|
||
<p>New constructors will be defined that will take an additional
|
||
argument to specify the value of <code class="docutils literal notranslate"><span class="pre">fold</span></code> in the created
|
||
instance:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">PyObject</span><span class="o">*</span> <span class="n">PyDateTime_FromDateAndTimeAndFold</span><span class="p">(</span>
|
||
<span class="nb">int</span> <span class="n">year</span><span class="p">,</span> <span class="nb">int</span> <span class="n">month</span><span class="p">,</span> <span class="nb">int</span> <span class="n">day</span><span class="p">,</span> <span class="nb">int</span> <span class="n">hour</span><span class="p">,</span> <span class="nb">int</span> <span class="n">minute</span><span class="p">,</span>
|
||
<span class="nb">int</span> <span class="n">second</span><span class="p">,</span> <span class="nb">int</span> <span class="n">usecond</span><span class="p">,</span> <span class="nb">int</span> <span class="n">fold</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Return a <code class="docutils literal notranslate"><span class="pre">datetime.datetime</span></code> object with the specified year, month,
|
||
day, hour, minute, second, microsecond and fold.</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">PyObject</span><span class="o">*</span> <span class="n">PyTime_FromTimeAndFold</span><span class="p">(</span>
|
||
<span class="nb">int</span> <span class="n">hour</span><span class="p">,</span> <span class="nb">int</span> <span class="n">minute</span><span class="p">,</span> <span class="nb">int</span> <span class="n">second</span><span class="p">,</span> <span class="nb">int</span> <span class="n">usecond</span><span class="p">,</span> <span class="nb">int</span> <span class="n">fold</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Return a <code class="docutils literal notranslate"><span class="pre">datetime.time</span></code> object with the specified hour, minute,
|
||
second, microsecond and fold.</p>
|
||
</section>
|
||
</section>
|
||
<section id="affected-behaviors">
|
||
<h3><a class="toc-backref" href="#affected-behaviors" role="doc-backlink">Affected Behaviors</a></h3>
|
||
<section id="what-time-is-it">
|
||
<h4><a class="toc-backref" href="#what-time-is-it" role="doc-backlink">What time is it?</a></h4>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">datetime.now()</span></code> method called without arguments will set
|
||
<code class="docutils literal notranslate"><span class="pre">fold=1</span></code> when returning the second of the two ambiguous times in a
|
||
system local time fold. When called with a <code class="docutils literal notranslate"><span class="pre">tzinfo</span></code> argument, the
|
||
value of the <code class="docutils literal notranslate"><span class="pre">fold</span></code> will be determined by the <code class="docutils literal notranslate"><span class="pre">tzinfo.fromutc()</span></code>
|
||
implementation. When an instance of the <code class="docutils literal notranslate"><span class="pre">datetime.timezone</span></code> class
|
||
(the stdlib’s fixed-offset <code class="docutils literal notranslate"><span class="pre">tzinfo</span></code> subclass,
|
||
<em>e.g.</em> <code class="docutils literal notranslate"><span class="pre">datetime.timezone.utc</span></code>) is passed as <code class="docutils literal notranslate"><span class="pre">tzinfo</span></code>, the
|
||
returned datetime instance will always have <code class="docutils literal notranslate"><span class="pre">fold=0</span></code>.
|
||
The <code class="docutils literal notranslate"><span class="pre">datetime.utcnow()</span></code> method is unaffected.</p>
|
||
</section>
|
||
<section id="conversion-from-naive-to-aware">
|
||
<h4><a class="toc-backref" href="#conversion-from-naive-to-aware" role="doc-backlink">Conversion from naive to aware</a></h4>
|
||
<p>A new feature is proposed to facilitate conversion from naive datetime
|
||
instances to aware.</p>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">astimezone()</span></code> method will now work for naive <code class="docutils literal notranslate"><span class="pre">self</span></code>. The
|
||
system local timezone will be assumed in this case and the <code class="docutils literal notranslate"><span class="pre">fold</span></code>
|
||
flag will be used to determine which local timezone is in effect
|
||
in the ambiguous case.</p>
|
||
<p>For example, on a system set to US/Eastern timezone:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">dt</span> <span class="o">=</span> <span class="n">datetime</span><span class="p">(</span><span class="mi">2014</span><span class="p">,</span> <span class="mi">11</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">30</span><span class="p">)</span>
|
||
<span class="gp">>>> </span><span class="n">dt</span><span class="o">.</span><span class="n">astimezone</span><span class="p">()</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s1">'%D %T %Z%z'</span><span class="p">)</span>
|
||
<span class="go">'11/02/14 01:30:00 EDT-0400'</span>
|
||
<span class="gp">>>> </span><span class="n">dt</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="n">fold</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">astimezone</span><span class="p">()</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s1">'%D %T %Z%z'</span><span class="p">)</span>
|
||
<span class="go">'11/02/14 01:30:00 EST-0500'</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>An implication is that <code class="docutils literal notranslate"><span class="pre">datetime.now(tz)</span></code> is fully equivalent to
|
||
<code class="docutils literal notranslate"><span class="pre">datetime.now().astimezone(tz)</span></code> (assuming <code class="docutils literal notranslate"><span class="pre">tz</span></code> is an instance of a
|
||
post-PEP <code class="docutils literal notranslate"><span class="pre">tzinfo</span></code> implementation, i.e. one that correctly handles
|
||
and sets <code class="docutils literal notranslate"><span class="pre">fold</span></code>).</p>
|
||
</section>
|
||
<section id="conversion-from-posix-seconds-from-epoch">
|
||
<h4><a class="toc-backref" href="#conversion-from-posix-seconds-from-epoch" role="doc-backlink">Conversion from POSIX seconds from EPOCH</a></h4>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">fromtimestamp()</span></code> static method of <code class="docutils literal notranslate"><span class="pre">datetime.datetime</span></code> will
|
||
set the <code class="docutils literal notranslate"><span class="pre">fold</span></code> attribute appropriately in the returned object.</p>
|
||
<p>For example, on a system set to US/Eastern timezone:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">datetime</span><span class="o">.</span><span class="n">fromtimestamp</span><span class="p">(</span><span class="mi">1414906200</span><span class="p">)</span>
|
||
<span class="go">datetime.datetime(2014, 11, 2, 1, 30)</span>
|
||
<span class="gp">>>> </span><span class="n">datetime</span><span class="o">.</span><span class="n">fromtimestamp</span><span class="p">(</span><span class="mi">1414906200</span> <span class="o">+</span> <span class="mi">3600</span><span class="p">)</span>
|
||
<span class="go">datetime.datetime(2014, 11, 2, 1, 30, fold=1)</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="conversion-to-posix-seconds-from-epoch">
|
||
<h4><a class="toc-backref" href="#conversion-to-posix-seconds-from-epoch" role="doc-backlink">Conversion to POSIX seconds from EPOCH</a></h4>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">timestamp()</span></code> method of <code class="docutils literal notranslate"><span class="pre">datetime.datetime</span></code> will return different
|
||
values for <code class="docutils literal notranslate"><span class="pre">datetime.datetime</span></code> instances that differ only by the value
|
||
of their <code class="docutils literal notranslate"><span class="pre">fold</span></code> attribute if and only if these instances represent an
|
||
ambiguous or a missing time.</p>
|
||
<p>When a <code class="docutils literal notranslate"><span class="pre">datetime.datetime</span></code> instance <code class="docutils literal notranslate"><span class="pre">dt</span></code> represents an ambiguous
|
||
time, there are two values <code class="docutils literal notranslate"><span class="pre">s0</span></code> and <code class="docutils literal notranslate"><span class="pre">s1</span></code> such that:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">datetime</span><span class="o">.</span><span class="n">fromtimestamp</span><span class="p">(</span><span class="n">s0</span><span class="p">)</span> <span class="o">==</span> <span class="n">datetime</span><span class="o">.</span><span class="n">fromtimestamp</span><span class="p">(</span><span class="n">s1</span><span class="p">)</span> <span class="o">==</span> <span class="n">dt</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>(This is because <code class="docutils literal notranslate"><span class="pre">==</span></code> disregards the value of fold – see below.)</p>
|
||
<p>In this case, <code class="docutils literal notranslate"><span class="pre">dt.timestamp()</span></code> will return the smaller of <code class="docutils literal notranslate"><span class="pre">s0</span></code>
|
||
and <code class="docutils literal notranslate"><span class="pre">s1</span></code> values if <code class="docutils literal notranslate"><span class="pre">dt.fold</span> <span class="pre">==</span> <span class="pre">0</span></code> and the larger otherwise.</p>
|
||
<p>For example, on a system set to US/Eastern timezone:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">datetime</span><span class="p">(</span><span class="mi">2014</span><span class="p">,</span> <span class="mi">11</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">30</span><span class="p">,</span> <span class="n">fold</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span><span class="o">.</span><span class="n">timestamp</span><span class="p">()</span>
|
||
<span class="go">1414906200.0</span>
|
||
<span class="gp">>>> </span><span class="n">datetime</span><span class="p">(</span><span class="mi">2014</span><span class="p">,</span> <span class="mi">11</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">30</span><span class="p">,</span> <span class="n">fold</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">timestamp</span><span class="p">()</span>
|
||
<span class="go">1414909800.0</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>When a <code class="docutils literal notranslate"><span class="pre">datetime.datetime</span></code> instance <code class="docutils literal notranslate"><span class="pre">dt</span></code> represents a missing
|
||
time, there is no value <code class="docutils literal notranslate"><span class="pre">s</span></code> for which:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">datetime</span><span class="o">.</span><span class="n">fromtimestamp</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">==</span> <span class="n">dt</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>but we can form two “nice to know” values of <code class="docutils literal notranslate"><span class="pre">s</span></code> that differ
|
||
by the size of the gap in seconds. One is the value of <code class="docutils literal notranslate"><span class="pre">s</span></code>
|
||
that would correspond to <code class="docutils literal notranslate"><span class="pre">dt</span></code> in a timezone where the UTC offset
|
||
is always the same as the offset right before the gap and the
|
||
other is the similar value but in a timezone the UTC offset
|
||
is always the same as the offset right after the gap.</p>
|
||
<p>The value returned by <code class="docutils literal notranslate"><span class="pre">dt.timestamp()</span></code> given a missing
|
||
<code class="docutils literal notranslate"><span class="pre">dt</span></code> will be the greater of the two “nice to know” values
|
||
if <code class="docutils literal notranslate"><span class="pre">dt.fold</span> <span class="pre">==</span> <span class="pre">0</span></code> and the smaller otherwise.
|
||
(This is not a typo – it’s intentionally backwards from the rule for
|
||
ambiguous times.)</p>
|
||
<p>For example, on a system set to US/Eastern timezone:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">datetime</span><span class="p">(</span><span class="mi">2015</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">30</span><span class="p">,</span> <span class="n">fold</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span><span class="o">.</span><span class="n">timestamp</span><span class="p">()</span>
|
||
<span class="go">1425799800.0</span>
|
||
<span class="gp">>>> </span><span class="n">datetime</span><span class="p">(</span><span class="mi">2015</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">30</span><span class="p">,</span> <span class="n">fold</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">timestamp</span><span class="p">()</span>
|
||
<span class="go">1425796200.0</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="aware-datetime-instances">
|
||
<h4><a class="toc-backref" href="#aware-datetime-instances" role="doc-backlink">Aware datetime instances</a></h4>
|
||
<p>Users of pre-PEP implementations of <code class="docutils literal notranslate"><span class="pre">tzinfo</span></code> will not see any
|
||
changes in the behavior of their aware datetime instances. Two such
|
||
instances that differ only by the value of the <code class="docutils literal notranslate"><span class="pre">fold</span></code> attribute will
|
||
not be distinguishable by any means other than an explicit access to
|
||
the <code class="docutils literal notranslate"><span class="pre">fold</span></code> value. (This is because these pre-PEP implementations
|
||
are not using the <code class="docutils literal notranslate"><span class="pre">fold</span></code> attribute.)</p>
|
||
<p>On the other hand, if an object’s <code class="docutils literal notranslate"><span class="pre">tzinfo</span></code> is set to a fold-aware
|
||
implementation, then in a fold or gap the value of <code class="docutils literal notranslate"><span class="pre">fold</span></code> will
|
||
affect the result of several methods:
|
||
<code class="docutils literal notranslate"><span class="pre">utcoffset()</span></code>, <code class="docutils literal notranslate"><span class="pre">dst()</span></code>, <code class="docutils literal notranslate"><span class="pre">tzname()</span></code>, <code class="docutils literal notranslate"><span class="pre">astimezone()</span></code>,
|
||
<code class="docutils literal notranslate"><span class="pre">strftime()</span></code> (if the “%Z” or “%z” directive is used in the format
|
||
specification), <code class="docutils literal notranslate"><span class="pre">isoformat()</span></code>, and <code class="docutils literal notranslate"><span class="pre">timetuple()</span></code>.</p>
|
||
</section>
|
||
<section id="combining-and-splitting-date-and-time">
|
||
<h4><a class="toc-backref" href="#combining-and-splitting-date-and-time" role="doc-backlink">Combining and splitting date and time</a></h4>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">datetime.datetime.combine()</span></code> method will copy the value of the
|
||
<code class="docutils literal notranslate"><span class="pre">fold</span></code> attribute to the resulting <code class="docutils literal notranslate"><span class="pre">datetime.datetime</span></code> instance.</p>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">datetime.datetime.time()</span></code> method will copy the value of the
|
||
<code class="docutils literal notranslate"><span class="pre">fold</span></code> attribute to the resulting <code class="docutils literal notranslate"><span class="pre">datetime.time</span></code> instance.</p>
|
||
</section>
|
||
<section id="pickles">
|
||
<h4><a class="toc-backref" href="#pickles" role="doc-backlink">Pickles</a></h4>
|
||
<p>The value of the fold attribute will only be saved in pickles created
|
||
with protocol version 4 (introduced in Python 3.4) or greater.</p>
|
||
<p>Pickle sizes for the <code class="docutils literal notranslate"><span class="pre">datetime.datetime</span></code> and <code class="docutils literal notranslate"><span class="pre">datetime.time</span></code>
|
||
objects will not change. The <code class="docutils literal notranslate"><span class="pre">fold</span></code> value will be encoded in the
|
||
first bit of the 3rd byte of the <code class="docutils literal notranslate"><span class="pre">datetime.datetime</span></code>
|
||
pickle payload; and in the first bit of the 1st byte of the
|
||
<code class="docutils literal notranslate"><span class="pre">datetime.time</span></code> payload. In the <a class="reference external" href="https://hg.python.org/cpython/file/v3.5.0/Include/datetime.h#l10">current implementation</a>
|
||
these bytes are used to store the month (1-12) and hour (0-23) values
|
||
and the first bit is always 0. We picked these bytes because they are
|
||
the only bytes that are checked by the current unpickle code. Thus
|
||
loading post-PEP <code class="docutils literal notranslate"><span class="pre">fold=1</span></code> pickles in a pre-PEP Python will result in
|
||
an exception rather than an instance with out of range components.</p>
|
||
</section>
|
||
</section>
|
||
</section>
|
||
<section id="implementations-of-tzinfo-in-the-standard-library">
|
||
<h2><a class="toc-backref" href="#implementations-of-tzinfo-in-the-standard-library" role="doc-backlink">Implementations of tzinfo in the Standard Library</a></h2>
|
||
<p>No new implementations of <code class="docutils literal notranslate"><span class="pre">datetime.tzinfo</span></code> abstract class are
|
||
proposed in this PEP. The existing (fixed offset) timezones do
|
||
not introduce ambiguous local times and their <code class="docutils literal notranslate"><span class="pre">utcoffset()</span></code>
|
||
implementation will return the same constant value as they do now
|
||
regardless of the value of <code class="docutils literal notranslate"><span class="pre">fold</span></code>.</p>
|
||
<p>The basic implementation of <code class="docutils literal notranslate"><span class="pre">fromutc()</span></code> in the abstract
|
||
<code class="docutils literal notranslate"><span class="pre">datetime.tzinfo</span></code> class will not change. It is currently not used
|
||
anywhere in the stdlib because the only included <code class="docutils literal notranslate"><span class="pre">tzinfo</span></code>
|
||
implementation (the <code class="docutils literal notranslate"><span class="pre">datetime.timezone</span></code> class implementing fixed
|
||
offset timezones) overrides <code class="docutils literal notranslate"><span class="pre">fromutc()</span></code>. Keeping the default
|
||
implementation unchanged has the benefit that pre-PEP 3rd party
|
||
implementations that inherit the default <code class="docutils literal notranslate"><span class="pre">fromutc()</span></code> are not
|
||
accidentally affected.</p>
|
||
</section>
|
||
<section id="guidelines-for-new-tzinfo-implementations">
|
||
<h2><a class="toc-backref" href="#guidelines-for-new-tzinfo-implementations" role="doc-backlink">Guidelines for New tzinfo Implementations</a></h2>
|
||
<p>Implementors of concrete <code class="docutils literal notranslate"><span class="pre">datetime.tzinfo</span></code> subclasses who want to
|
||
support variable UTC offsets (due to DST and other causes) should follow
|
||
these guidelines.</p>
|
||
<section id="ignorance-is-bliss">
|
||
<h3><a class="toc-backref" href="#ignorance-is-bliss" role="doc-backlink">Ignorance is Bliss</a></h3>
|
||
<p>New implementations of <code class="docutils literal notranslate"><span class="pre">utcoffset()</span></code>, <code class="docutils literal notranslate"><span class="pre">tzname()</span></code> and <code class="docutils literal notranslate"><span class="pre">dst()</span></code>
|
||
methods should ignore the value of <code class="docutils literal notranslate"><span class="pre">fold</span></code> unless they are called on
|
||
the ambiguous or missing times.</p>
|
||
</section>
|
||
<section id="in-the-fold">
|
||
<h3><a class="toc-backref" href="#in-the-fold" role="doc-backlink">In the Fold</a></h3>
|
||
<p>New subclasses should override the base-class <code class="docutils literal notranslate"><span class="pre">fromutc()</span></code> method and
|
||
implement it so that in all cases where two different UTC times <code class="docutils literal notranslate"><span class="pre">u0</span></code> and
|
||
<code class="docutils literal notranslate"><span class="pre">u1</span></code> (<code class="docutils literal notranslate"><span class="pre">u0</span></code> <<code class="docutils literal notranslate"><span class="pre">u1</span></code>) correspond to the same local time <code class="docutils literal notranslate"><span class="pre">t</span></code>,
|
||
<code class="docutils literal notranslate"><span class="pre">fromutc(u0)</span></code> will return an instance with <code class="docutils literal notranslate"><span class="pre">fold=0</span></code> and
|
||
<code class="docutils literal notranslate"><span class="pre">fromutc(u1)</span></code> will return an instance with <code class="docutils literal notranslate"><span class="pre">fold=1</span></code>. In all
|
||
other cases the returned instance should have <code class="docutils literal notranslate"><span class="pre">fold=0</span></code>.</p>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">utcoffset()</span></code>, <code class="docutils literal notranslate"><span class="pre">tzname()</span></code> and <code class="docutils literal notranslate"><span class="pre">dst()</span></code> methods should use the
|
||
value of the fold attribute to determine whether an otherwise
|
||
ambiguous time <code class="docutils literal notranslate"><span class="pre">t</span></code> corresponds to the time before or after the
|
||
transition. By definition, <code class="docutils literal notranslate"><span class="pre">utcoffset()</span></code> is greater before and
|
||
smaller after any transition that creates a fold. The values returned
|
||
by <code class="docutils literal notranslate"><span class="pre">tzname()</span></code> and <code class="docutils literal notranslate"><span class="pre">dst()</span></code> may or may not depend on the value of
|
||
the <code class="docutils literal notranslate"><span class="pre">fold</span></code> attribute depending on the kind of the transition.</p>
|
||
<a class="invert-in-dark-mode reference internal image-reference" href="../_images/pep-0495-fold.svg"><img alt="Diagram of relationship between UTC and local time around a fall-back transition – see full description on page." class="invert-in-dark-mode align-center" src="../_images/pep-0495-fold.svg" width="60%" /></a>
|
||
<p>The sketch above illustrates the relationship between the UTC and
|
||
local time around a fall-back transition. The zig-zag line is a graph
|
||
of the function implemented by <code class="docutils literal notranslate"><span class="pre">fromutc()</span></code>. Two intervals on the
|
||
UTC axis adjacent to the transition point and having the size of the
|
||
time shift at the transition are mapped to the same interval on the
|
||
local axis. New implementations of <code class="docutils literal notranslate"><span class="pre">fromutc()</span></code> method should set
|
||
the fold attribute to 1 when <code class="docutils literal notranslate"><span class="pre">self</span></code> is in the region marked in
|
||
yellow on the UTC axis. (All intervals should be treated as closed on
|
||
the left and open on the right.)</p>
|
||
</section>
|
||
<section id="mind-the-gap">
|
||
<h3><a class="toc-backref" href="#mind-the-gap" role="doc-backlink">Mind the Gap</a></h3>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">fromutc()</span></code> method should never produce a time in the gap.</p>
|
||
<p>If the <code class="docutils literal notranslate"><span class="pre">utcoffset()</span></code>, <code class="docutils literal notranslate"><span class="pre">tzname()</span></code> or <code class="docutils literal notranslate"><span class="pre">dst()</span></code> method is called on a
|
||
local time that falls in a gap, the rules in effect before the
|
||
transition should be used if <code class="docutils literal notranslate"><span class="pre">fold=0</span></code>. Otherwise, the rules in
|
||
effect after the transition should be used.</p>
|
||
<a class="invert-in-dark-mode reference internal image-reference" href="../_images/pep-0495-gap.svg"><img alt="Diagram of relationship between UTC and local time around a spring-forward transition – see full description on page." class="invert-in-dark-mode align-center" src="../_images/pep-0495-gap.svg" width="60%" /></a>
|
||
<p>The sketch above illustrates the relationship between the UTC and
|
||
local time around a spring-forward transition. At the transition, the
|
||
local clock is advanced skipping the times in the gap. For the
|
||
purposes of determining the values of <code class="docutils literal notranslate"><span class="pre">utcoffset()</span></code>, <code class="docutils literal notranslate"><span class="pre">tzname()</span></code>
|
||
and <code class="docutils literal notranslate"><span class="pre">dst()</span></code>, the line before the transition is extended forward to
|
||
find the UTC time corresponding to the time in the gap with <code class="docutils literal notranslate"><span class="pre">fold=0</span></code>
|
||
and for instances with <code class="docutils literal notranslate"><span class="pre">fold=1</span></code>, the line after the transition is
|
||
extended back.</p>
|
||
</section>
|
||
<section id="summary-of-rules-at-a-transition">
|
||
<h3><a class="toc-backref" href="#summary-of-rules-at-a-transition" role="doc-backlink">Summary of Rules at a Transition</a></h3>
|
||
<p>On ambiguous/missing times <code class="docutils literal notranslate"><span class="pre">utcoffset()</span></code> should return values
|
||
according to the following table:</p>
|
||
<table class="docutils align-default">
|
||
<thead>
|
||
<tr class="row-odd"><th class="head"></th>
|
||
<th class="head">fold=0</th>
|
||
<th class="head">fold=1</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="row-even"><td>Fold</td>
|
||
<td>oldoff</td>
|
||
<td>newoff = oldoff - delta</td>
|
||
</tr>
|
||
<tr class="row-odd"><td>Gap</td>
|
||
<td>oldoff</td>
|
||
<td>newoff = oldoff + delta</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>where <code class="docutils literal notranslate"><span class="pre">oldoff</span></code> (<code class="docutils literal notranslate"><span class="pre">newoff</span></code>) is the UTC offset before (after) the
|
||
transition and <code class="docutils literal notranslate"><span class="pre">delta</span></code> is the absolute size of the fold or the gap.</p>
|
||
<p>Note that the interpretation of the fold attribute is consistent in
|
||
the fold and gap cases. In both cases, <code class="docutils literal notranslate"><span class="pre">fold=0</span></code> (<code class="docutils literal notranslate"><span class="pre">fold=1</span></code>) means
|
||
use <code class="docutils literal notranslate"><span class="pre">fromutc()</span></code> line before (after) the transition to find the UTC
|
||
time. Only in the “Fold” case, the UTC times <code class="docutils literal notranslate"><span class="pre">u0</span></code> and <code class="docutils literal notranslate"><span class="pre">u1</span></code> are
|
||
“real” solutions for the equation <code class="docutils literal notranslate"><span class="pre">fromutc(u)</span> <span class="pre">==</span> <span class="pre">t</span></code>, while in the
|
||
“Gap” case they are “imaginary” solutions.</p>
|
||
</section>
|
||
<section id="the-dst-transitions">
|
||
<h3><a class="toc-backref" href="#the-dst-transitions" role="doc-backlink">The DST Transitions</a></h3>
|
||
<p>On a missing time introduced at the start of DST, the values returned
|
||
by <code class="docutils literal notranslate"><span class="pre">utcoffset()</span></code> and <code class="docutils literal notranslate"><span class="pre">dst()</span></code> methods should be as follows</p>
|
||
<table class="docutils align-default">
|
||
<thead>
|
||
<tr class="row-odd"><th class="head"></th>
|
||
<th class="head">fold=0</th>
|
||
<th class="head">fold=1</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="row-even"><td>utcoffset()</td>
|
||
<td>stdoff</td>
|
||
<td>stdoff + dstoff</td>
|
||
</tr>
|
||
<tr class="row-odd"><td>dst()</td>
|
||
<td>zero</td>
|
||
<td>dstoff</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>On an ambiguous time introduced at the end of DST, the values returned
|
||
by <code class="docutils literal notranslate"><span class="pre">utcoffset()</span></code> and <code class="docutils literal notranslate"><span class="pre">dst()</span></code> methods should be as follows</p>
|
||
<table class="docutils align-default">
|
||
<thead>
|
||
<tr class="row-odd"><th class="head"></th>
|
||
<th class="head">fold=0</th>
|
||
<th class="head">fold=1</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="row-even"><td>utcoffset()</td>
|
||
<td>stdoff + dstoff</td>
|
||
<td>stdoff</td>
|
||
</tr>
|
||
<tr class="row-odd"><td>dst()</td>
|
||
<td>dstoff</td>
|
||
<td>zero</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>where <code class="docutils literal notranslate"><span class="pre">stdoff</span></code> is the standard (non-DST) offset, <code class="docutils literal notranslate"><span class="pre">dstoff</span></code> is the
|
||
DST correction (typically <code class="docutils literal notranslate"><span class="pre">dstoff</span> <span class="pre">=</span> <span class="pre">timedelta(hours=1)</span></code>) and <code class="docutils literal notranslate"><span class="pre">zero</span>
|
||
<span class="pre">=</span> <span class="pre">timedelta(0)</span></code>.</p>
|
||
</section>
|
||
</section>
|
||
<section id="temporal-arithmetic-and-comparison-operators">
|
||
<h2><a class="toc-backref" href="#temporal-arithmetic-and-comparison-operators" role="doc-backlink">Temporal Arithmetic and Comparison Operators</a></h2>
|
||
<blockquote class="epigraph">
|
||
<div><div class="line-block">
|
||
<div class="line">In <em>mathematicks</em> he was greater</div>
|
||
<div class="line">Than Tycho Brahe, or Erra Pater:</div>
|
||
<div class="line">For he, by geometric scale,</div>
|
||
<div class="line">Could take the size of pots of ale;</div>
|
||
<div class="line">Resolve, by sines and tangents straight,</div>
|
||
<div class="line">If bread or butter wanted weight,</div>
|
||
<div class="line">And wisely tell what hour o’ th’ day</div>
|
||
<div class="line">The clock does strike by algebra.</div>
|
||
</div>
|
||
<blockquote>
|
||
<div>– “Hudibras” by Samuel Butler</div></blockquote>
|
||
</div></blockquote>
|
||
<p>The value of the <code class="docutils literal notranslate"><span class="pre">fold</span></code> attribute will be ignored in all operations
|
||
with naive datetime instances. As a consequence, naive
|
||
<code class="docutils literal notranslate"><span class="pre">datetime.datetime</span></code> or <code class="docutils literal notranslate"><span class="pre">datetime.time</span></code> instances that differ only
|
||
by the value of <code class="docutils literal notranslate"><span class="pre">fold</span></code> will compare as equal. Applications that
|
||
need to differentiate between such instances should check the value of
|
||
<code class="docutils literal notranslate"><span class="pre">fold</span></code> explicitly or convert those instances to a timezone that does
|
||
not have ambiguous times (such as UTC).</p>
|
||
<p>The value of <code class="docutils literal notranslate"><span class="pre">fold</span></code> will also be ignored whenever a timedelta is
|
||
added to or subtracted from a datetime instance which may be either
|
||
aware or naive. The result of addition (subtraction) of a timedelta
|
||
to (from) a datetime will always have <code class="docutils literal notranslate"><span class="pre">fold</span></code> set to 0 even if the
|
||
original datetime instance had <code class="docutils literal notranslate"><span class="pre">fold=1</span></code>.</p>
|
||
<p>No changes are proposed to the way the difference <code class="docutils literal notranslate"><span class="pre">t</span> <span class="pre">-</span> <span class="pre">s</span></code> is
|
||
computed for datetime instances <code class="docutils literal notranslate"><span class="pre">t</span></code> and <code class="docutils literal notranslate"><span class="pre">s</span></code>. If both instances
|
||
are naive or <code class="docutils literal notranslate"><span class="pre">t.tzinfo</span></code> is the same instance as <code class="docutils literal notranslate"><span class="pre">s.tzinfo</span></code>
|
||
(<code class="docutils literal notranslate"><span class="pre">t.tzinfo</span> <span class="pre">is</span> <span class="pre">s.tzinfo</span></code> evaluates to <code class="docutils literal notranslate"><span class="pre">True</span></code>) then <code class="docutils literal notranslate"><span class="pre">t</span> <span class="pre">-</span> <span class="pre">s</span></code> is a
|
||
timedelta <code class="docutils literal notranslate"><span class="pre">d</span></code> such that <code class="docutils literal notranslate"><span class="pre">s</span> <span class="pre">+</span> <span class="pre">d</span> <span class="pre">==</span> <span class="pre">t</span></code>. As explained in the
|
||
previous paragraph, timedelta addition ignores both <code class="docutils literal notranslate"><span class="pre">fold</span></code> and
|
||
<code class="docutils literal notranslate"><span class="pre">tzinfo</span></code> attributes and so does intra-zone or naive datetime
|
||
subtraction.</p>
|
||
<p>Naive and intra-zone comparisons will ignore the value of <code class="docutils literal notranslate"><span class="pre">fold</span></code> and
|
||
return the same results as they do now. (This is the only way to
|
||
preserve backward compatibility. If you need an aware intra-zone
|
||
comparison that uses the fold, convert both sides to UTC first.)</p>
|
||
<p>The inter-zone subtraction will be defined as it is now: <code class="docutils literal notranslate"><span class="pre">t</span> <span class="pre">-</span> <span class="pre">s</span></code> is
|
||
computed as <code class="docutils literal notranslate"><span class="pre">(t</span> <span class="pre">-</span> <span class="pre">t.utcoffset())</span> <span class="pre">-</span> <span class="pre">(s</span> <span class="pre">-</span>
|
||
<span class="pre">s.utcoffset()).replace(tzinfo=t.tzinfo)</span></code>, but the result will
|
||
depend on the values of <code class="docutils literal notranslate"><span class="pre">t.fold</span></code> and <code class="docutils literal notranslate"><span class="pre">s.fold</span></code> when either
|
||
<code class="docutils literal notranslate"><span class="pre">t.tzinfo</span></code> or <code class="docutils literal notranslate"><span class="pre">s.tzinfo</span></code> is post-PEP. <a class="footnote-reference brackets" href="#id10" id="id9">[5]</a></p>
|
||
<aside class="footnote-list brackets">
|
||
<aside class="footnote brackets" id="id10" role="doc-footnote">
|
||
<dt class="label" id="id10">[<a href="#id9">5</a>]</dt>
|
||
<dd>Note that the new rules may result in a paradoxical situation
|
||
when <code class="docutils literal notranslate"><span class="pre">s</span> <span class="pre">==</span> <span class="pre">t</span></code> but <code class="docutils literal notranslate"><span class="pre">s</span> <span class="pre">-</span> <span class="pre">u</span> <span class="pre">!=</span> <span class="pre">t</span> <span class="pre">-</span> <span class="pre">u</span></code>. Such paradoxes are
|
||
not really new and are inherent in the overloading of the minus
|
||
operator differently for intra- and inter-zone operations. For
|
||
example, one can easily construct datetime instances <code class="docutils literal notranslate"><span class="pre">t</span></code> and <code class="docutils literal notranslate"><span class="pre">s</span></code>
|
||
with some variable offset <code class="docutils literal notranslate"><span class="pre">tzinfo</span></code> and a datetime <code class="docutils literal notranslate"><span class="pre">u</span></code> with
|
||
<code class="docutils literal notranslate"><span class="pre">tzinfo=timezone.utc</span></code> such that <code class="docutils literal notranslate"><span class="pre">(t</span> <span class="pre">-</span> <span class="pre">u)</span> <span class="pre">-</span> <span class="pre">(s</span> <span class="pre">-</span> <span class="pre">u)</span> <span class="pre">!=</span> <span class="pre">t</span> <span class="pre">-</span> <span class="pre">s</span></code>.
|
||
The explanation for this paradox is that the minuses inside the
|
||
parentheses and the two other minuses are really three different
|
||
operations: inter-zone datetime subtraction, timedelta subtraction,
|
||
and intra-zone datetime subtraction, which each have the mathematical
|
||
properties of subtraction separately, but not when combined in a
|
||
single expression.</aside>
|
||
</aside>
|
||
<section id="aware-datetime-equality-comparison">
|
||
<h3><a class="toc-backref" href="#aware-datetime-equality-comparison" role="doc-backlink">Aware datetime Equality Comparison</a></h3>
|
||
<p>The aware datetime comparison operators will work the same as they do
|
||
now, with results indirectly affected by the value of <code class="docutils literal notranslate"><span class="pre">fold</span></code> whenever
|
||
the <code class="docutils literal notranslate"><span class="pre">utcoffset()</span></code> value of one of the operands depends on it, with one
|
||
exception. Whenever one or both of the operands in inter-zone comparison is
|
||
such that its <code class="docutils literal notranslate"><span class="pre">utcoffset()</span></code> depends on the value of its <code class="docutils literal notranslate"><span class="pre">fold</span></code>
|
||
fold attribute, the result is <code class="docutils literal notranslate"><span class="pre">False</span></code>. <a class="footnote-reference brackets" href="#id12" id="id11">[6]</a></p>
|
||
<aside class="footnote-list brackets">
|
||
<aside class="footnote brackets" id="id12" role="doc-footnote">
|
||
<dt class="label" id="id12">[<a href="#id11">6</a>]</dt>
|
||
<dd>This exception is designed to preserve the hash and equivalence
|
||
invariants in the face of paradoxes of inter-zone arithmetic.</aside>
|
||
</aside>
|
||
<p>Formally, <code class="docutils literal notranslate"><span class="pre">t</span> <span class="pre">==</span> <span class="pre">s</span></code> when <code class="docutils literal notranslate"><span class="pre">t.tzinfo</span> <span class="pre">is</span> <span class="pre">s.tzinfo</span></code> evaluates to
|
||
<code class="docutils literal notranslate"><span class="pre">False</span></code> can be defined as follows. Let <code class="docutils literal notranslate"><span class="pre">toutc(t,</span> <span class="pre">fold)</span></code> be a
|
||
function that takes an aware datetime instance <code class="docutils literal notranslate"><span class="pre">t</span></code> and returns a
|
||
naive instance representing the same time in UTC assuming a given
|
||
value of <code class="docutils literal notranslate"><span class="pre">fold</span></code>:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">toutc</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">fold</span><span class="p">):</span>
|
||
<span class="n">u</span> <span class="o">=</span> <span class="n">t</span> <span class="o">-</span> <span class="n">t</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="n">fold</span><span class="o">=</span><span class="n">fold</span><span class="p">)</span><span class="o">.</span><span class="n">utcoffset</span><span class="p">()</span>
|
||
<span class="k">return</span> <span class="n">u</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="n">tzinfo</span><span class="o">=</span><span class="kc">None</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Then <code class="docutils literal notranslate"><span class="pre">t</span> <span class="pre">==</span> <span class="pre">s</span></code> is equivalent to</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">toutc</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">fold</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span> <span class="o">==</span> <span class="n">toutc</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">fold</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span> <span class="o">==</span> <span class="n">toutc</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">fold</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span> <span class="o">==</span> <span class="n">toutc</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">fold</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
</section>
|
||
<section id="backward-and-forward-compatibility">
|
||
<h2><a class="toc-backref" href="#backward-and-forward-compatibility" role="doc-backlink">Backward and Forward Compatibility</a></h2>
|
||
<p>This proposal will have little effect on the programs that do not read
|
||
the <code class="docutils literal notranslate"><span class="pre">fold</span></code> flag explicitly or use tzinfo implementations that do.
|
||
The only visible change for such programs will be that conversions to
|
||
and from POSIX timestamps will now round-trip correctly (up to
|
||
floating point rounding). Programs that implemented a work-around to
|
||
the old incorrect behavior may need to be modified.</p>
|
||
<p>Pickles produced by older programs will remain fully forward
|
||
compatible. Only datetime/time instances with <code class="docutils literal notranslate"><span class="pre">fold=1</span></code> pickled
|
||
in the new versions will become unreadable by the older Python
|
||
versions. Pickles of instances with <code class="docutils literal notranslate"><span class="pre">fold=0</span></code> (which is the
|
||
default) will remain unchanged.</p>
|
||
</section>
|
||
<section id="questions-and-answers">
|
||
<h2><a class="toc-backref" href="#questions-and-answers" role="doc-backlink">Questions and Answers</a></h2>
|
||
<section id="why-not-call-the-new-flag-isdst">
|
||
<h3><a class="toc-backref" href="#why-not-call-the-new-flag-isdst" role="doc-backlink">Why not call the new flag “isdst”?</a></h3>
|
||
<section id="a-non-technical-answer">
|
||
<h4><a class="toc-backref" href="#a-non-technical-answer" role="doc-backlink">A non-technical answer</a></h4>
|
||
<ul class="simple">
|
||
<li>Alice: Bob - let’s have a stargazing party at 01:30 AM tomorrow!</li>
|
||
<li>Bob: Should I presume initially that Daylight Saving Time is or is
|
||
not in effect for the specified time?</li>
|
||
<li>Alice: Huh?</li>
|
||
</ul>
|
||
<hr class="docutils" />
|
||
<ul class="simple">
|
||
<li>Bob: Alice - let’s have a stargazing party at 01:30 AM tomorrow!</li>
|
||
<li>Alice: You know, Bob, 01:30 AM will happen twice tomorrow. Which time do you have in mind?</li>
|
||
<li>Bob: I did not think about it, but let’s pick the first.</li>
|
||
</ul>
|
||
<hr class="docutils" />
|
||
<p>(same characters, an hour later)</p>
|
||
<hr class="docutils" />
|
||
<ul class="simple">
|
||
<li>Bob: Alice - this Py-O-Clock gadget of mine asks me to choose
|
||
between fold=0 and fold=1 when I set it for tomorrow 01:30 AM.
|
||
What should I do?</li>
|
||
<li>Alice: I’ve never hear of a Py-O-Clock, but I guess fold=0 is
|
||
the first 01:30 AM and fold=1 is the second.</li>
|
||
</ul>
|
||
</section>
|
||
<section id="a-technical-reason">
|
||
<h4><a class="toc-backref" href="#a-technical-reason" role="doc-backlink">A technical reason</a></h4>
|
||
<p>While the <code class="docutils literal notranslate"><span class="pre">tm_isdst</span></code> field of the <code class="docutils literal notranslate"><span class="pre">time.struct_time</span></code> object can be
|
||
used to disambiguate local times in the fold, the semantics of such
|
||
disambiguation are completely different from the proposal in this PEP.</p>
|
||
<p>The main problem with the <code class="docutils literal notranslate"><span class="pre">tm_isdst</span></code> field is that it is impossible
|
||
to know what value is appropriate for <code class="docutils literal notranslate"><span class="pre">tm_isdst</span></code> without knowing the
|
||
details about the time zone that are only available to the <code class="docutils literal notranslate"><span class="pre">tzinfo</span></code>
|
||
implementation. Thus while <code class="docutils literal notranslate"><span class="pre">tm_isdst</span></code> is useful in the <em>output</em> of
|
||
methods such as <code class="docutils literal notranslate"><span class="pre">time.localtime</span></code>, it is cumbersome as an <em>input</em> of
|
||
methods such as <code class="docutils literal notranslate"><span class="pre">time.mktime</span></code>.</p>
|
||
<p>If the programmer misspecified a non-negative value of <code class="docutils literal notranslate"><span class="pre">tm_isdst</span></code> to
|
||
<code class="docutils literal notranslate"><span class="pre">time.mktime</span></code>, the result will be time that is 1 hour off and since
|
||
there is rarely a way to know anything about DST <em>before</em> a call to
|
||
<code class="docutils literal notranslate"><span class="pre">time.mktime</span></code> is made, the only sane choice is usually
|
||
<code class="docutils literal notranslate"><span class="pre">tm_isdst=-1</span></code>.</p>
|
||
<p>Unlike <code class="docutils literal notranslate"><span class="pre">tm_isdst</span></code>, the proposed <code class="docutils literal notranslate"><span class="pre">fold</span></code> attribute has no effect on
|
||
the interpretation of the datetime instance unless without that
|
||
attribute two (or no) interpretations are possible.</p>
|
||
<p>Since it would be very confusing to have something called <code class="docutils literal notranslate"><span class="pre">isdst</span></code>
|
||
that does not have the same semantics as <code class="docutils literal notranslate"><span class="pre">tm_isdst</span></code>, we need a
|
||
different name. Moreover, the <code class="docutils literal notranslate"><span class="pre">datetime.datetime</span></code> class already has
|
||
a method called <code class="docutils literal notranslate"><span class="pre">dst()</span></code> and if we called <code class="docutils literal notranslate"><span class="pre">fold</span></code> “isdst”, we would
|
||
necessarily have situations when “isdst” is zero but <code class="docutils literal notranslate"><span class="pre">dst()</span></code> is not
|
||
or the other way around.</p>
|
||
</section>
|
||
</section>
|
||
<section id="why-fold">
|
||
<h3><a class="toc-backref" href="#why-fold" role="doc-backlink">Why “fold”?</a></h3>
|
||
<p>Suggested by Guido van Rossum and favored by one (but initially
|
||
disfavored by another) author. A consensus was reached after the
|
||
allowed values for the attribute were changed from False/True to 0/1.
|
||
The noun “fold” has correct connotations and easy mnemonic rules, but
|
||
at the same time does not invite unbased assumptions.</p>
|
||
</section>
|
||
<section id="what-is-first">
|
||
<h3><a class="toc-backref" href="#what-is-first" role="doc-backlink">What is “first”?</a></h3>
|
||
<p>This was a working name of the attribute chosen initially because the
|
||
obvious alternative (“second”) conflicts with the existing attribute.
|
||
It was rejected mostly on the grounds that it would make True a
|
||
default value.</p>
|
||
<p>The following alternative names have also been considered:</p>
|
||
<dl class="simple">
|
||
<dt><strong>later</strong></dt><dd>A close contender to “fold”. One author dislikes it because
|
||
it is confusable with equally fitting “latter,” but in the age
|
||
of auto-completion everywhere this is a small consideration. A
|
||
stronger objection may be that in the case of missing time, we
|
||
will have <code class="docutils literal notranslate"><span class="pre">later=True</span></code> instance converted to an earlier time by
|
||
<code class="docutils literal notranslate"><span class="pre">.astimezone(timezone.utc)</span></code> that that with <code class="docutils literal notranslate"><span class="pre">later=False</span></code>.
|
||
Yet again, this can be interpreted as a desirable indication that
|
||
the original time is invalid.</dd>
|
||
<dt><strong>which</strong></dt><dd>The <a class="reference external" href="https://mail.python.org/pipermail/python-dev/2015-April/139099.html">original</a> placeholder name for the <code class="docutils literal notranslate"><span class="pre">localtime</span></code> function
|
||
branch index was <a class="reference external" href="https://mail.python.org/pipermail/datetime-sig/2015-August/000479.html">independently proposed</a> for the name of the
|
||
disambiguation attribute and received <a class="reference external" href="https://mail.python.org/pipermail/datetime-sig/2015-August/000483.html">some support</a>.</dd>
|
||
<dt><strong>repeated</strong></dt><dd>Did not receive any support on the mailing list.</dd>
|
||
<dt><strong>ltdf</strong></dt><dd>(Local Time Disambiguation Flag) - short and no-one will attempt
|
||
to guess what it means without reading the docs. (This abbreviation
|
||
was used in PEP discussions with the meaning <code class="docutils literal notranslate"><span class="pre">ltdf=False</span></code> is the
|
||
earlier by those who didn’t want to endorse any of the alternatives.)</dd>
|
||
</dl>
|
||
</section>
|
||
<section id="are-two-values-enough">
|
||
<h3><a class="toc-backref" href="#are-two-values-enough" role="doc-backlink">Are two values enough?</a></h3>
|
||
<p>Several reasons have been raised to allow a <code class="docutils literal notranslate"><span class="pre">None</span></code> or -1 value for
|
||
the <code class="docutils literal notranslate"><span class="pre">fold</span></code> attribute: backward compatibility, analogy with <code class="docutils literal notranslate"><span class="pre">tm_isdst</span></code>
|
||
and strict checking for invalid times.</p>
|
||
<section id="backward-compatibility">
|
||
<h4><a class="toc-backref" href="#backward-compatibility" role="doc-backlink">Backward Compatibility</a></h4>
|
||
<p>It has been suggested that backward compatibility can be improved if
|
||
the default value of the <code class="docutils literal notranslate"><span class="pre">fold</span></code> flag was <code class="docutils literal notranslate"><span class="pre">None</span></code> which would
|
||
signal that pre-PEP behavior is requested. Based on the analysis
|
||
below, we believe that the proposed changes with the <code class="docutils literal notranslate"><span class="pre">fold=0</span></code>
|
||
default are sufficiently backward compatible.</p>
|
||
<p>This PEP provides only three ways for a program to discover that two
|
||
otherwise identical datetime instances have different values of
|
||
<code class="docutils literal notranslate"><span class="pre">fold</span></code>: (1) an explicit check of the <code class="docutils literal notranslate"><span class="pre">fold</span></code> attribute; (2) if
|
||
the instances are naive - conversion to another timezone using the
|
||
<code class="docutils literal notranslate"><span class="pre">astimezone()</span></code> method; and (3) conversion to <code class="docutils literal notranslate"><span class="pre">float</span></code> using the
|
||
<code class="docutils literal notranslate"><span class="pre">timestamp()</span></code> method.</p>
|
||
<p>Since <code class="docutils literal notranslate"><span class="pre">fold</span></code> is a new attribute, the first option is not available
|
||
to the existing programs. Note that option (2) only works for naive
|
||
datetimes that happen to be in a fold or a gap in the system time
|
||
zone. In all other cases, the value of <code class="docutils literal notranslate"><span class="pre">fold</span></code> will be ignored in
|
||
the conversion unless the instances use a <code class="docutils literal notranslate"><span class="pre">fold</span></code>-aware <code class="docutils literal notranslate"><span class="pre">tzinfo</span></code>
|
||
which would not be available in a pre-PEP program. Similarly, the
|
||
<code class="docutils literal notranslate"><span class="pre">astimezone()</span></code> called on a naive instance will not be available in
|
||
such program because <code class="docutils literal notranslate"><span class="pre">astimezone()</span></code> does not currently work with
|
||
naive datetimes.</p>
|
||
<p>This leaves us with only one situation where an existing program can
|
||
start producing different results after the implementation of this PEP:
|
||
when a <code class="docutils literal notranslate"><span class="pre">datetime.timestamp()</span></code> method is called on a naive datetime
|
||
instance that happen to be in the fold or the gap. In the current
|
||
implementation, the result is undefined. Depending on the system
|
||
<code class="docutils literal notranslate"><span class="pre">mktime</span></code> implementation, the programs can see different results or
|
||
errors in those cases. With this PEP in place, the value of timestamp
|
||
will be well-defined in those cases but will depend on the value of
|
||
the <code class="docutils literal notranslate"><span class="pre">fold</span></code> flag. We consider the change in
|
||
<code class="docutils literal notranslate"><span class="pre">datetime.timestamp()</span></code> method behavior a bug fix enabled by this
|
||
PEP. The old behavior can still be emulated by the users who depend
|
||
on it by writing <code class="docutils literal notranslate"><span class="pre">time.mktime(dt.timetuple())</span> <span class="pre">+</span> <span class="pre">1e-6*dt.microsecond</span></code>
|
||
instead of <code class="docutils literal notranslate"><span class="pre">dt.timestamp()</span></code>.</p>
|
||
</section>
|
||
<section id="analogy-with-tm-isdst">
|
||
<h4><a class="toc-backref" href="#analogy-with-tm-isdst" role="doc-backlink">Analogy with tm_isdst</a></h4>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">time.mktime</span></code> interface allows three values for the <code class="docutils literal notranslate"><span class="pre">tm_isdst</span></code>
|
||
flag: -1, 0, and 1. As we explained above, -1 (asking <code class="docutils literal notranslate"><span class="pre">mktime</span></code> to
|
||
determine whether DST is in effect for the given time from the rest of
|
||
the fields) is the only choice that is useful in practice.</p>
|
||
<p>With the <code class="docutils literal notranslate"><span class="pre">fold</span></code> flag, however, <code class="docutils literal notranslate"><span class="pre">datetime.timestamp()</span></code> will return
|
||
the same value as <code class="docutils literal notranslate"><span class="pre">mktime</span></code> with <code class="docutils literal notranslate"><span class="pre">tm_isdst=-1</span></code> in 99.98% of the
|
||
time for most time zones with DST transitions. Moreover,
|
||
<code class="docutils literal notranslate"><span class="pre">tm_isdst=-1</span></code>-like behavior is specified <em>regardless</em> of the value
|
||
of <code class="docutils literal notranslate"><span class="pre">fold</span></code>.</p>
|
||
<p>It is only in the 0.02% cases (2 hours per year) that the
|
||
<code class="docutils literal notranslate"><span class="pre">datetime.timestamp()</span></code> and <code class="docutils literal notranslate"><span class="pre">mktime</span></code> with <code class="docutils literal notranslate"><span class="pre">tm_isdst=-1</span></code> may
|
||
disagree. However, even in this case, most of the <code class="docutils literal notranslate"><span class="pre">mktime</span></code>
|
||
implementations will return the <code class="docutils literal notranslate"><span class="pre">fold=0</span></code> or the <code class="docutils literal notranslate"><span class="pre">fold=1</span></code>
|
||
value even though relevant standards allow <code class="docutils literal notranslate"><span class="pre">mktime</span></code> to return -1 and
|
||
set an error code in those cases.</p>
|
||
<p>In other words, <code class="docutils literal notranslate"><span class="pre">tm_isdst=-1</span></code> behavior is not missing from this PEP.
|
||
To the contrary, it is the only behavior provided in two different
|
||
well-defined flavors. The behavior that is missing is when a given
|
||
local hour is interpreted as a different local hour because of the
|
||
misspecified <code class="docutils literal notranslate"><span class="pre">tm_isdst</span></code>.</p>
|
||
<p>For example, in the DST-observing time zones in the Northern
|
||
hemisphere (where DST is in effect in June) one can get</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="kn">from</span> <span class="nn">time</span> <span class="kn">import</span> <span class="n">mktime</span><span class="p">,</span> <span class="n">localtime</span>
|
||
<span class="gp">>>> </span><span class="n">t</span> <span class="o">=</span> <span class="n">mktime</span><span class="p">((</span><span class="mi">2015</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">12</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>
|
||
<span class="gp">>>> </span><span class="n">localtime</span><span class="p">(</span><span class="n">t</span><span class="p">)[:]</span>
|
||
<span class="go">(2015, 6, 1, 13, 0, 0, 0, 152, 1)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Note that 12:00 was interpreted as 13:00 by <code class="docutils literal notranslate"><span class="pre">mktime</span></code>. With the
|
||
<code class="docutils literal notranslate"><span class="pre">datetime.timestamp</span></code>, <code class="docutils literal notranslate"><span class="pre">datetime.fromtimestamp</span></code>, it is currently
|
||
guaranteed that</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">t</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="p">(</span><span class="mi">2015</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">12</span><span class="p">)</span><span class="o">.</span><span class="n">timestamp</span><span class="p">()</span>
|
||
<span class="gp">>>> </span><span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">fromtimestamp</span><span class="p">(</span><span class="n">t</span><span class="p">)</span>
|
||
<span class="go">datetime.datetime(2015, 6, 1, 12, 0)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>This PEP extends the same guarantee to both values of <code class="docutils literal notranslate"><span class="pre">fold</span></code>:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">t</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="p">(</span><span class="mi">2015</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">12</span><span class="p">,</span> <span class="n">fold</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span><span class="o">.</span><span class="n">timestamp</span><span class="p">()</span>
|
||
<span class="gp">>>> </span><span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">fromtimestamp</span><span class="p">(</span><span class="n">t</span><span class="p">)</span>
|
||
<span class="go">datetime.datetime(2015, 6, 1, 12, 0)</span>
|
||
</pre></div>
|
||
</div>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">t</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="p">(</span><span class="mi">2015</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">12</span><span class="p">,</span> <span class="n">fold</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">timestamp</span><span class="p">()</span>
|
||
<span class="gp">>>> </span><span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">fromtimestamp</span><span class="p">(</span><span class="n">t</span><span class="p">)</span>
|
||
<span class="go">datetime.datetime(2015, 6, 1, 12, 0)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Thus one of the suggested uses for <code class="docutils literal notranslate"><span class="pre">fold=-1</span></code> – to match the legacy
|
||
behavior – is not needed. Either choice of <code class="docutils literal notranslate"><span class="pre">fold</span></code> will match the
|
||
old behavior except in the few cases where the old behavior was
|
||
undefined.</p>
|
||
</section>
|
||
<section id="strict-invalid-time-checking">
|
||
<h4><a class="toc-backref" href="#strict-invalid-time-checking" role="doc-backlink">Strict Invalid Time Checking</a></h4>
|
||
<p>Another suggestion was to use <code class="docutils literal notranslate"><span class="pre">fold=-1</span></code> or <code class="docutils literal notranslate"><span class="pre">fold=None</span></code> to
|
||
indicate that the program truly has no means to deal with the folds
|
||
and gaps and <code class="docutils literal notranslate"><span class="pre">dt.utcoffset()</span></code> should raise an error whenever <code class="docutils literal notranslate"><span class="pre">dt</span></code>
|
||
represents an ambiguous or missing local time.</p>
|
||
<p>The main problem with this proposal, is that <code class="docutils literal notranslate"><span class="pre">dt.utcoffset()</span></code> is
|
||
used internally in situations where raising an error is not an option:
|
||
for example, in dictionary lookups or list/set membership checks. So
|
||
strict gap/fold checking behavior would need to be controlled by a
|
||
separate flag, say <code class="docutils literal notranslate"><span class="pre">dt.utcoffset(raise_on_gap=True,</span>
|
||
<span class="pre">raise_on_fold=False)</span></code>. However, this functionality can be easily
|
||
implemented in user code:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">utcoffset</span><span class="p">(</span><span class="n">dt</span><span class="p">,</span> <span class="n">raise_on_gap</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">raise_on_fold</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
|
||
<span class="n">u</span> <span class="o">=</span> <span class="n">dt</span><span class="o">.</span><span class="n">utcoffset</span><span class="p">()</span>
|
||
<span class="n">v</span> <span class="o">=</span> <span class="n">dt</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="n">fold</span><span class="o">=</span><span class="ow">not</span> <span class="n">dt</span><span class="o">.</span><span class="n">fold</span><span class="p">)</span><span class="o">.</span><span class="n">utcoffset</span><span class="p">()</span>
|
||
<span class="k">if</span> <span class="n">u</span> <span class="o">==</span> <span class="n">v</span><span class="p">:</span>
|
||
<span class="k">return</span> <span class="n">u</span>
|
||
<span class="k">if</span> <span class="p">(</span><span class="n">u</span> <span class="o"><</span> <span class="n">v</span><span class="p">)</span> <span class="o">==</span> <span class="n">dt</span><span class="o">.</span><span class="n">fold</span><span class="p">:</span>
|
||
<span class="k">if</span> <span class="n">raise_on_fold</span><span class="p">:</span>
|
||
<span class="k">raise</span> <span class="n">AmbiguousTimeError</span>
|
||
<span class="k">else</span><span class="p">:</span>
|
||
<span class="k">if</span> <span class="n">raise_on_gap</span><span class="p">:</span>
|
||
<span class="k">raise</span> <span class="n">MissingTimeError</span>
|
||
<span class="k">return</span> <span class="n">u</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Moreover, raising an error in the problem cases is only one of many
|
||
possible solutions. An interactive program can ask the user for
|
||
additional input, while a server process may log a warning and take an
|
||
appropriate default action. We cannot possibly provide functions for
|
||
all possible user requirements, but this PEP provides the means to
|
||
implement any desired behavior in a few lines of code.</p>
|
||
</section>
|
||
</section>
|
||
</section>
|
||
<section id="implementation">
|
||
<h2><a class="toc-backref" href="#implementation" role="doc-backlink">Implementation</a></h2>
|
||
<ul class="simple">
|
||
<li>Github fork: <a class="reference external" href="https://github.com/abalkin/cpython/tree/issue24773-s3">https://github.com/abalkin/cpython/tree/issue24773-s3</a></li>
|
||
<li>Tracker issue: <a class="reference external" href="http://bugs.python.org/issue24773">http://bugs.python.org/issue24773</a></li>
|
||
</ul>
|
||
</section>
|
||
<section id="copyright">
|
||
<h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2>
|
||
<p>This document has been placed in the public domain.</p>
|
||
</section>
|
||
<section id="picture-credit">
|
||
<h2><a class="toc-backref" href="#picture-credit" role="doc-backlink">Picture Credit</a></h2>
|
||
<p>This image is a work of a U.S. military or Department of Defense
|
||
employee, taken or made as part of that person’s official duties. As a
|
||
work of the U.S. federal government, the image is in the public
|
||
domain.</p>
|
||
</section>
|
||
</section>
|
||
<hr class="docutils" />
|
||
<p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0495.rst">https://github.com/python/peps/blob/main/peps/pep-0495.rst</a></p>
|
||
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0495.rst">2024-01-11 16:25:09 GMT</a></p>
|
||
|
||
</article>
|
||
<nav id="pep-sidebar">
|
||
<h2>Contents</h2>
|
||
<ul>
|
||
<li><a class="reference internal" href="#abstract">Abstract</a></li>
|
||
<li><a class="reference internal" href="#rationale">Rationale</a></li>
|
||
<li><a class="reference internal" href="#terminology">Terminology</a></li>
|
||
<li><a class="reference internal" href="#proposal">Proposal</a><ul>
|
||
<li><a class="reference internal" href="#the-fold-attribute">The “fold” attribute</a></li>
|
||
<li><a class="reference internal" href="#affected-apis">Affected APIs</a><ul>
|
||
<li><a class="reference internal" href="#attributes">Attributes</a></li>
|
||
<li><a class="reference internal" href="#constructors">Constructors</a></li>
|
||
<li><a class="reference internal" href="#methods">Methods</a></li>
|
||
<li><a class="reference internal" href="#c-api">C-API</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#affected-behaviors">Affected Behaviors</a><ul>
|
||
<li><a class="reference internal" href="#what-time-is-it">What time is it?</a></li>
|
||
<li><a class="reference internal" href="#conversion-from-naive-to-aware">Conversion from naive to aware</a></li>
|
||
<li><a class="reference internal" href="#conversion-from-posix-seconds-from-epoch">Conversion from POSIX seconds from EPOCH</a></li>
|
||
<li><a class="reference internal" href="#conversion-to-posix-seconds-from-epoch">Conversion to POSIX seconds from EPOCH</a></li>
|
||
<li><a class="reference internal" href="#aware-datetime-instances">Aware datetime instances</a></li>
|
||
<li><a class="reference internal" href="#combining-and-splitting-date-and-time">Combining and splitting date and time</a></li>
|
||
<li><a class="reference internal" href="#pickles">Pickles</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#implementations-of-tzinfo-in-the-standard-library">Implementations of tzinfo in the Standard Library</a></li>
|
||
<li><a class="reference internal" href="#guidelines-for-new-tzinfo-implementations">Guidelines for New tzinfo Implementations</a><ul>
|
||
<li><a class="reference internal" href="#ignorance-is-bliss">Ignorance is Bliss</a></li>
|
||
<li><a class="reference internal" href="#in-the-fold">In the Fold</a></li>
|
||
<li><a class="reference internal" href="#mind-the-gap">Mind the Gap</a></li>
|
||
<li><a class="reference internal" href="#summary-of-rules-at-a-transition">Summary of Rules at a Transition</a></li>
|
||
<li><a class="reference internal" href="#the-dst-transitions">The DST Transitions</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#temporal-arithmetic-and-comparison-operators">Temporal Arithmetic and Comparison Operators</a><ul>
|
||
<li><a class="reference internal" href="#aware-datetime-equality-comparison">Aware datetime Equality Comparison</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#backward-and-forward-compatibility">Backward and Forward Compatibility</a></li>
|
||
<li><a class="reference internal" href="#questions-and-answers">Questions and Answers</a><ul>
|
||
<li><a class="reference internal" href="#why-not-call-the-new-flag-isdst">Why not call the new flag “isdst”?</a><ul>
|
||
<li><a class="reference internal" href="#a-non-technical-answer">A non-technical answer</a></li>
|
||
<li><a class="reference internal" href="#a-technical-reason">A technical reason</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#why-fold">Why “fold”?</a></li>
|
||
<li><a class="reference internal" href="#what-is-first">What is “first”?</a></li>
|
||
<li><a class="reference internal" href="#are-two-values-enough">Are two values enough?</a><ul>
|
||
<li><a class="reference internal" href="#backward-compatibility">Backward Compatibility</a></li>
|
||
<li><a class="reference internal" href="#analogy-with-tm-isdst">Analogy with tm_isdst</a></li>
|
||
<li><a class="reference internal" href="#strict-invalid-time-checking">Strict Invalid Time Checking</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#implementation">Implementation</a></li>
|
||
<li><a class="reference internal" href="#copyright">Copyright</a></li>
|
||
<li><a class="reference internal" href="#picture-credit">Picture Credit</a></li>
|
||
</ul>
|
||
|
||
<br>
|
||
<a id="source" href="https://github.com/python/peps/blob/main/peps/pep-0495.rst">Page Source (GitHub)</a>
|
||
</nav>
|
||
</section>
|
||
<script src="../_static/colour_scheme.js"></script>
|
||
<script src="../_static/wrap_tables.js"></script>
|
||
<script src="../_static/sticky_banner.js"></script>
|
||
</body>
|
||
</html> |