Small details that build taste in Flutter.

curated by Kamran BekirovKamran Bekirov

Format dates for humans

2016-06-24 14:44:00.000 is what DateTime prints, and no user should read a date like that. Show 24 July 2016, 14:44 instead.

DateFormat from intl does the formatting. It takes a pattern and a locale, so month names come out in the user's language:

DateFormat('d MMMM yyyy, HH:mm', languageCode).format(dateTime)

Locale data doesn't load itself, so initialize it once in main:

await initializeDateFormatting();

Calling DateFormat with patterns all over the app gets messy. Collect the formats in one extension on DateTime? (copy-pasteable file at the bottom), where every case has a method, a null date becomes a placeholder instead of null on screen, and showing a date stays one call:

Text(
  order.createdAt.formattedDateTime(languageCode),
)

Spell the month out where the date is the point, like an order details page:

// 24 July 2016, 14:44
String formattedDateTime(String languageCode) {
  if (this == null) return 'N/A';
  
  return DateFormat('d MMMM yyyy, HH:mm', languageCode).format(this!);
}

Dense lists have no room for full month names, so shorten there:

// 24 Jul 2016
String formattedDate(String languageCode) {
  if (this == null) return 'N/A';
  
  return DateFormat('d MMM yyyy', languageCode).format(this!);
}

Add the weekday to the pattern when the user plans around it, like an appointment:

// Friday, 24 July
String formattedWeekdayDate(String languageCode) {
  if (this == null) return 'N/A';
  
  return DateFormat('EEEE, d MMMM', languageCode).format(this!);
}

If everything on the screen happened today, show only the time:

// 14:44
String get formattedTime {
  if (this == null) return 'N/A';
  
  return DateFormat('HH:mm').format(this!);
}

For recent dates, Today reads better than 24 July. Check today and yesterday first, then fall back to the date. Run the labels through your translations too:

// Today · Yesterday · 24 Jul 2016
String formattedDayOrDate(String languageCode) {
  if (this == null) return 'N/A';
  
  if (isToday) return 'Today';
  if (isYesterday) return 'Yesterday';
  
  return formattedDate(languageCode);
}

The backend needs its own fixed format, never shown to users:

// 2016-07-24, for requests only
String get formattedForBackend {
  if (this == null) return '';
  
  return DateFormat('yyyy-MM-dd').format(this!);
}

The whole file, ready to copy:

import 'package:intl/intl.dart';
  
extension DateTimeX on DateTime? {
  // 24 July 2016, 14:44
  String formattedDateTime(String languageCode) {
    if (this == null) return 'N/A';
  
    return DateFormat('d MMMM yyyy, HH:mm', languageCode).format(this!);
  }
  
  // 24 Jul 2016
  String formattedDate(String languageCode) {
    if (this == null) return 'N/A';
  
    return DateFormat('d MMM yyyy', languageCode).format(this!);
  }
  
  // Friday, 24 July
  String formattedWeekdayDate(String languageCode) {
    if (this == null) return 'N/A';
  
    return DateFormat('EEEE, d MMMM', languageCode).format(this!);
  }
  
  // 14:44
  String get formattedTime {
    if (this == null) return 'N/A';
  
    return DateFormat('HH:mm').format(this!);
  }
  
  // Today · Yesterday · 24 Jul 2016
  String formattedDayOrDate(String languageCode) {
    if (this == null) return 'N/A';
  
    if (isToday) return 'Today';
    if (isYesterday) return 'Yesterday';
  
    return formattedDate(languageCode);
  }
  
  // 2016-07-24, for requests only
  String get formattedForBackend {
    if (this == null) return '';
  
    return DateFormat('yyyy-MM-dd').format(this!);
  }
  
  bool get isToday {
    if (this == null) return false;
  
    final DateTime now = DateTime.now();
  
    return this!.year == now.year &&
        this!.month == now.month &&
        this!.day == now.day;
  }
  
  bool get isYesterday {
    if (this == null) return false;
  
    final DateTime yesterday = DateTime.now().subtract(
      const Duration(days: 1),
    );
  
    return this!.year == yesterday.year &&
        this!.month == yesterday.month &&
        this!.day == yesterday.day;
  }
}
Kamran Bekirov
Kamran Bekirov

Want this level of care in your Flutter apps?

Work With Me