Flutter Date Formatter
A Dart and Flutter package for formatting dates and times in 55+ locales: patterns with ordinals, relative times ("5 minutes ago"), calendar times ("Yesterday at 3:00 PM"), humanized durations ("2 hours 5 minutes"), parsing, and many DateTime helpers.
π Docs & live playground: https://thanhhaidev.github.io/flutter_date_formatter/ β every example runs the real package in your browser.
Installation π»
Install via dart pub add (or flutter pub add in Flutter projects):
dart pub add flutter_date_formatter
Usage π
Import the package:
import 'package:flutter_date_formatter/flutter_date_formatter.dart';
Prerequisites
The package loads the bundled intl date data on first use, so no setup is required. If you also use intl's DateFormat directly, call initializeDateFormatting() from package:intl/date_symbol_data_local.dart as usual:
import 'package:intl/date_symbol_data_local.dart';
void main() async {
await initializeDateFormatting();
// Your app initialization code here
}
Configuration
Set a default locale, the first day of the week, or a clock used as "now" (handy in tests):
DateFormatterConfig.configure(
locale: 'vi',
startOfWeek: StartOfWeek.monday,
clock: () => DateTime(2025, 3, 10, 12),
);
DateTime(2025, 3, 10).isToday; // true, using the configured clock
DateFormatterConfig.reset(); // back to the defaults
Formatting Dates
You can format dates using the FlutterDateFormatter class:
DateTime now = DateTime.now();
String pattern = 'do MMMM yyyy';
String formattedDate = FlutterDateFormatter(pattern, 'en').format(now);
print(formattedDate); // Output: 13th February 2025
Formatting Relative Dates
You can format dates relative to the current time using the formatRelativeDateTime function:
DateTime now = DateTime.now();
DateTime pastDate = now.subtract(Duration(days: 5));
String formattedRelativeDate = FlutterDateFormatter.formatRelativeDateTime(
pastDate,
locale: 'en',
);
print(formattedRelativeDate); // Output: 5 days ago
Calendar Times
Format a date relative to today, like chat apps and feeds do:
final now = DateTime(2025, 3, 10, 12); // Monday
DateTime(2025, 3, 10, 15).formatCalendar(clock: now); // Today at 3:00 PM
DateTime(2025, 3, 9, 15).formatCalendar(clock: now); // Yesterday at 3:00 PM
DateTime(2025, 3, 13, 15).formatCalendar(clock: now); // Thursday at 3:00 PM
DateTime(2025, 3, 5, 15).formatCalendar(clock: now); // Last Wednesday at 3:00 PM
DateTime(2025, 2, 1).formatCalendar(clock: now); // 2/1/2025
DateTime(2025, 3, 10, 15).formatCalendar(clock: now, locale: 'vi'); // HΓ΄m nay lΓΊc 15:00
Weekdays are worded relative to the current week, using the locale's first day of the week: a day earlier this week is just "Wednesday at 3:00 PM", while one in the previous week is "Last Wednesday at 3:00 PM" (ζ¬ε¨δΈ / δΈε¨δΈ in Chinese, Π ΡΡΠ΅Π΄Ρ / Π ΠΏΡΠΎΡΠ»ΡΡ ΡΡΠ΅Π΄Ρ in Russian).
timePattern and datePattern customize the time and the fallback date format.
Humanized Durations
const duration = Duration(days: 1, hours: 2, minutes: 5);
duration.humanize(); // 1 day 2 hours
duration.humanize(maxUnits: 3); // 1 day 2 hours 5 minutes
duration.humanize(short: true, maxUnits: 3); // 1d 2h 5m
duration.humanize(largestUnit: Unit.hour); // 26 hours 5 minutes
duration.humanize(locale: 'vi'); // 1 ngΓ y 2 giα»
Parsing
parse and tryParse read strings written in the same pattern syntax as format, including do ordinals and [literal] text:
final formatter = FlutterDateFormatter('do MMMM yyyy', 'en');
formatter.parse('21st March 2025'); // DateTime(2025, 3, 21)
formatter.tryParse('not a date'); // null
FlutterDateFormatter('yyyy-MM-dd', 'en').parse('2025-02-30', strict: true); // throws FormatException
Ranges and Comparison
DateTime(2025, 3, 1).rangeTo(DateTime(2025, 3, 3)); // Mar 1, Mar 2, Mar 3
DateTime(2025, 1, 31).rangeTo(DateTime(2025, 4, 30), unit: Unit.month); // Jan 31, Feb 28, Mar 31, Apr 30
TimeSpan(start, end).iterate(unit: Unit.week); // every week of the span
date.clamp(min, max);
[a, b, c].earliest;
[a, b, c].latest;
Ordinal Numbers
You can get the ordinal representation of a number using the ordinal method in the locale classes:
int number = 1;
String ordinal = FlutterDateFormatter.ordinal(number, locale: 'en');
print(ordinal); // Output: 1st
DateTime Extensions
The package now includes several new extension methods for the DateTime class:
DateTime date = DateTime.now();
print(date.isToday); // Output: true
String pattern = 'do MMMM yyyy';
String formattedDate = date.format(pattern: pattern, locale: 'en');
print(formattedDate); // Output: 13th February 2025
DateTime pastDate = date.subtract(Duration(days: 5));
String formattedRelativeDate = pastDate.formatRelative(
locale: 'en',
);
print(formattedRelativeDate); // Output: 5 days ago
Properties
isFuture β bool
isPast β bool
isToday β bool
isYesterday β bool
isTomorrow β bool
isLocal β bool
isWeekend β bool
isLeapYear β bool
dayOfWeek β int
dayOfYear β int
daysInMonth β int
weekOfYear β int // ISO-8601 week number
quarterOfYear β int
startOfDay β DateTime
startOfWeek β DateTime
startOfMonth β DateTime
startOfYear β DateTime
startOfQuarter β DateTime
endOfDay β DateTime
endOfWeek β DateTime
endOfMonth β DateTime
endOfYear β DateTime
endOfQuarter β DateTime
Methods
clone() β DateTime
indexOfClosestDay(Iterable<DateTime> dates) β int
closestDayTo(Iterable<DateTime> dates) β DateTime?
isWithin(DateTime start, DateTime end) β bool
isWithinTimeSpan(TimeSpan timeSpan) β bool
endOf(Unit unit) β DateTime
startOf(Unit unit) β DateTime
subYears(int amount) β DateTime
subMonths(int amount) β DateTime
subWeeks(int amount) β DateTime
subDays(int amount) β DateTime
subHours(int amount) β DateTime
subMinutes(int amount) β DateTime
subSeconds(int amount) β DateTime
subMilliseconds(int amount) β DateTime
subMicroseconds(int amount) β DateTime
subtractDate({int microseconds, int milliseconds, int seconds, int minutes, int hours, int days, int weeks, int months, int years}) β DateTime
addDate({int microseconds, int milliseconds, int seconds, int minutes, int hours, int days, int weeks, int months, int years}) β DateTime
addYears(int amount) β DateTime
addMonths(int amount) β DateTime
addWeeks(int amount) β DateTime
addDays(int amount) β DateTime
addHours(int amount) β DateTime
addMinutes(int amount) β DateTime
addSeconds(int amount) β DateTime
addMilliseconds(int amount) β DateTime
addMicroseconds(int amount) β DateTime
diff(DateTime other, {Unit unit = Unit.microsecond, bool asFloat = false}) β num
diffInYears(DateTime other, {bool asFloat = false}) β num
diffInMonths(DateTime other, {bool asFloat = false}) β num
diffInWeeks(DateTime other, {bool asFloat = false}) β num
diffInDays(DateTime other, {bool asFloat = false}) β num
diffInHours(DateTime other, {bool asFloat = false}) β num
diffInMinutes(DateTime other, {bool asFloat = false}) β num
diffInSeconds(DateTime other, {bool asFloat = false}) β num
diffInMilliseconds(DateTime other, {bool asFloat = false}) β num
isSame(DateTime other, {Unit unit = Unit.microsecond}) β bool
isBeforeDate(DateTime other, {Unit unit = Unit.microsecond}) β bool
isAfterDate(DateTime other, {Unit unit = Unit.microsecond}) β bool
isSameOrBefore(DateTime other, {Unit unit = Unit.microsecond}) β bool
isSameOrAfter(DateTime other, {Unit unit = Unit.microsecond}) β bool
isSameDay(DateTime other) β bool
isSameWeek(DateTime other) β bool
isSameMonth(DateTime other) β bool
isSameYear(DateTime other) β bool
isSameHour(DateTime other) β bool
isSameMinute(DateTime other) β bool
isSameSecond(DateTime other) β bool
isBetween(DateTime startDateTime, DateTime endDateTime, {Unit unit = Unit.microsecond}) β bool
format({String? pattern, String? locale}) β String
formatRelative({String? locale, DateTime? clock, bool short = false, bool withPrefixAndSuffix = true}) β String
formatFrom({required DateTime clock, String? locale, bool short = false, bool withPrefixAndSuffix = true}) β String
formatFromNow({String? locale, bool short = false, bool withPrefixAndSuffix = true}) β String
formatTo({required DateTime clock, String? locale, bool short = false, bool withPrefixAndSuffix = true}) β String
formatToNow({String? locale, bool short = false, bool withPrefixAndSuffix = true}) β String
formatOrdinalNumber({String? locale}) β String
formatCalendar({String? locale, DateTime? clock, String? timePattern, String? datePattern}) β String
rangeTo(DateTime end, {Unit unit = Unit.day, int step = 1}) β Iterable<DateTime>
clamp(DateTime min, DateTime max) β DateTime
Day and week arithmetic (
addDays,subWeeks,startOfWeek,diffInDays, ...) uses calendar days, so the wall-clock time is kept across daylight saving time transitions.
Register Custom Locales (Add or Override)
A custom locale can also override calendarDateTime(), durationUnits() and shortDurationUnits(); when it doesn't, calendar times and durations use English.
You can add or override custom locales in the supported locales list. Locale codes are matched case-insensitively and accept BCP-47 tags (pt-BR, zh-cn); an unknown region falls back to its language, then to English.
void main() async {
await initializeDateFormatting();
// Adding custom locale
SupportedLocalesUtils.registerLocale('vi_custom', ViLocaleCustom());
// Overriding locale
SupportedLocalesUtils.registerLocale('vi', ViLocaleCustom());
}
class ViLocaleCustom extends DateFormatterLocale {
@override
String code() => 'vi_custom';
@override
String ordinal(int n) => '';
@override
String ordinalNumber(int n) => 'ngΓ y thα»© $n';
// Custom relative time
@override
RelativeDateTime relativeDateTime() => ViCustomRelativeTime();
// Custom short relative time
@override
RelativeDateTime shortRelativeDateTime() => ViCustomShortRelativeTime();
// Optional: calendar and duration strings (English is used otherwise)
@override
CalendarDateTime calendarDateTime() => ViCalendarDateTime();
@override
DurationUnits durationUnits() => ViDurationUnits();
}
// To change only a few strings, extend a built-in locale instead:
class ViOrdinalsCustom extends ViLocale {
@override
String ordinalNumber(int n) => 'ngΓ y thα»© $n';
}
Supported Locales
The package supports multiple locales. Here is a list of all supported locales:
Formatting & Relative Locales Supported
am- Amharicar- Arabicaz- Azerbaijanibe- Belarusianbn- Bengalibs- Bosnianca- Catalancs- Czechda- Danishde- Germanel- Greek (gris kept as an alias)en- Englishes- Spanishet- Estonianfa- Persianfi- Finnishfr- Frenchhe- Hebrewhi- Hindihr- Croatianhu- Hungarianid- Indonesianit- Italianja- Japaneseka- Georgiankm- Khmerko- Koreanlv- Latvianmn- Mongolianms/ms_MY- Malaymy- Burmesenb- Norwegian BokmΓ₯lnl- Dutchpl- Polishps- Pashtopt- Portuguesero- Romanianru- Russiansk- Slovaksr- Serbiansv- Swedishta- Tamilth- Thaitl_PH- Filipinotr- Turkishuk- Ukrainianur- Urduvi- Vietnamesezh/zh_CN- Chinese (Simplified)zh_TW/zh_HK- Chinese (Traditional)
Only Supported Relative Locales
dv- Divehiku- Kurdishnn- Norwegian Nynorskrw- Kinyarwandatk- Turkmen
Contributing π€
Contributions are welcome! Please open an issue or submit a pull request.
License π
This project is licensed under the MIT License - see the LICENSE file for details.