Make every microsecond count.
Stop wrestling with DateTime
and Duration
. time_plus
gives you the tools you wish Dart had built inโadd time units, break durations down, convert across scales, and do it all with a clear, predictable API. No dependencies. Just useful extensions that make working with time easier.
Table of Contents
๐
DateTime
- add โ Add time units to
DateTime
from milliseconds to centuries with.addX()
or.addX
getters. - subtract โ Subtract time units from
DateTime
using intuitive, calendar-aware methods. - isSame โ Compare two dates by year, month, day, hour, to microseconds using
isSameX()
. - startOf / endOf โ Get start or end of time units: minute, hour, day, week, month, year.
- next โ Find the next matching
DateTime
by weekday or time of day. - leap โ Check if
DateTime
is in a leap year, leap month, or on leap day (Feb 29). - daysInMonth / daysInYear โ Get days in current month/year, with leap year handling.
- yesterday / tomorrow โ Get yesterday or tomorrow with
.yesterday
or.tomorrow
getters.
โฑ๏ธ Duration
- add โ Chain any time unit, from microseconds to centuries, with
.addX()
or.addX
getters. - in โ Convert durations into whole units like
inWeeks
,inYears
, orinCenturies
. - as โ Convert durations to fractional units like
asDays
,asWeeks
, orasCenturies
. - only โ Extract the remainder after subtracting larger units (e.g.
onlyMinutes
,onlySeconds
). - without โ Strip full units to isolate what's left (e.g. time since midnight).
- int ->
Duration
โ Create Duration usingint
with1.days
,2.hours
,3.minutes
, etc. - double ->
Duration
โ1.5.hours
,2.25.minutes
,0.5.days
, etc. (with precise decomposition) - Factories โ Create durations from any unit or use built-in constants like
DurationFrom.year
.
Why Use time_plus
?
โ
Zero dependencies โ Pure Dart. No setup or third-party overhead.
โ
Lightweight & fast โ Minimal footprint with efficient, production-safe code.
โ
Comprehensive time tools โ Add, compare, normalize, and decompose dates and durations with ease.
โ
Reliable and robust โ Built for real-world use, with 128 extensions and 717 tests ensuring stability.
โ
A better alternative to the time
package โ Passes tests the time
package fails, performs faster, and avoids questionable design choices like hard dependencies on clock
and more, does not have "clock" features (keeps separation of concerns).
- Ideal for:
- ๐ Calendar logic โ Scheduling, planning, date math, and recurring events
- ๐งฎ Data handling โ Grouping, filtering, and comparing
DateTime
objects with precision - โฑ๏ธ UI & analytics โ Formatting durations, tracking activity, and displaying time intuitively
time_plus
closes the gaps in Dart's native DateTime
and Duration
APIs โ making your code easier to write, easier to read, and easier to trust.
โ add
โ Add Time to a DateTime
Extend DateTime
just like you wish it worked. These extensions let you safely add milliseconds, hours, days, months, and even centuries โ with proper handling for leap years and end-of-month overflows.
addMilliseconds(int)
/addMillisecond
addSeconds(int)
/addSecond
addMinutes(int)
/addMinute
addHours(int)
/addHour
addDays(int)
/addDay
โ Preserves exact time of day (all following methods do)addWeeks(int)
/addWeek
addMonths(int)
/addMonth
addYears(int)
/addYear
addDecades(int)
/addDecade
(10-year spans)addCenturies(int)
/addCentury
(100-year spans)
All methods return a new DateTime
instance. Month and year-based methods clamp invalid dates (e.g. Feb 30 โ Feb 28/29), ensuring always-valid results.
๐งช Example
final now = DateTime(2024, 2, 29);
final nextYear = now.addYear; // โ 2025-02-28
final chained = now.addYear.addYear.addMonth; // โ 2026-03-29
final future = now.addDecades(2); // โ 2044-02-29
final long = now.addCenturies(1); // โ 2124-02-29
Important: The
addDays
andaddWeeks
and the bigger time units methods preserve the exact time of day and are calendar-aware, making them safe for daylight saving time transitions. They are not equivalent to adding hours.
โคด๏ธ Back -> Table of Contents
โ subtract
โ Subtract Time from a DateTime
Safely subtract time from any DateTime
using intuitive, calendar-aware methods. These extensions go beyond raw durations to handle months, years, decades, and centuries โ correctly accounting for leap years, daylight saving, and invalid dates like Feb 30.
subtractMilliseconds(int)
/subtractMillisecond
subtractSeconds(int)
/subtractSecond
subtractMinutes(int)
/subtractMinute
subtractHours(int)
/subtractHour
subtractDays(int)
/subtractDay
โ Preserves exact time of day (all following methods do)subtractWeeks(int)
/subtractWeek
subtractMonths(int)
/subtractMonth
subtractYears(int)
/subtractYear
subtractDecades(int)
/subtractDecade
(10-year spans)subtractCenturies(int)
/subtractCentury
(100-year spans)
All methods return a new DateTime
instance. Month and year-based methods clamp invalid dates (e.g. March 31 โ February 28/29), ensuring always-valid results.
๐งช Example
final now = DateTime(2024, 2, 29);
final lastYear = now.subtractYear; // โ 2023-02-28
final chained = now.subtractYear.subtractMonth; // โ 2022-01-28
final past = now.subtractDecades(2); // โ 2004-02-29
final wayBack = now.subtractCenturies(1); // โ 1924-02-29
Important: The
subtractDays
andsubtractWeeks
and the bigger time units methods preserve the exact time of day and are calendar-aware, making them safe for daylight saving time transitions. They are not equivalent to subtracting hours.
โคด๏ธ Back -> Table of Contents
๐งฉ isSame
โ Compare Temporal Precision
Quickly compare two DateTime
instances with precision โ from year-level down to microseconds. Each method checks only the relevant granularity, making it ideal for scheduling, display logic, or grouping events.
isSameMicrosecond(DateTime)
isSameMillisecond(DateTime)
isSameSecond(DateTime)
isSameMinute(DateTime)
isSameHour(DateTime)
isSameDay(DateTime)
isSameMonth(DateTime)
isSameYear(DateTime)
isSameDecade(DateTime)
(10-year spans)isSameCentury(DateTime)
(100-year spans)
Each method returns true
if the current DateTime
matches the given one at that specific resolution.
๐งช Example
final a = DateTime(2024, 4, 20, 10, 15);
final b = DateTime(2024, 4, 20, 10, 45);
a.isSameDay(b); // โ true
a.isSameHour(b); // โ true
a.isSameMinute(b); // โ false
โคด๏ธ Back -> Table of Contents
๐งฑ startOf
/ endOf
โ DateTime Boundaries
Get the exact start or end of any time unit โ minute, hour, day, week, month, or year. These helpers return a new DateTime
aligned to the boundary, ideal for filtering, grouping, or time range logic.
startOfMillisecond
/endOfMillisecond
startOfSecond
/endOfSecond
startOfMinute
/endOfMinute
startOfHour
/endOfHour
startOfDay
/endOfDay
startOfWeek
/endOfWeek
(Monday โ Sunday)startOfMonth
/endOfMonth
startOfYear
/endOfYear
startOfDecade
/endOfDecade
(10-year spans)startOfCentury
/endOfCentury
(100-year spans)
Each result is a fresh DateTime
at the zero point of the boundary (or start of the next one, for endOf...
).
๐งช Example
final now = DateTime(2024, 4, 20, 15, 45, 12);
now.startOfDay; // โ 2024-04-20 00:00:00
now.endOfDay; // โ 2024-04-21 00:00:00
now.startOfWeek; // โ 2024-04-15 00:00:00 (Monday)
now.endOfMonth; // โ 2024-05-01 00:00:00
These methods respect the original timezone (local
or UTC
).
โคด๏ธ Back -> Table of Contents
โญ๏ธ next
โ Find the Next Matching DateTime
Easily find the next time that matches a specific weekday or time of day โ skipping the current moment even if it matches. Useful for scheduling recurring events, alarms, or reminders.
nextWeekdayTime(weekday, ...)
โ Returns the next occurrence of a specific weekday (1โ7, MondayโSunday), with optional time.nextTimeOfDay(hour, ...)
โ Returns the next time that matches the given time of day (tomorrow if already passed today).
These respect the original timezone (UTC/local) and guarantee forward-only results.
๐งช Example
final now = DateTime(2024, 4, 20, 15); // Saturday
now.nextWeekdayTime(1, hour: 9); // โ Monday 09:00
now.nextTimeOfDay(hour: 8); // โ Tomorrow 08:00
โคด๏ธ Back -> Table of Contents
๐ธ leap
โ Leap Year, Month, and Day Detection
Easily check if a DateTime
falls in a leap year, on a leap month (February in a leap year), or on the rarest of all โ leap day itself (Feb 29).
isLeapYear
โtrue
if the year has 366 daysisLeapMonth
โtrue
if it's February in a leap yearisLeapDay
โtrue
if it's exactly February 29
๐งช Example
final date = DateTime(2024, 2, 29);
final dateNotDay = DateTime(2024, 2, 28);
date.isLeapYear; // โ true
date.isLeapMonth; // โ true
date.isLeapDay; // โ true
dateNotDay.isLeapDay; // โ false
โคด๏ธ Back -> Table of Contents
๐
daysInMonth
/ daysInYear
โ Calendar-Aware Date Info
Get the correct number of days in the current month or year, with full leap year handling built in. Ideal for calendar UIs, range generators, or custom date calculations.
daysInMonth
โ Returns 28โ31 based on month and leap yeardaysInYear
โ Returns 365 or 366 based on the current year
๐งช Example
DateTime(2024, 2, 10).daysInMonth; // โ 29 (leap year)
DateTime(2023, 2, 10).daysInMonth; // โ 28
DateTime(2024, 1, 1).daysInYear; // โ 366
DateTime(2023, 1, 1).daysInYear; // โ 365
โคด๏ธ Back -> Table of Contents
๐
yesterday
/ tomorrow
โ Relative Day Helpers
Convenient shortcuts to get yesterday
, tomorrow
, and their weekday numbers โ always aligned to the start of the day.
yesterday
โ Start of the previous daytomorrow
โ Start of the next daypreviousWeekday
โ Weekday number of yesterday (1 = Monday
,7 = Sunday
)nextWeekday
โ Weekday number of tomorrow
Perfect for logic around schedules, shifts, events, or time-based UI highlights.
๐งช Example
final now = DateTime(2024, 4, 20, 13, 45); // Saturday
now.yesterday; // โ 2024-04-19 00:00:00
now.tomorrow; // โ 2024-04-21 00:00:00
now.previousWeekday; // โ 5 (Friday)
now.nextWeekday; // โ 7 (Sunday)
All results respect the original time zone (local
or UTC
).
โคด๏ธ Back -> Table of Contents
โ add
โ Add Time Units to a Duration
Easily extend a Duration
by any time unit โ from microseconds to centuries โ using intuitive, chainable methods. Supports both numeric arguments and single-unit getters for clear, readable code.
addMicroseconds(int)
/addMicrosecond
addMilliseconds(int)
/addMillisecond
addSeconds(int)
/addSecond
addMinutes(int)
/addMinute
addHours(int)
/addHour
addDays(int)
/addDay
addWeeks(int)
/addWeek
(7-day spans)addMonths(int)
/addMonth
(โ30.436875 days)addYears(int)
/addYear
(โ365.2425 days)addDecades(int)
/addDecade
(โ3652.425 days)addCenturies(int)
/addCentury
(โ36,524.25 days)
All methods return a new Duration
without modifying the original instance.
๐งช Example
final duration = Duration(hours: 1);
final extended = duration.addMinutes(30); // โ 1h 30m
final chained = duration.addDay.addHour; // โ 1d 2h
final future = duration.addDecades(1); // โ ~3652.4d + 1h
โ ๏ธ Note on accuracy: The
addMonths
,addYears
,addDecades
, andaddCenturies
methods onDuration
now use long-term Gregorian averages (e.g., 30.436875 days/month, 365.2425 days/year) based on a 400-year cycle. These are more precise than previous fixed approximations, but still not suitable for exact date calculations.โ For calendar-accurate operations (e.g., leap years, end-of-month logic), use the equivalent methods on
DateTime
instead.
โคด๏ธ Back -> Table of Contents
๐งฎ in
โ Convert Duration to Whole Units
Convert a Duration
into whole, integer-based time units โ perfect for calculations, comparisons, or formatting where only full units matter. These getters are safe, clear, and based on long-term Gregorian averages.
inWeeks
โ Full 7-day weeksinMonths
โ Full months (โ30.436875 days)inYears
โ Full years (โ365.2425 days)inDecades
โ Full decades (โ3652.425 days)inCenturies
โ Full centuries (โ36,524.25 days)
All values are calculated using integer division and return only whole units.
final d = Duration(days: 750);
d.inYears; // โ 2
d.inMonths; // โ 24
โ ๏ธ Note on precision: These unit conversions are based on mean durations over 400 years in the Gregorian calendar. While significantly more accurate than fixed approximations (like "30 days per month"), they still do not match exact calendar units.
โ Use
DateTime
methods for exact date math, including leap years and end-of-month boundaries.
โคด๏ธ Back -> Table of Contents
โ as
โ Convert Duration to Fractional Units
Convert a Duration
to floating-point values โ including fractions โ in any time unit, from milliseconds to centuries. Unlike inX
, which gives only whole units, asX
provides precise decimal results.
asMilliseconds
,asSeconds
,asMinutes
,asHours
,asDays
asWeeks
,asMonths
,asYears
,asDecades
,asCenturies
All values are double
and include partial units (e.g., 1.5 days
, 2.75 hours
).
๐งช Example
final duration = Duration(hours: 36);
duration.asDays; // โ 1.5
duration.asWeeks; // โ ~0.214
duration.asYears; // โ ~0.0041
โ ๏ธ Note on precision: The months/years/decades/centuries conversions are based on mean durations over 400 years in the Gregorian calendar. While significantly more accurate than fixed approximations (like "30 days per month"), they still do not match exact calendar units.
โ Use
DateTime
methods for exact date math, including leap years and end-of-month boundaries.
โคด๏ธ Back -> Table of Contents
๐งฉ only
โ Break Down Duration by Remaining Units
Decompose a Duration
into its leftover parts, excluding higher units. Ideal for time formatting (e.g. 1h 23m 45s
) or visual breakdowns.
onlyMicroseconds
โ Microseconds (excluding full milliseconds)onlyMilliseconds
โ Milliseconds (excluding full seconds)onlySeconds
โ Seconds (excluding full minutes)onlyMinutes
โ Minutes (excluding full hours)onlyHours
โ Hours (excluding full days)onlyDays
โ Total full days
These getters let you reconstruct any Duration
piece by piece.
final duration = Duration(days: 1, hours: 2, minutes: 45, seconds: 30);
final days = duration.onlyDays;
final hours = duration.onlyHours;
final minutes = duration.onlyMinutes;
final seconds = duration.onlySeconds;
print('$days days, $hours hours, $minutes minutes, $seconds seconds');
// โ 1 days, 2 hours, 45 minutes, 30 seconds
โคด๏ธ Back -> Table of Contents
๐งผ without
โ Remove Full Units from a Duration
Strip away full units from a Duration
, leaving only the remainder. Useful when you want the leftover time within a day, hour, minute, or second โ like isolating time of day or breaking durations into parts.
withoutDays
โ Removes full days, keeps hours/minutes/etc.withoutHours
โ Removes full hours, keeps minutes/seconds/etc.withoutMinutes
โ Removes full minutes, keeps seconds/milliseconds/etc.withoutSeconds
โ Removes full seconds, keeps milliseconds/microsecondswithoutMilliseconds
โ Removes full milliseconds, keeps microseconds
Each method returns a new Duration
with the higher units removed.
๐งช Example
final d = Duration(hours: 2, minutes: 45, seconds: 30);
final remainder = d.withoutHours; // โ 0:45:30.000000
โคด๏ธ Back -> Table of Contents
๐ข int
โ Duration
โ Natural Time Expressions
Make your time math more expressive. These extensions let you turn any int
into a Duration
โ from milliseconds to centuries โ using natural, readable syntax.
1.milliseconds
,1.seconds
,1.minutes
,1.hours
,1.days
2.weeks
,3.months
,5.years
,10.decades
,1.centuries
This makes time-based calculations cleaner and easier to read โ no more Duration(seconds: 5)
boilerplate.
๐งช Example
final delay = 3.seconds + 500.milliseconds;
final timeout = 2.hours + 30.minutes;
final historical = 2.centuries - 1.decade;
final oneYear = 1.days + 2.hours + 30.minutes + 15.seconds;
โ ๏ธ Note on accuracy: The months/years/decades/centuries are based on long-term Gregorian averages derived from a 400-year calendar cycle. They are excellent for simulations, scheduling, and time estimation โ but do not reflect the exact number of days in individual months or years.
โ For exact date handling (leap years, month lengths, DST shifts), use
DateTime
instead.
โคด๏ธ Back -> Table of Contents
๐ฌ double
โ Duration
โ Fractional Time Made Precise
Convert decimal values into smart, decomposed Duration
objects. Supports precise handling of fractions โ like 1.5 hours or 2.75 months โ with full breakdown into microseconds.
1.5.seconds
,2.25.minutes
,0.5.hours
1.5.days
,2.75.weeks
,0.33.months
0.1.years
,1.25.decades
,2.5.centuries
Internally decomposed into full Duration
fields: days, hours, minutes, etc., for consistent and readable output โ even across large or fractional units.
๐งช Example
final nap = 1.5.hours; // โ 1h 30m 0s
final quarter = 0.25.years; // โ ~91 days
final longView = 2.5.centuries; // โ 91250 days
โ ๏ธ Note on accuracy: The months/years/decades/centuries are based on long-term Gregorian averages derived from a 400-year calendar cycle. They are excellent for simulations, scheduling, and time estimation โ but do not reflect the exact number of days in individual months or years.
โ For exact date handling (leap years, month lengths, DST shifts), use
DateTime
instead.
โคด๏ธ Back -> Table of Contents
๐๏ธ factories
โ Create Durations from Any Unit
This is the core of all Duration
creation in the package โ powering everything from int
and double
extensions to add
methods and smart conversions.
A unified way to construct Duration
instances from any time unit โ including long spans like months, years, decades, and centuries. Provides both numeric constructors and ready-to-use constants.
microseconds(int)
,milliseconds(int)
,seconds(int)
minutes(int)
,hours(int)
,days(int)
weeks(int)
,months(int)
,years(int)
decades(int)
,centuries(int)
- Predefined constants:
microsecond
,millisecond
,second
,minute
,hour
,day
,week
,month
,year
,decade
,century
These follow long-term Gregorian calendar averages:
- 1 week = 7 days
- 1 month โ 30.436875 days
- 1 year โ 365.2425 days
- 1 decade โ 3,652.425 days
- 1 century โ 36,524.25 days
๐งช Example
final workout = DurationFrom.minutes(45);
final breakTime = DurationFrom.week; // constant: 7 days
final future = workout + DurationFrom.years(2); // โ 730.485 days
โ ๏ธ Note on accuracy: All factory methods use averaged Gregorian values derived from a 400-year calendar cycle. These are excellent for simulations, scheduling, and time estimation โ but do not reflect the exact number of days in individual months or years.
โ For exact date handling (leap years, month lengths, DST shifts), use
DateTime
instead.
โคด๏ธ Back -> Table of Contents
time
vs time_plus
The Dart time
package provides a handful of DateTime
and Duration
extensions, but it's tightly coupled to the clock
package and lacks precision, modularity, and extensibility.
By contrast, time_plus
was built from real-world project needs. It keeps clock logic out of core date/time operations, performs better, passes more edge-case tests, and offers 8x more functionality with no extra dependencies.
In short:
time_plus
is a modern, accurate, and robust alternative โ not a fork, but a clean rethinking of what Dartโs time handling should be.
Feature/Aspect | time |
time_plus |
---|---|---|
Dependencies | โ Requires clock package โ introduces tight coupling |
โ Zero dependencies โ modular and self-contained |
Separation of Concerns | โ Blends clock management with date/time logic | โ Clean boundaries โ clock logic handled externally |
Extension Coverage | โ ~15 basic extensions | โ 128 extensions โ composable, precise, and field-tested |
DateTime Utilities | โ Limited API: isSameXAs , copyWith , shift |
โ Extensive support: unit math, boundaries, recurrence |
Duration Utilities | โ Only provides unit constructors (2.hours ), with known test issues |
โ
Full suite: in , as , only , without , factories |
Precision & Accuracy | โ Integer-based math; known inconsistencies in edge cases | โ High-precision constants; 717 verified unit tests |
โคด๏ธ Back -> Table of Contents
Why Not Just Improve time
?
The time
package provides a minimal set of extensions on Duration
and DateTime
, but it falls short of the flexibility, performance, and precision needed for real-world applications. Rather than attempting to patch a narrowly scoped and structurally limited library, we built time_plus
from the ground up with clear priorities: accuracy, extensibility, modularity, and production safety.
A Different Goal
time_plus
didnโt begin as a replacement for time
. It started with a completely separate purpose โ to add modular, testable, and precise extensions to Duration
and DateTime
, with a clear boundary between calendar logic and runtime clocks.
Later, once the package matured and handled large-scale duration and date logic cleanly, it expanded to support int
/double
extensions as well โ but with strict attention to precision, performance, and decomposition logic.
In contrast, time
was always focused on quick syntax enhancements, like:
final future = 10.minutes.fromNow;
final delay = 2.5.hours.delay;
Which are helpful โ but shallow in scope and tied to global clock behavior.
Limited Scope, By Design
-
time_plus
introduces over 120 extensions, covering:- full time arithmetic across centuries
- granular comparisons (e.g.,
isSameMinute
,isSameDay
) startOf
,endOf
,next
,yesterday
,tomorrow
- complete
Duration
breakdowns (only
,without
) - support for
int
anddouble
โDuration
, factories, and more.
Smarter Memory Usage
In time
, common getters like daysInMonth
create a new list every time they are called โ even though the values are static and immutable. This results in unnecessary allocations that can impact both performance and garbage collection in high-frequency code paths.
// time (creates a new list on every access)
final days = [
31, // January
if (isLeapYear) 29 else 28,
...
];
In contrast, time_plus
uses compile-time constant lists:
// time_plus (zero allocation)
const commonYearDays = [...];
const leapYearDays = [...];
This approach is not only more efficient โ especially in tight loops or calendar-heavy logic โ but also avoids subtle bugs from mutable runtime-created data. Itโs a small optimization with real-world impact at scale.
Additionally, time_plus
applies the same zero-allocation mindset across Duration
math, leap year checks, and unit decompositions โ ensuring every operation remains performant, consistent, and GC-friendly.
Clock Coupling in time
A core architectural limitation of the time
package is its implicit dependency on the clock
package, which introduces hidden state into APIs that should remain deterministic and side-effect-free.
Implicit State in Common Operations
The time
package injects runtime logic directly into extension getters such as:
final future = 5.minutes.fromNow;
final past = 2.hours.ago;
final isToday = someDate.isToday;
Although these appear to be lightweight utilities, they internally call clock.now()
, meaning:
- The result is time-sensitive and non-deterministic
- Behavior depends on a global singleton
- Testing becomes brittle without additional mocking infrastructure
This design choice tightly couples business logic with environmental state, reducing testability, predictability, and modularity โ especially in larger codebases.
Precision Matters
One of the most critical shortcomings in the time
package is its reliance on simple multiplication when converting numbers into Duration
objects:
Duration get days => milliseconds * Duration.millisecondsPerDay;
This approach treats 2.5.days
the same as 2.5 * 86_400_000
, which leads to accumulated rounding errors and loss of microsecond-level precision. Worse, this same calculation is applied identically to both int
and double
types โ even though they should be handled differently.
In contrast, time_plus
:
-
Uses the native
Duration
constructor for allint
-based units (e.g.3.days
โDuration(days: 3)
), avoiding unnecessary conversions. -
For fractional values (
double
), it performs smart decomposition:- Breaks
2.5.days
intoDuration(days: 2, hours: 12)
- Maintains sub-millisecond precision by working directly with microseconds
- Breaks
-
Applies this decomposition for all scales โ from microseconds to centuries โ preserving accuracy and performance across the board.
The result is predictable, consistent, and verifiable time math โ even in complex or high-frequency environments. With time_plus
, you're not just getting shorthand syntax โ you're getting a precision-engineered time system built for production.
Leap Year Logic
In production code, we favor mathematical consistency unless business logic explicitly dictates otherwise. The time
package's implementation of isLeapYear
includes a hardcoded domain check โ restricting results to year >= 1582
.
// From `time`
bool get isLeapYear =>
year >= 1582 && year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
This artificial constraint introduces ambiguity and silently fails for valid dates before the Gregorian reform โ which may be entirely acceptable in many systems (e.g. calendar tools, academic or historical models).
By contrast, time_plus
implements pure Gregorian leap year logic, applicable to any DateTime
instance, and extends functionality with precise checks for isLeapMonth
and isLeapDay
.
// From `time_plus`
bool get isLeapYear =>
year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
This makes the behavior deterministic, testable, and consistent โ critical traits in time logic. No hidden assumptions. No unnecessary domain rules. Just predictable, correct results.
Additionally, time_plus
introduces:
isLeapMonth
โ true only for February in leap yearsisLeapDay
โ true only for February 29th in leap years
This level of expressiveness is missing entirely in time
, making time_plus
a more complete and accurate solution for calendar-based logic.
Certainly. Here's a concise, professional explanation you can include in your README or documentation:
In Dart, all
DateTime
values follow the proleptic Gregorian calendar, meaning the Gregorian leap year rules are applied consistently across all years, even those before 1582.
This ensures predictable and mathematically correct behavior, regardless of historical transitions. Most applications donโt model historical calendars โ they just need consistent and reliable time math.
By avoiding arbitrary cutoffs like year >= 1582
, time_plus
aligns with Dartโs native behavior and supports a broader range of valid use cases without introducing unnecessary constraints.
Test Failures and Fragile Behavior
Many of time
โs numeric and duration operations fail precision-based tests, particularly for fractional durations and boundary cases. Its logic isnโt designed for edge-case correctness or production-scale stability.
time_plus
is built with:
- 717 tests covering edge cases, conversions, rounding, and regressions.
- Extensive real-world validation in multiple production apps.
- Clean architecture that ensures correctness by design.
โคด๏ธ Back -> Table of Contents
๐ License MIT ยฉ Jozz
Libraries
- time_plus
- A lightweight extension library for working with time in Dart.