<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>Benchmarking on Oleksii M.</title><link>https://welldonesoftware.dev/tags/benchmarking/</link><description>Recent content in Benchmarking on Oleksii M.</description><generator>Hugo -- 0.154.5</generator><language>en</language><lastBuildDate>Tue, 29 Sep 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://welldonesoftware.dev/tags/benchmarking/index.xml" rel="self" type="application/rss+xml"/><item><title>Choosing the fastest datetime library for Python</title><link>https://welldonesoftware.dev/posts/benchmark-datetime/</link><pubDate>Tue, 29 Sep 2026 00:00:00 +0000</pubDate><guid>https://welldonesoftware.dev/posts/benchmark-datetime/</guid><description>&amp;lt;no value&amp;gt;</description><content type="text/html" mode="escaped"><![CDATA[<p>Python has several popular datetime libraries: the standard-library <code>datetime</code>, <code>python-dateutil</code>, Arrow, Pendulum, <code>udatetime</code>, Whenever, plus parsing functionality in Pydantic and pandas.</p>
<p>If performance matters, which one should you use?</p>
<p>The <a href="https://github.com/alessio-locatelli/benchmark-datetime" target="_blank" ><code>benchmark-datetime</code></a> project compares three kinds of operations:</p>
<ul>
<li>parsing datetime values</li>
<li>manipulating dates and times</li>
<li>dumping datetime values to strings</li>
</ul>
<p>The current benchmark runs on Python 3.14.7 and compares libraries only where the operation is supported and relevant.</p>
<p>The short answer is: <strong>Whenever is the fastest option in 10 of the 12 benchmark groups.</strong></p>
<h2 id="whenever-is-usually-the-fastest">Whenever is usually the fastest<a href="#whenever-is-usually-the-fastest" class="anchor" aria-hidden="true"><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" class="feather">
      <path d="M15 7h3a5 5 0 0 1 5 5 5 5 0 0 1-5 5h-3m-6 0H6a5 5 0 0 1-5-5 5 5 0 0 1 5-5h3"></path>
      <line x1="8" y1="12" x2="16" y2="12"></line>
   </svg></a></h2>
<p>For adding a duration:</p>
<table>
  <thead>
      <tr>
          <th>Library</th>
          <th style="text-align: right">Mean time</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Whenever</td>
          <td style="text-align: right">387 ns</td>
      </tr>
      <tr>
          <td><code>datetime</code></td>
          <td style="text-align: right">976 ns</td>
      </tr>
      <tr>
          <td>Pendulum</td>
          <td style="text-align: right">4.53 µs</td>
      </tr>
      <tr>
          <td>Arrow</td>
          <td style="text-align: right">8.04 µs</td>
      </tr>
  </tbody>
</table>
<p>For getting the current local time:</p>
<table>
  <thead>
      <tr>
          <th>Library</th>
          <th style="text-align: right">Mean time</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Whenever</td>
          <td style="text-align: right">95.3 ns</td>
      </tr>
      <tr>
          <td><code>udatetime</code></td>
          <td style="text-align: right">121 ns</td>
      </tr>
      <tr>
          <td><code>datetime</code></td>
          <td style="text-align: right">170 ns</td>
      </tr>
      <tr>
          <td>Pendulum</td>
          <td style="text-align: right">974 ns</td>
      </tr>
      <tr>
          <td>Arrow</td>
          <td style="text-align: right">3.25 µs</td>
      </tr>
  </tbody>
</table>
<p>For dumping a datetime to ISO format:</p>
<table>
  <thead>
      <tr>
          <th>Library</th>
          <th style="text-align: right">Mean time</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Whenever</td>
          <td style="text-align: right">119 ns</td>
      </tr>
      <tr>
          <td><code>udatetime</code></td>
          <td style="text-align: right">424 ns</td>
      </tr>
      <tr>
          <td><code>datetime</code></td>
          <td style="text-align: right">1.05 µs</td>
      </tr>
      <tr>
          <td>Arrow</td>
          <td style="text-align: right">1.08 µs</td>
      </tr>
      <tr>
          <td>Pendulum</td>
          <td style="text-align: right">1.54 µs</td>
      </tr>
  </tbody>
</table>
<p>The same pattern appears across most of this benchmark suite: Whenever has noticeably lower overhead than the alternatives in these tests.</p>
<h2 id="parsing-shows-the-biggest-differences">Parsing shows the biggest differences<a href="#parsing-shows-the-biggest-differences" class="anchor" aria-hidden="true"><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" class="feather">
      <path d="M15 7h3a5 5 0 0 1 5 5 5 5 0 0 1-5 5h-3m-6 0H6a5 5 0 0 1-5-5 5 5 0 0 1 5-5h3"></path>
      <line x1="8" y1="12" x2="16" y2="12"></line>
   </svg></a></h2>
