easy_date_time 0.10.0
easy_date_time: ^0.10.0 copied to clipboard
A drop-in DateTime replacement with IANA timezone support. Preserves original time values when parsing.
easy_date_time #
A drop-in DateTime replacement with IANA timezone support. Preserves original time values when parsing.
// DateTime converts to UTC, changing the hour
DateTime.parse('2026-01-18T10:30:00+08:00').hour // 2
// EasyDateTime keeps the original hour
EasyDateTime.parse('2026-01-18T10:30:00+08:00').hour // 10
Install #
Dependency #
Add to your pubspec.yaml:
dependencies:
easy_date_time: ^0.10.0
Initialization #
Initialize the timezone database before use:
void main() {
EasyDateTime.initializeTimeZone();
runApp(MyApp());
}
Usage #
Create and parse datetime with timezone:
final now = EasyDateTime.now(location: TimeZones.tokyo);
final parsed = EasyDateTime.parse('2026-01-18T10:30:00+08:00');
print(parsed.hour); // 10
print(parsed.locationName); // Asia/Shanghai
Use Duration extensions for arithmetic:
final tomorrow = now + 1.days;
final later = now + 2.hours + 30.minutes;
Format with pattern strings:
// 2026-01-18 10:30
print(dt.format('yyyy-MM-dd HH:mm'));
Features #
Timezones #
Three ways to specify timezone:
// 1. TimeZones constants
final tokyo = EasyDateTime.now(location: TimeZones.tokyo);
// 2. IANA timezone names
final nairobi = EasyDateTime.now(location: getLocation('Africa/Nairobi'));
// 3. Global default
EasyDateTime.setDefaultLocation(TimeZones.shanghai);
final now = EasyDateTime.now(); // uses Asia/Shanghai
Convert between timezones:
final newYork = tokyo.inLocation(TimeZones.newYork);
tokyo.isAtSameMomentAs(newYork); // true — same instant
Arithmetic #
Duration extensions provide natural syntax:
now + 1.days
now - 2.hours
now + 30.minutes + 15.seconds
Calendar arithmetic preserves wall time during DST changes:
// DST transition day in New York (March 9, 2025)
final dt = EasyDateTime(2025, 3, 9, 0, 0, location: newYork);
dt.addCalendarDays(1); // 2025-03-10 00:00 — same wall time
dt.add(Duration(days: 1)); // 2025-03-10 01:00 — 24 hours later
Related getters:
dt.tomorrow // next calendar day
dt.yesterday // previous calendar day
dt.dateOnly // time set to 00:00:00
Safe month overflow handling:
final jan31 = EasyDateTime.utc(2025, 1, 31);
jan31.copyWith(month: 2); // Mar 3 (overflow)
jan31.copyWithClamped(month: 2); // Feb 28 (clamped to valid day)
Get boundaries of time units:
dt.startOf(DateTimeUnit.day); // 00:00:00
dt.startOf(DateTimeUnit.week); // Monday 00:00:00 (ISO 8601)
dt.startOf(DateTimeUnit.month); // 1st 00:00:00
dt.endOf(DateTimeUnit.month); // last day 23:59:59.999999
Properties #
Date calculations:
dayOfYear— day number within year (1-366)weekOfYear— ISO 8601 week number (1-53)quarter— quarter of year (1-4)daysInMonth— days in current month (28-31)isLeapYear— whether year is a leap year
Day checks:
isToday,isTomorrow,isYesterdayisThisWeek,isThisMonth,isThisYearisWeekend,isWeekdayisPast,isFuture
Timezone:
isDst— whether daylight saving time is activelocationName— IANA timezone name
Formatting #
Use format() with pattern strings:
dt.format('yyyy-MM-dd'); // 2026-01-18
dt.format('HH:mm:ss'); // 14:30:45
dt.format('hh:mm a'); // 02:30 PM
Predefined format constants:
dt.format(DateTimeFormats.isoDate); // 2026-01-18
dt.format(DateTimeFormats.isoDateTime); // 2026-01-18T14:30:45
dt.format(DateTimeFormats.rfc2822); // Sun, 18 Jan 2026 14:30:45 +0800
For performance in loops, pre-compile the pattern:
static final formatter = EasyDateTimeFormatter('yyyy-MM-dd HH:mm');
formatter.format(dt);
Pattern tokens:
| Token | Description | Example |
|---|---|---|
yyyy |
4-digit year | 2025 |
MM / M |
Month | 01 / 1 |
dd / d |
Day | 07 / 7 |
HH / H |
Hour (24h) | 09 / 9 |
hh / h |
Hour (12h) | 02 / 2 |
mm / m |
Minute | 05 / 5 |
ss / s |
Second | 05 / 5 |
SSS |
Millisecond | 123 |
a |
AM / PM | AM / PM |
EEE |
Day of week | Mon |
MMM |
Month name | Dec |
xxxxx |
Offset | +08:00 |
X |
ISO Offset | Z / +0800 |
intl #
EasyDateTime implements DateTime and works directly with the intl package:
import 'package:intl/intl.dart';
DateFormat.yMMMMd('ja').format(dt); // 2025年12月7日
DateFormat.yMMMMd('en').format(dt); // December 7, 2025
JSON #
Use a custom converter with json_serializable or freezed:
class EasyDateTimeConverter implements JsonConverter<EasyDateTime, String> {
const EasyDateTimeConverter();
@override
EasyDateTime fromJson(String json) => EasyDateTime.fromIso8601String(json);
@override
String toJson(EasyDateTime object) => object.toIso8601String();
}
With freezed:
@freezed
class Event with _$Event {
const factory Event({
@EasyDateTimeConverter() required EasyDateTime startTime,
}) = _Event;
factory Event.fromJson(Map<String, dynamic> json) => _$EventFromJson(json);
}
Notes #
Equality follows Dart's DateTime semantics:
final utc = EasyDateTime.utc(2025, 1, 1, 0, 0);
final local = EasyDateTime.parse('2026-01-18T08:00:00+08:00');
utc == local; // false — different timezone type
utc.isAtSameMomentAs(local); // true — same instant
Avoid mixing EasyDateTime and DateTime in the same Set or Map. They have different hashCode implementations.
Invalid dates automatically roll over:
EasyDateTime(2025, 2, 30); // 2025-03-02
Safe parsing for user input:
final dt = EasyDateTime.tryParse(userInput);
if (dt == null) {
// invalid format
}
Extension conflicts — if 1.days conflicts with another package:
import 'package:easy_date_time/easy_date_time.dart' hide DurationExtension;
Contributing #
See CONTRIBUTING.md.
License #
BSD 2-Clause