Introduction
Let’s be honest, for all human-kind creatures in the world handling dates in is harder than it should be!
The following content is inspired by Eric Evans on one of his brilliant talk at DDD Europe 2018
I’ve spent years building systems that rely on time: payroll platforms, accounting tools, HR modules, and international apps. And in every one of them, the same pain points come up again and again. So instead of fighting DateTime one more time, I built Quantum.Tempo , a library designed to make working with time easier, smarter, and more flexible in .NET.
Let’s start with some real-life developer conversations. These aren’t made up, they’re pulled straight from projects I’ve worked on.
Accounting: We use a fiscal calendar that starts in March. Nothing works out of the box.
You’re building an accounting system. Reports don’t follow the January–December year. You start your fiscal year in March. Yet every built-in method, every helper, every report assumes the Gregorian calendar and starts from January. Now you’re stuck rewriting logic, again for something so basic.
Payroll: We process payroll using year-months like ‘2024–05’. But DateTime.Parse throws.
HR and finance teams don’t always care about full dates. Often, they give you “2024–05” and expect you to just know what that means. But try parsing that in .NET and you’ll get an exception or a silent error. Now you’re back to guessing days or coercing strings.
HR: Our users want dates in Persian. Our backend is stuck in Gregorian.
Your users in Iran expect “1403–02–15”. But your backend returns “2024–05–04”. You try converting it, but DateTime doesn’t support Persian calendars easily. And even if it did, what about formatting it in Farsi? Or parsing from Persian into the system?
Legacy Data: Our legacy data only has years like ‘1990’ or year-month like ‘2010–06’. We can’t lose it.
You can’t demand perfect data from old systems. Sometimes all you have is “1990”. But try to store or manipulate that in a DateTime, and you’ll be forced to guess a full date, or throw the record away.
These are not edge cases. They are everyday cases. And they’re exactly what Quantum.Tempo is built to solve.
Sound familiar?
If you’ve ever had to handle time beyond the usual “Gregorian date at midnight,” you’ve felt this. Most of the .NET ecosystem is tightly tied to DateTime and the ISO calendar. But the real world is bigger and messier — and your tools should be too.
Introducing Quantum.Tempo
https://github.com/Quantum-Space-Org/Tempo
A Modern .NET Date/Time Library for Real-World Calendars and Human-Friendly Time
Quantum.Tempo is a .NET date/time framework focused on simple, string-based, calendar-agnostic manipulation of dates, times, intervals, and durations.
It supports multiple calendar systems (Gregorian, Persian/Shamsi, Hijri/Arabic, and custom) and is designed for robust, human-friendly, and ISO-compliant operations, without the usual headaches.
Key Features at a Glance
- String-based API : All operations use and return plain strings (“2024–05–01”)
- Calendar-agnostic : Supports Gregorian, Persian (Shamsi), Hijri (Arabic), and pluggable custom calendars
- Navigation and interval algebra : Easy next/previous logic, unions, intersections, and gaps
- Duration arithmetic : Parse, add, subtract ISO-8601 durations like P3D, PT1H30M
- Localization: Built-in English, Farsi, and Arabic output
- Fuzzy date parsing: Understands “next Friday”, “tomorrow”, “today” and more
- Business Day logic: Skip weekends and holidays, support custom business rules
- Recurrence rules: (RRULE), Generate repeat schedules with RFC 5545 rules
- Pluggable calendar providers: Inject your own fiscal or religious calendar logic
- CLI playground + REPL: Try everything interactively from the command line
Real-World Examples Solved with Quantum.Tempo
Parse and Normalize Dates Across Calendars
Parse and Normalize Dates Across Calendars
"1402/02/01".AutoNormalizeToIsoDateString();
// → "2023–04–21"
"2024–05–01".ToPersianString();
// → "1403–02–12"
"01/01/1445".ToGregorianString();
// → "2023–07–19"
Navigate Dates and Periods
"2024–05–01".NextDate(); // "2024–05–02"
"2024–05–01".NextWeek(); // "2024–05–08"
"2024–05–01".PreviousMonth(); // "2024–04–01"
Duration Parsing and Arithmetic
"2024–05–01".AddDuration("P3D"); // → "2024–05–04"
"2024–05–01".SubtractDuration("P1M"); // → "2024–04–01"
Interval Algebra
Interval.Union("2024–01–01/2024–01–10", "2024–01–05/2024–01–15");
// → "2024–01–01/2024–01–15"
Interval.Intersection("2024–01–01/2024–01–10", "2024–01–05/2024–01–15");
// → "2024–01–05/2024–01–10"
Recurrence Rules (RRULE)
StringExtensions.ParseRRule(
"FREQ=WEEKLY;BYDAY=MO,WE,FR;COUNT=4",
"2024–05–01"
);
// → ["2024–05–01", "2024–05–03", "2024–05–06", "2024–05–08"]
Custom Calendars (e.g. Fiscal Year)
CalendarProviderRegistry.Register(new SampleFiscalCalendarProvider());
"2024–04".ToFiscalQuarter(); // → "Q1-FY2025"
Business Day Calculations
"2024–05–01".IsBusinessDay(); // → true
"2024–05–04".NextBusinessDay(); // → "2024–05–06"
"2024–05–01".AddBusinessDays(5); // → "2024–05–08"
Try It Interactively with REPL
Quantum.Tempo includes a command-line REPL so you can try everything hands-on:
dotnet run - project src/Tempo.Repl
Type help inside the REPL to explore available commands.
What Makes It Different?
. String-first: You can parse, format, add, subtract, compare, all using string input and output. No need to convert to DateTime unless you want to.
. Calendar-aware: ISO, Persian, and Hijri support are built in. You can plug in custom calendars too.
. Interval/duration algebra: Normalize, union, intersect, split, all using standard string formats.
. RRULE support: Generate recurring events using RFC 5545 rules (used by iCalendar, Google Calendar, etc.).
. Business logic built in: Check if a date is a business day, jump to the next one, or define your own holiday set.
. Fuzzy input: Parse natural language like “today” or “next Friday.”
. Localization: Format results in English, Farsi, or Arabic.
. CLI and REPL: Run everything from the terminal. Great for testing, learning, and scripting.
. Extensible: Add your own calendars, business rules, or localization options.
Try It Out
Install from NuGet:
dotnet add package Quantum.Tempo
Run the REPL:
dotnet run - project src/Tempo.Repl
Type helps to explore commands and try features interactively.
Give it a try, and if you’ve got ideas, issues, or requests, I’d love your feedback.
Final Thought
If you’ve ever found yourself saying:
“This should be simple, why is it so complicated?”
…then Quantum.Tempo was built for you.
Real-world time is messy. This library embraces that and gives you the tools to make it manageable, whether you’re building a banking app, HR system, scheduling engine, or just need to parse “next Monday” correctly in three languages.
Give it a try, and tell us what’s missing. We’re building it with you.
Leave a Reply