Dart/Flutter - Format DateTime to String Examples

This tutorial shows various ways to convert a DateTime instance to a string with a specific format, including localization support.

In Dart, values that represent a time instance are usually stored as a DateTime variable. DateTime has a toString method that returns a human-readable string. However, in most cases, there is a requirement to display the value in a particular format. This tutorial explains several ways to convert a DateTime to a string with any format you want.

First of all, we need to create a DateTime instance.

  DateTime dt = DateTime.now();

In the examples below, we are going to format the instance above.

Format to ISO-8601

ISO-8601 defines standards for date time formats. Flutter has built-in functionality to convert a DateTime to a string that complies with the ISO-8601 full-precision extended format. For UTC time, the format is yyyy-MM-ddTHH:mm:ss.mmmuuuZ. For non-UTC time, the format is yyyy-MM-ddTHH:mm:ss.mmmuuu (without Z). To return a string with that format, just call the toIso8601String method.

  final nonUtcIso8601 = dt.toIso8601String();
  final utcIso8601 = dt.toUtc().toIso8601String();
  print('Non UTC: $nonUtcIso8601');
  print('UTC: $utcIso8601');

Output:

  Non UTC: 2023-06-01T17:15:55.469427
  UTC: 2023-06-01T10:15:55.469427Z

Without Library

The DateTime class has properties for accessing the components of a date time. You can access some of the properties to be included in the formatted string. Below are the important properties that you may need to use.

  • year
  • month
  • day
  • hour
  • minute
  • second
  • millisecond
  • microsecond
  • weekday
  • timeZoneName
  • timeZoneOffset

Example:

  final result = '${dt.year}-${dt.month}-${dt.day} (${dt.hour}:${dt.minute}:${dt.second}})';
  print(result);

Output:

  2023-06-01 (17:15:55)

Using intl Package

Formatting a date can be a challenging thing if your application needs to display various date formats. You may need to write the code and perform testing for each format. That requires a lot of effort. In addition, if your application supports multiple languages, formatting to specific language(s) or locales(s) needs additional effort as well. That's because parts of the formatted string can have locale-specific values. For example, the list of month names in English is different to other languages such as French, German, Spanish, or Indonesian. Fortunately, there is an official package from dart.dev that allows you to convert a DateTime to any format using various locales.

intl is a popular library that provides internationalization and localization. It has a class named DateFormat which can be used for formatting and parsing date time values.

First, add it to the dependencies of your pubspec.yaml.

  dependencies:
    intl: ^0.18.1

Then, run dart pub get (or flutter pub get for Flutter) to install the package. After that, add the import statement below on the file where you want to use it.

  import 'package:intl/intl.dart';

