python-peps/pep-0495/index.html

1009 lines
92 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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:description" content="This PEP adds a new attribute fold to instances of the datetime.time and datetime.datetime classes that can be used to differentiate between two moments in time for which local times are the same. The allowed values for the fold attribute will be 0 and...">
<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="This PEP adds a new attribute fold to instances of the datetime.time and datetime.datetime classes that can be used to differentiate between two moments in time for which local times are the same. The allowed values for the fold attribute will be 0 and...">
<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> &raquo; </li>
<li><a href="../pep-0000/">PEP Index</a> &raquo; </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 &lt;alexander.belopolsky&#32;&#97;t&#32;gmail.com&gt;, Tim Peters &lt;tim.peters&#32;&#97;t&#32;gmail.com&gt;</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&#64;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.&quot;" 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 dont 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 stdlibs 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">&gt;&gt;&gt; </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">&gt;&gt;&gt; </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">&#39;%D %T %Z%z&#39;</span><span class="p">)</span>
<span class="go">&#39;11/02/14 01:30:00 EDT-0400&#39;</span>
<span class="gp">&gt;&gt;&gt; </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">&#39;%D %T %Z%z&#39;</span><span class="p">)</span>
<span class="go">&#39;11/02/14 01:30:00 EST-0500&#39;</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">&gt;&gt;&gt; </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">&gt;&gt;&gt; </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">&gt;&gt;&gt; </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">&gt;&gt;&gt; </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 its 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">&gt;&gt;&gt; </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">&gt;&gt;&gt; </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 objects <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> &lt;<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" style="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" style="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 - lets 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 - lets 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 lets 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: Ive 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 didnt 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">&gt;&gt;&gt; </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">&gt;&gt;&gt; </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">&gt;&gt;&gt; </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">&gt;&gt;&gt; </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">&gt;&gt;&gt; </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">&gt;&gt;&gt; </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">&gt;&gt;&gt; </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">&gt;&gt;&gt; </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">&gt;&gt;&gt; </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">&lt;</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 persons 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>