Skip to content

Instantly share code, notes, and snippets.

@davidsdearaujo
Last active June 13, 2025 23:56
Show Gist options
  • Save davidsdearaujo/3350766847257f4a306626033618cc57 to your computer and use it in GitHub Desktop.
Save davidsdearaujo/3350766847257f4a306626033618cc57 to your computer and use it in GitHub Desktop.
Flutter: DateTime extension containing various formatting and date calculation helpers

Date Helper

That's a DateTime extension containing various formatting and date calculation helpers. There are two different files, you can pick one:

date_helper_l10n.dart

To use this version you need l10n internationalization configured in your project – that's the internationalization method officially recomended by Flutter website;

date_helper_NO_l10n.dart

This version uses fixed English texts, no extra configuration is required.

import 'package:clock/clock.dart';
import 'package:your_awesome_app/l10n/l10n.dart';
import 'package:intl/intl.dart';
/// DateTime extension containing various formatting and date calculation
/// helpers
extension DateTimeHelper on DateTime {
/// Formats date as a section header title with special handling for today/yesterday
/// and different formats for current year vs previous years
///
/// Example:
/// - Today => "TODAY"
/// - Yesterday => "YESTERDAY"
/// - Same year date => "WEDNESDAY, JAN 3"
/// - Cross-year date => "WEDNESDAY, JAN 3 2023"
String formattedSectionTitle(AppLocalizations l10n) {
final today = clock.now();
final yesterday = today.yesterday;
final String title;
if (isBetween(today.startOfDay, today.endOfDay)) {
title = l10n.today;
} else if (isBetween(yesterday.startOfDay, yesterday.endOfDay)) {
title = l10n.yesterday;
} else if (year == today.year) {
final dateFormat = DateFormat('EEEE, MMM d');
title = dateFormat.format(this);
} else {
final dateFormat = DateFormat('EEEE, MMM d y');
title = dateFormat.format(this);
}
return title.toUpperCase();
}
/// Formats time in lowercase am/pm format
///
/// Example: 21:30 => "9:30 pm"
String formattedTimeLowerCaseAmPm() {
final tripFormat = DateFormat('h:mm a');
return tripFormat.format(this).toLowerCase();
}
/// Formats elapsed time since this date
///
/// Example: "5 minutes ago", "3 hours ago", "2 days ago"
String formatElapsedTime({
required AppLocalizations l10n,
}) {
final now = clock.now();
final timeSince = now.difference(this);
var elapsedTime = '';
if (timeSince.inMinutes < 1) {
return l10n.justNow;
} else if (timeSince.inMinutes < 60) {
elapsedTime = l10n.timeDurationMinutes(timeSince.inMinutes);
} else if (timeSince.inHours < 24) {
elapsedTime = l10n.timeDurationHours(timeSince.inHours);
} else if (timeSince.inDays < 7) {
elapsedTime = l10n.timeDurationDays(timeSince.inDays);
} else {
elapsedTime = l10n.timeDurationWeeks(timeSince.inDays ~/ 7);
}
return l10n.timeAgo(elapsedTime);
}
/// Formats refresh time status with different phrasing than regular elapsed
/// time
///
/// Example: "Refreshed 2 hours ago", "Refreshed 3 months ago"
String formattedRefreshedTimeStatus(AppLocalizations l10n) {
final localTime = toLocal();
final timeSince = clock.now().difference(localTime);
if (timeSince.inHours < 1) {
return l10n.refreshedTimeInMinutes(timeSince.inMinutes);
} else if (timeSince.inHours < 24) {
return l10n.refreshedTimeInHours(timeSince.inHours);
} else if (timeSince.inDays < 14) {
return l10n.refreshedTimeInDays(timeSince.inDays);
} else if (timeSince.inDays < daysInMonth) {
return l10n.refreshedTimeInWeeks((timeSince.inDays / 7).round());
} else if (timeSince.inDays > 365) {
return l10n.refreshedTimeInYears(timeSince.inDays ~/ 365);
} else {
var timestamp = localTime;
var daysRemaining =
timeSince.inDays + localTime.daysInMonth - localTime.day;
var months = 0;
while (daysRemaining > 0) {
final daysInMonth = timestamp.daysInMonth;
if (daysRemaining < daysInMonth) {
break;
}
months += 1;
daysRemaining -= daysInMonth;
timestamp = DateTime(
timestamp.year,
timestamp.month + 1,
);
}
return l10n.refreshedTimeInMonths(months);
}
}
/// Formats date in MM/dd/yyyy format
/// Example: 2023-01-05 => "01/05/2023"
String formattedMMddyyyy() {
final dateFormat = DateFormat('MM/dd/yyyy');
return dateFormat.format(this);
}
/// Formats date in MM/dd format
/// Example: 2023-01-05 => "01/05"
String formattedMMdd() {
final dateFormat = DateFormat('MM/dd');
return dateFormat.format(this);
}
/// Formats date in abbreviated month format
/// Example: 2023-01-20 => "Jan 20, 2023"
String formattedMMMdy() {
final dateFormat = DateFormat('MMM d, y');
return dateFormat.format(this);
}
/// Formats date in full month format
/// Example: 2023-01-20 => "January 20, 2023"
String formattedMMMMdy() {
final dateFormat = DateFormat('MMMM d, y');
return dateFormat.format(this);
}
/// Formats date with full weekday and month name
/// Example: 2023-05-20 => "Saturday, May 20"
String formattedEEEEMMMMd() {
final dateFormat = DateFormat('EEEE, MMMM d');
return dateFormat.format(this);
}
/// Gets DateTime for yesterday at midnight
/// Example: 2023-01-05 14:30 => 2023-01-04 00:00
DateTime get yesterday {
return DateTime(
year,
month,
day - 1,
);
}
/// Gets DateTime for start of current day (midnight)
/// Example: 2023-01-05 14:30 => 2023-01-05 00:00
DateTime get startOfDay {
return DateTime(
year,
month,
day,
);
}
/// Gets DateTime for end of current day (23:59:59.999)
/// Example: 2023-01-05 14:30 => 2023-01-05 23:59:59.999
DateTime get endOfDay {
return DateTime(
year,
month,
day,
23,
59,
59,
999,
);
}
/// Checks if this date is between two other dates (inclusive)
/// Example: 2023-06-15.isBetween(2023-06-01, 2023-06-30) => true
bool isBetween(DateTime start, DateTime end) {
return (isBefore(end) || this == end) && (isAfter(start) || this == start);
}
/// Checks if two dates occur on the same calendar day
/// Example: 2023-01-05 14:30.isSameDay(2023-01-05 09:00) => true
bool isSameDay(DateTime? other) {
return year == other?.year && month == other?.month && day == other?.day;
}
/// Gets number of days in the current month
/// Example: February 2024 => 29 (leap year)
int get daysInMonth {
return DateTime(
year,
month + 1,
0,
).day;
}
}
import 'package:clock/clock.dart';
import 'package:intl/intl.dart';
/// DateTime extension containing various formatting and date calculation
/// helpers
extension DateTimeHelper on DateTime {
/// Formats date as a section header title with special handling for today/yesterday
/// and different formats for current year vs previous years
///
/// Example:
/// - Today => "TODAY"
/// - Yesterday => "YESTERDAY"
/// - Same year date => "WEDNESDAY, JAN 3"
/// - Cross-year date => "WEDNESDAY, JAN 3 2023"
String formattedSectionTitle() {
final today = clock.now();
final yesterday = today.yesterday;
final String title;
if (isBetween(today.startOfDay, today.endOfDay)) {
title = 'today';
} else if (isBetween(yesterday.startOfDay, yesterday.endOfDay)) {
title = 'yesterday';
} else if (year == today.year) {
final dateFormat = DateFormat('EEEE, MMM d');
title = dateFormat.format(this);
} else {
final dateFormat = DateFormat('EEEE, MMM d y');
title = dateFormat.format(this);
}
return title.toUpperCase();
}
/// Formats time in lowercase am/pm format
///
/// Example: 21:30 => "9:30 pm"
String formattedTimeLowerCaseAmPm() {
final tripFormat = DateFormat('h:mm a');
return tripFormat.format(this).toLowerCase();
}
/// Formats elapsed time since this date
///
/// Example: "5 minutes ago", "3 hours ago", "2 days ago"
String formatElapsedTime() {
final now = clock.now();
final timeSince = now.difference(this);
var elapsedTime = '';
if (timeSince.inMinutes < 1) {
return 'Just now';
} else if (timeSince.inMinutes < 60) {
elapsedTime = '${timeSince.inMinutes} minutes ago';
} else if (timeSince.inHours < 24) {
elapsedTime = '${timeSince.inHours} hours ago';
} else if (timeSince.inDays < 7) {
elapsedTime = '${timeSince.inDays} days ago';
} else {
elapsedTime = '${timeSince.inDays ~/ 7} weeks ago';
}
return elapsedTime;
}
/// Formats refresh time status with different phrasing than regular elapsed
/// time
///
/// Example: "Refreshed 2 hours ago", "Refreshed 3 months ago"
String formattedRefreshedTimeStatus() {
final localTime = toLocal();
final timeSince = clock.now().difference(localTime);
if (timeSince.inHours < 1) {
return 'Refreshed ${timeSince.inMinutes} minutes ago';
} else if (timeSince.inHours < 24) {
return 'Refreshed ${timeSince.inHours} hours ago';
} else if (timeSince.inDays < 14) {
return 'Refreshed ${timeSince.inDays} days ago';
} else if (timeSince.inDays < daysInMonth) {
return 'Refreshed ${(timeSince.inDays / 7).round()} weeks ago';
} else if (timeSince.inDays > 365) {
return 'Refreshed ${timeSince.inDays ~/ 365} years ago';
} else {
var timestamp = localTime;
var daysRemaining =
timeSince.inDays + localTime.daysInMonth - localTime.day;
var months = 0;
while (daysRemaining > 0) {
final daysInMonth = timestamp.daysInMonth;
if (daysRemaining < daysInMonth) {
break;
}
months += 1;
daysRemaining -= daysInMonth;
timestamp = DateTime(
timestamp.year,
timestamp.month + 1,
);
}
return 'Refreshed ${months} months ago';
}
}
/// Formats date in MM/dd/yyyy format
/// Example: 2023-01-05 => "01/05/2023"
String formattedMMddyyyy() {
final dateFormat = DateFormat('MM/dd/yyyy');
return dateFormat.format(this);
}
/// Formats date in MM/dd format
/// Example: 2023-01-05 => "01/05"
String formattedMMdd() {
final dateFormat = DateFormat('MM/dd');
return dateFormat.format(this);
}
/// Formats date in abbreviated month format
/// Example: 2023-01-20 => "Jan 20, 2023"
String formattedMMMdy() {
final dateFormat = DateFormat('MMM d, y');
return dateFormat.format(this);
}
/// Formats date in full month format
/// Example: 2023-01-20 => "January 20, 2023"
String formattedMMMMdy() {
final dateFormat = DateFormat('MMMM d, y');
return dateFormat.format(this);
}
/// Formats date with full weekday and month name
/// Example: 2023-05-20 => "Saturday, May 20"
String formattedEEEEMMMMd() {
final dateFormat = DateFormat('EEEE, MMMM d');
return dateFormat.format(this);
}
/// Gets DateTime for yesterday at midnight
/// Example: 2023-01-05 14:30 => 2023-01-04 00:00
DateTime get yesterday {
return DateTime(
year,
month,
day - 1,
);
}
/// Gets DateTime for start of current day (midnight)
/// Example: 2023-01-05 14:30 => 2023-01-05 00:00
DateTime get startOfDay {
return DateTime(
year,
month,
day,
);
}
/// Gets DateTime for end of current day (23:59:59.999)
/// Example: 2023-01-05 14:30 => 2023-01-05 23:59:59.999
DateTime get endOfDay {
return DateTime(
year,
month,
day,
23,
59,
59,
999,
);
}
/// Checks if this date is between two other dates (inclusive)
/// Example: 2023-06-15.isBetween(2023-06-01, 2023-06-30) => true
bool isBetween(DateTime start, DateTime end) {
return (isBefore(end) || this == end) && (isAfter(start) || this == start);
}
/// Checks if two dates occur on the same calendar day
/// Example: 2023-01-05 14:30.isSameDay(2023-01-05 09:00) => true
bool isSameDay(DateTime? other) {
return year == other?.year && month == other?.month && day == other?.day;
}
/// Gets number of days in the current month
/// Example: February 2024 => 29 (leap year)
int get daysInMonth {
return DateTime(
year,
month + 1,
0,
).day;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment