A faster way to calculate the day-of-the-week<br>You need to enable JavaScript to run this app.
RSS Feed<br>X (Twitter)<br>LinkedIn
A faster way to calculate the day of the week<br>A range of fast modulus techniques that beat compiler output<br>17 August 2026<br>Converting a day-count ("rata-die") to the day-of-the-week (“weekday”) sounds like it should be so trivial, that there's almost nothing to say about it. But, as it turns out, when we look under the hood, this is a surprisingly complex problem.<br>Throughout this article I will present a range of really fast functions to solve this problem, tuned for different use cases (throughput vs latency, different platforms etc.). Each outperforms existing solutions, and many have a latency of just a single multiplication plus two cycles. A surprising result is presented: the weekday can be computed in ISO format ([1‥7] instead of [0‥6]), with the exact same instructions, just with tweaked constants (and zero speed penalty).<br>To give you a taste of the insanity, I'll highlight my favourite function here, this crazy looking 3-instruction sequence (plus a constant load) is accurate over the full signed 32-bit range (it may not be the lowest latency full-range algo in this article, but has the highest throughput for x86):<br>Unix Weekday [0‥6] ISO Weekday [1‥7]<br>Given: input (rd = signed 32-Bit Unix day-count); Compute weekday [0‥6]: mov eax, 613566756 ; Constant Load: u32 M = (1<br>imul ecx ; rd * M (u32 a = low bits, i32 b = high bits)<br>lea eax, [eax-1828716544+edx*4] ; u32 r = a + 4 * b + (Z = 0x93000000)<br>shr eax, 29 ; weekday = r >> 29
You don't need prior understanding of assembly to follow this blog post .<br>By the end, you will understand why this code above works.
Visualisation of how the function above produces the desired output. The constant on line-3 acts as a rotation angle.
This article is for people interested in low level bit manipulation, optimising high performance date libraries / database engines, compiler authors, and crazy people in general. The techniques used here generalise to x % (2^N - 1), and new fast modulus techniques are introduced for other divisors such as x % 24 and x % 60 - applicable to timekeeping.<br>If you're just here to copy/paste and benchmark code in your library, you can jump to the "Function Explorer" which has all code examples on this page available to copy/paste from C++.<br>Approx. Relative Speeds of Fastest Algorithms As tested on AMD Ryzen 9 and Apple M4 Pro processors<br>(smaller numbers = faster)<br>See benchmark section<br>for specific results.<br>Others<br>(double-mod, Rust:rem_euclid, Hinnant)<br>~1.5-3+×
Neri (2024)1×
New Algos (2026)~0.3-0.5×
Article Sections:<br>Simple Approaches<br>Hinnant<br>Neri<br>The Unreasonably Fast Mul-Add-Shift AlgorithmFast Full Range via 64-Bit Widening
Fast Full Range (Variant 1: Shifts)<br>Fast Full Range (Variant 2: Two Muls)<br>Fast Full Range (Variant 3: High + Low Bits)<br>The Function Explorer<br>Generalisation<br>Closing Thoughts<br>Annexure A. Benchmark Results<br>Annexure B. Proof of modulus by power-of-2 padding
Simple Approaches Deep link<br>Given: rd = rata-die (day-count, signed 32-Bit int), with epoch 1970-01-01 = Thursday (4) — Then:<br>Double-mod (languages with signed "%", eg. C/C++) weekday = ((rd % 7) + 7 + 4) % 7
Languages with special positive-mod (eg. Rust) weekday = (rd + 4) POSMOD 7
— Where: weekday ∈ [0‥6] (0 = Sunday)<br>This is what I would recommend in most non-library code where maintenance is more important than micro-optimisation.<br>Note that the Rust example overflows for the highest 4 inputs, but assume we don't care about those.<br>The addition of 4 (or 11 = 7 + 4) is due to the Unix epoch 1970-01-01 being a Thursday. If you number your weekdays differently, or use a different epoch, this might vary.<br>These "simple approaches" do the job, but they are quite slow, even in the case of Rust with its positive-mod function (rem_euclid), which translated back into C-style pseudocode, looks like the following:<br>Rust's rem_euclid (compiled pseudocode equivalent) View on Godbolt i32 a = (i64(rd + 4) * -1840700269) >> 32 // Note: This pseudocode assumes<br>i32 b = rd + 4 + a // that overflow of signed addition<br>i32 c = (b >> 2) + (u32(b) >> 31) // is defined as per Rust<br>i32 d = rd - c * 7 // and two's complement, whereas<br>i32 e = d + 4 // for C/C++ it is undefined.<br>u32 weekday = e >= 0 ? e : d + 11
A lot more steps than you might have expected, right?<br>Hinnant Deep link<br>Howard Hinnant's technique (2014) was adopted by many date libraries (see original article ).<br>Hinnant's Algorithm (bit-size independent)<br>Range: INT32_MIN → INT32_MAX − 4 weekday = rd >= -4 ? (rd + 4) % 7<br>: (rd + 5) % 7 + 6
This approach appears designed for simplicity and flexibility. It is the only algorithm from here onwards that does not rely on sign casting or overflow, nor is it bit-width specific. It will be the same logic for 8-bit through to 64-bit.<br>Hinnant points out in his article that this covers the full signed 32-bit range, except for the highest 4 inputs, which in C/C++...