<p>ISO 8601 parsing is especially interesting:</p>
<table>
  <thead>
      <tr>
          <th>Library</th>
          <th style="text-align: right">Mean time</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Whenever</td>
          <td style="text-align: right">89.6 ns</td>
      </tr>
      <tr>
          <td><code>datetime.fromisoformat()</code></td>
          <td style="text-align: right">103 ns</td>
      </tr>
      <tr>
          <td>Pydantic</td>
          <td style="text-align: right">399 ns</td>
      </tr>
      <tr>
          <td><code>udatetime</code></td>
          <td style="text-align: right">512 ns</td>
      </tr>
      <tr>
          <td>pandas</td>
          <td style="text-align: right">2.74 µs</td>
      </tr>
      <tr>
          <td><code>python-dateutil</code></td>
          <td style="text-align: right">4.64 µs</td>
      </tr>
      <tr>
          <td>Pendulum</td>
          <td style="text-align: right">4.96 µs</td>
      </tr>
      <tr>
          <td>Arrow</td>
          <td style="text-align: right">33.9 µs</td>
      </tr>
  </tbody>
</table>
<p>Here, the standard library is almost as fast as Whenever.</p>
<p>Arrow is hundreds of times slower in this particular benchmark because <code>arrow.get()</code> is a more general parsing interface, while <code>datetime.fromisoformat()</code> and <code>OffsetDateTime.parse_iso()</code> are specialized APIs.</p>
<p>That distinction matters: the benchmark measures the actual API call used for the operation, not some abstract notion of library speed.</p>
<h2 id="the-exceptions-are-useful">The exceptions are useful<a href="#the-exceptions-are-useful" class="anchor" aria-hidden="true"><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" class="feather">
      <path d="M15 7h3a5 5 0 0 1 5 5 5 5 0 0 1-5 5h-3m-6 0H6a5 5 0 0 1-5-5 5 5 0 0 1 5-5h3"></path>
      <line x1="8" y1="12" x2="16" y2="12"></line>
   </svg></a></h2>
<p>Whenever does not win every benchmark.</p>
<p>For a weekday lookup, Python&rsquo;s <code>datetime</code> and <code>udatetime</code> take about 58 ns, while Whenever takes about 172 ns.</p>
<p>The reason is simple: <code>datetime</code> exposes <code>.weekday()</code> directly. Whenever needs a longer call chain to produce the same 0–6 numbering:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>dt<span style="color:#f92672">.</span>date()<span style="color:#f92672">.</span>day_of_week()<span style="color:#f92672">.</span>value <span style="color:#f92672">-</span> <span style="color:#ae81ff">1</span>
</span></span></code></pre></div><p>ISO 8601 duration parsing is another exception. Pydantic takes about 352 ns, while Whenever takes about 4.73 µs because it first parses an <code>ItemizedDelta</code> and then converts it to <code>TimeDelta</code>.</p>
<p>These cases show why one overall score would be misleading. API design affects performance too.</p>
<h2 id="what-should-you-choose">What should you choose?<a href="#what-should-you-choose" class="anchor" aria-hidden="true"><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" class="feather">
      <path d="M15 7h3a5 5 0 0 1 5 5 5 5 0 0 1-5 5h-3m-6 0H6a5 5 0 0 1-5-5 5 5 0 0 1 5-5h3"></path>
      <line x1="8" y1="12" x2="16" y2="12"></line>
   </svg></a></h2>
<p>If raw datetime performance is important, <strong>Whenever is the strongest option in this benchmark</strong>.</p>
<p>But <code>datetime</code> remains very competitive, especially for ISO 8601 parsing and simple operations, and it requires no extra dependency.</p>
<p>Arrow and Pendulum provide higher-level APIs and are slower in many of these benchmarks. Choosing them for that convenience can be a reasonable trade-off when datetime operations are not a bottleneck.</p>
<p>Pydantic and pandas should generally be chosen for their broader functionality rather than as standalone datetime libraries, although their existing datetime APIs may be useful when those packages are already dependencies.</p>
<p>A practical approach is:</p>
<ul>
<li>Use <code>datetime</code> if it already does what is needed.</li>
<li>Consider Whenever when datetime operations are performance-sensitive.</li>
<li>When using Arrow, Pendulum, Pydantic, or pandas for their functionality, benchmark the specific relevant operations rather than treating the whole library as fast or slow.</li>
</ul>
<p>The full benchmark results, source code, and histograms are available in <a href="https://github.com/alessio-locatelli/benchmark-datetime" target="_blank" ><code>benchmark-datetime</code></a>.</p>
]]></content></item></channel></rss>