Jalali date arithmetic, relative time and ranges
Add days, months and years to Jalali dates in Dart, count whole months and years, write relative time such as ۳ روز پیش, and work with date ranges.
Date arithmetic
final date = PersianDate(1403, 6, 31);
print(date.addDays(1)); // 1403/07/01
print(date.addMonths(1)); // 1403/07/30, the day is clamped
print(PersianDate(1403, 12, 30).addYears(1)); // 1404/12/29
print(PersianDate(1404, 1, 1).differenceInDays(PersianDate(1403, 1, 1))); // 366
print(PersianDate(1405, 8, 5).differenceInMonths(PersianDate(1405, 2, 20))); // 5
print(PersianDate(1400, 12, 29).differenceInYears(PersianDate(1370, 12, 30))); // 30addMonths and addYears clamp the day to the length of the target month.
This differs from DateTime, which rolls over into the next month.
Results are date-only and throw ArgumentError outside the supported range.
differenceInMonths and differenceInYears count whole months and years the same way, so date.addMonths(n).differenceInMonths(date) is always n.
Someone born on 1370/12/30 is 30 on 1400/12/29, the last day of a year without 30 Esfand.
Temporal's persian calendar counts that as 29 years, 11 months, and 29 days, because the day of the month is still smaller.
Relative time
final today = PersianDate(1405, 8, 5);
print(PersianDate(1405, 8, 4).relativeTo(today)); // دیروز
print(PersianDate(1405, 8, 2).relativeTo(today)); // 3 روز پیش
print(PersianDate(1405, 9, 5).relativeTo(today)); // ماه آینده
print(PersianDate(1403, 8, 5).relativeTo(today, persianDigits: true)); // ۲ سال پیش
print(PersianDate(1405, 8, 4).relativeTo(today, numeric: true)); // 1 روز پیش
print(PersianDate.withTime(1405, 8, 5, 9, 30)
.relativeTo(PersianDate.withTime(1405, 8, 5, 12, 0))); // 2 ساعت پیشrelativeTo counts calendar days: days up to a week, weeks while less than a whole month has passed, then months and years counted like differenceInMonths.
When both dates have a time of day and are less than a day apart, it uses hours and minutes instead, and اکنون under a minute.
fromNow() is relativeTo(PersianDate.now()).
The words are the CLDR ones that Intl.RelativeTimeFormat('fa') uses in browsers; numeric: true always writes a number.
Ranges
final range = PersianDateRange(PersianDate(1403, 1, 1), PersianDate(1403, 1, 13));
print(range.length); // 13
print(range.contains(PersianDate(1403, 1, 4))); // true
for (final day in range.days) {
print(day.format('E d'));
}
print(PersianDate(1403, 12, 29).daysUntil(PersianDate(1404, 1, 1)).length); // 3