Next, you need to create a DateFormat instance and call the format method by passing the DateTime to be formatted. The DateFormat instance defines the pattern to be used. You can create it using one of the named constructors if the pattern you want to use is already defined. The list of predefined patterns can be seen on the class documentation. Below is the usage example.

  final result = DateFormat('yMMMMEEEEd').format(DateTime.now();
  print(result):

Output:

  Thursday, June 1, 2023

As of version 0.18.1, here is the list of the predefined patterns along with the example.

  • d (1)
  • E (Thu)
  • EEEE (Thursday)
  • LLL (Jun)
  • LLLL (June)
  • M (6)
  • Md (6/1)
  • MEd (Thu, 6/1)
  • MMM (Jun)
  • MMMd (Jun 1)
  • MMMEd (Thu, Jun 1)
  • MMMM (June)
  • MMMMd (June 1)
  • MMMMEEEEd (Thursday, June 1)
  • QQQ (Q2)
  • QQQQ (2nd quarter)
  • y (2023)
  • yM (6/2023)
  • yMd (6/1/2023)
  • yMEd (Thu, 6/1/2023)
  • yMMM (Jun 2023)
  • yMMMd (Jun 1, 2023)
  • yMMMEd (Thu, Jun 1, 2023)
  • yMMMM (June 2023)
  • yMMMMd (June 1, 2023)
  • yMMMMEEEEd (Thursday, June 1, 2023)
  • yQQQ (Q2 2023)
  • yQQQQ (2nd quarter 2023)
  • H (16)
  • Hm (16:38)
  • Hms (16:38:40)
  • j (4 PM)
  • jm (4:38 PM)
  • jms (4:38:40 PM)
  • d (1)
  • E (Thu)
  • EEEE (Thursday)
  • LLL (Jun)
  • LLLL (June)
  • M (6)
  • Md (6/1)
  • MEd (Thu, 6/1)
  • MMM (Jun)
  • MMMd (Jun 1)
  • MMMEd (Thu, Jun 1)
  • MMMM (June)
  • MMMMd (June 1)
  • MMMMEEEEd (Thursday, June 1)
  • QQQ (Q2)
  • QQQQ (2nd quarter)
  • y (2023)
  • yM (6/2023)
  • yMd (6/1/2023)
  • yMEd (Thu, 6/1/2023)
  • yMMM (Jun 2023)
  • yMMMd (Jun 1, 2023)
  • yMMMEd (Thu, Jun 1, 2023)
  • yMMMM (June 2023)
  • yMMMMd (June 1, 2023)
  • yMMMMEEEEd (Thursday, June 1, 2023)
  • yQQQ (Q2 2023)
  • yQQQQ (2nd quarter 2023)
  • H (16)
  • Hm (16:38)
  • Hms (16:38:40)
  • j (4 PM)
  • jm (4:38 PM)
  • jms (4:38:40 PM)

If the format you want to use is not already defined, you can create a DateFormat instance with a custom pattern.

  print(DateFormat('yyyy-MM-dd').format(currentTime));

Below is the list of characters that can be processed as a part of the pattern:

  • G (era designator, e.g. AD)
  • y (year, e.g. 1996)
  • M (month in year, e.g. July & 07)
  • L (standalone month, e.g. July & 07)
  • d (day in month, e.g. 10)
  • c (standalone day, e.g. 10)
  • h (hour in am/pm (1~12), e.g. 12)
  • H (hour in day (0~23), e.g. 0)
  • m (minute in hour, e.g. 30)
  • s (second in minute, e.g. 55)
  • S (fractional second, e.g. 978)
  • E (day of week, e.g. Tuesday)
  • D (day in year, e.g. 189)
  • a (am/pm marker, e.g. PM)
  • k (hour in day (1~24), e.g. 24)
  • K (hour in am/pm (0~11), e.g. 0)
  • Q (quarter, e.g. Q3)
  • ' (escape for text, e.g. 'Date=')
  • '' (single quote, e.g. o''clock')

intl Localization

The intl package supports localization. The default locale is en_US. To use another locale, you need to call intl's initializeDateFormatting method. The method is responsible for loading date symbols for all supported locales and the date pattern map. It's an asynchronous method that returns Future, so you have to call it using await inside an async block.

  await initializeDateFormatting();

Alternatively, you can chain the Future.

  initializeDateFormatting()
    .then((_) {
      // your code here
    });

To run a function with a specific locale. you can use Intl.withLocale by passing the locale as the first argument and the function to be run as the second argument. In the example below, the first call to formatDateTime uses id_ID as the locale, while the second call uses pt_BR as the locale.

  Intl.withLocale("id_ID", () {
    final result = DateFormat.yMEd().format(dt);
    print('id_ID: $result');
  });
  Intl.withLocale("pt_BR", () {
    final result = DateFormat.yMEd().format(dt);
    print('pt_BR: $result');
  });

Output:

  Kam, 1/6/2023
  qui., 01/06/2023

It's also possible to change the default locale.

  Intl.defaultLocale = "id_ID";

Using jiffy Package

Jiffy is a date time package for Dart inspired by momentjs for Javascript. It also supports formatting date time with various patterns. To use the package, add it to the dependencies of your pubspec.yaml file and run dart pub get (or flutter pub get for Flutter)

  dependencies:
    jiffy: ^6.1.0

Then, import the library on the file where you want to use it

  import 'package:jiffy/jiffy.dart';

To work with Jiffy, you need to have the time instant as a Jiffy instance. If you already have a DateTime instance, you can convert it to a Jiffy instance using Jiffy.parseFromDateTime factory constructor.

  final currentTime = DateTime.now();
  final jdt = Jiffy.parseFromDateTime(currentTime);

Jiffy has some predefined getters for common patterns. To format a Jiffy instance to a string, just access the getter with the pattern you want to use.

  final result = jdt.MMMMEEEEd;
  print(result);

Output:

  Thursday, June 1

Below is the list of predefined getters along with the example.

  • E (Thu)
  • EEEE (Thursday)
  • Md (6/1)
  • MEd (Thu, 6/1)
  • MMM (Jun)
  • MMMd (Jun 1)
  • MMMEd (Thu, Jun 1)
  • MMMM (June)
  • MMMMd (June 1)
  • MMMMEEEEd (Thursday, June 1)
  • QQQ (Q2)
  • QQQQ (2nd quarter)
  • yM (6/2023)
  • yMd (6/1/2023)
  • yMEd (Thu, 6/1/2023)
  • yMMM (Jun 2023)
  • yMMMd (Jun 1, 2023)
  • yMMMdjm (Jun 1, 2023 6:10 PM)
  • yMMMEd (Thu, Jun 1, 2023)
  • yMMMEdjm (Thu, Jun 1, 2023 6:10 PM)
  • yMMMM (June 2023)
  • yMMMMd (June 1, 2023)
  • yMMMMdjm (June 1, 2023 6:10 PM)
  • yMMMMEEEEd (Thursday, June 1, 2023)
  • yMMMMEEEEdjm (Thursday, June 1, 2023 6:10 PM)
  • yQQQ (Q2 2023)
  • yQQQQ (2nd quarter 2023)
  • H (18)
  • Hm (18:10)
  • Hms (18:10:37)
  • j (6 PM)
  • jm (6:10 PM)
  • jms (6:10:37 PM)

It's also possible to use a custom pattern. The list of supported characters for pattern is basically the same as the DateFormat class of intl package, since Jiffy runs on top of DateFormat.

  Jiffy.parseFromDateTime(currentTime).format(pattern: 'yyyy-MM-dd') // 2023-06-01

jiffy Localization

Jiffy also supports localization. To use a particular locale, call Jiffy.setLocale method and pass the locale you want to use. It returns a Future, so you have to use await inside an async block or chain the Future. To switch to another locale, call the setLocale method again. You can see the package documentation for the list of supported locales.

  await Jiffy.setLocale('id');
  final idResult = DateFormat('yyyy, MMMM dd').format(currentTime);
  print('id: $idResult');

  await Jiffy.setLocale('fr_ca');
  final frCaResult = DateFormat('yyyy, MMMM dd').format(currentTime);
  print('fr_ca: $frCaResult');

Output:

  id: 2023, Juni 01
  fr_ca: 2023, juin 01

Summary

There are several ways to format a DateTime in Dart. If the expected output is in ISO-8601 format, just use the toIso8601String method. If the format is simple and you don't need to handle various formats or localization, writing your own code can be a lightweight solution as you don't need any additional library. If you get a requirement to handle multiple or complex formats, especially with localization support, using an additional library such as intl or jiffy can be the solution.

You can also read about: