Dart DateTime handling

eye-catchDart and Flutter

DateTime is very common in programming languages. We should know the basics to handle the date-time and show it correctly on our application. Let’s check how to handle date-time in Dart.

Sponsored links

Instantiate DateTime

Dart offers DateTime class to handle date and time. The specific date can be set by passing the value to the constructor.

print(DateTime(2020)); // 2020-01-01 00:00:00.000
print(DateTime(2020, 12)); // 2020-12-01 00:00:00.000
print(DateTime(2020, 12, 11, 10, 9, 8, 7, 6)); // 2020-12-11 10:09:08.007006

If the current date-time is needed, use now function.

print(DateTime.now());  // 2021-11-21 16:50:52.156693

If we need UTC time, we can use utc constructor. It instantiates the date-time with the specified time. toUtc() function can convert the date time to UTC but we should know the difference.

print(DateTime.utc(2020, 12, 11, 10, 9, 8));     // 2020-12-11 10:09:08.000Z
print(DateTime(2020, 12, 11, 10, 9, 8).toUtc()); // 2020-12-11 09:09:08.000Z

I executed this code in Germany. The timezone is +01:00. The original time is 2020-12-11T10:09:08. To convert the time to UTC, it needs to be subtracted for 1 hour. Therefore, the result becomes 2020-12-11 09:09:08.000Z here.

DateTime class offers constant values. These values are obvious but we should define them to make our code clearer. Let’s use them if necessary.

print(DateTime.may);            // 5
print(DateTime.daysPerWeek);    // 7
print(DateTime.monthsPerYear);  // 12
print(DateTime.monday);         // 1
print(DateTime.sunday);         // 7

DateFormat

We need to format the date-time if we want to show it on our application. DateFormat is for that. To use DateFormat, intl needs to be installed and imported.

import 'package:intl/intl.dart';

We can use DateFormat now.

final timestamp = DateTime(2021, 11, 12, 13, 14, 15,123);
print(timestamp); // 2021-11-12 13:14:15.123  

final formatter = DateFormat("yyyy-MM-ddTHH:mm:ss.SSS");
print(formatter.format(timestamp));  // 2021-11-12T13:14:15.123
print(DateFormat("yyyyMMddHHmmssSSS").format(timestamp)); // 20211112131415123

We can specify the following constant values. I think this list can cover almost all cases.

 ICU Name                   Skeleton
 --------                   --------
 DAY                          d
 ABBR_WEEKDAY                 E
 WEEKDAY                      EEEE
 ABBR_STANDALONE_MONTH        LLL
 STANDALONE_MONTH             LLLL
 NUM_MONTH                    M
 NUM_MONTH_DAY                Md
 NUM_MONTH_WEEKDAY_DAY        MEd
 ABBR_MONTH                   MMM
 ABBR_MONTH_DAY               MMMd
 ABBR_MONTH_WEEKDAY_DAY       MMMEd
 MONTH                        MMMM
 MONTH_DAY                    MMMMd
 MONTH_WEEKDAY_DAY            MMMMEEEEd
 ABBR_QUARTER                 QQQ
 QUARTER                      QQQQ
 YEAR                         y
 YEAR_NUM_MONTH               yM
 YEAR_NUM_MONTH_DAY           yMd
 YEAR_NUM_MONTH_WEEKDAY_DAY   yMEd
 YEAR_ABBR_MONTH              yMMM
 YEAR_ABBR_MONTH_DAY          yMMMd
 YEAR_ABBR_MONTH_WEEKDAY_DAY  yMMMEd
 YEAR_MONTH                   yMMMM
 YEAR_MONTH_DAY               yMMMMd
 YEAR_MONTH_WEEKDAY_DAY       yMMMMEEEEd
 YEAR_ABBR_QUARTER            yQQQ
 YEAR_QUARTER                 yQQQQ
 HOUR24                       H
 HOUR24_MINUTE                Hm
 HOUR24_MINUTE_SECOND         Hms
 HOUR                         j
 HOUR_MINUTE                  jm
 HOUR_MINUTE_SECOND           jms
 HOUR_MINUTE_GENERIC_TZ       jmv   (not yet implemented)
 HOUR_MINUTE_TZ               jmz   (not yet implemented)
 HOUR_GENERIC_TZ              jv    (not yet implemented)
 HOUR_TZ                      jz    (not yet implemented)
 MINUTE                       m
 MINUTE_SECOND                ms
 SECOND                       s

Let’s try to use them.

final timestamp = DateTime(2021, 11, 12, 13, 14, 15, 123);
print(DateFormat("MM dd").format(timestamp)); // 11 12
print(DateFormat("MMMd").format(timestamp));  // Nov 12
print(DateFormat.MMMd().format(timestamp));   // Nov 12

DateFormat with locale

Date format is different depending on the country. When we need to change the locale, it needs to be set correctly like this below.

print(DateFormat.MMMd("ja").format(timestamp));

But the following error occurs.

// Unhandled exception:
// LocaleDataException: Locale data has not been initialized,
// call initializeDateFormatting(<locale>).

I tried to set different locale to the initializeDateFormatting() function but I didn’t find the difference. Even if I set “de” to it, the format for “ja” succeeded. If we want to load all locales, call the function without argument.

import 'package:intl/date_symbol_data_local.dart';

await initializeDateFormatting();
print(DateFormat.MMMd("en").format(timestamp)); // Nov 12
print(DateFormat.MMMd("ja").format(timestamp)); // 11月12日
print(DateFormat.MMMd("de").format(timestamp)); // 12. Nov.

There are some packages that have the same function but others require arguments. Make sure that you import the right one.

Let’s check the difference. The order of the year/month/day is different for each.

final time = DateTime(2021, 10, 11, 20, 0, 15, 12);
print(DateFormat.yMd("en").add_jms().format(time)); // 10/11/2021 8:00:15 PM
print(DateFormat.yMd("en").add_Hms().format(time)); // 10/11/2021 20:00:15
print(DateFormat.yMd("ja").add_jms().format(time)); // 2021/10/11 20:00:15
print(DateFormat.yMd("ja").add_Hms().format(time)); // 2021/10/11 20:00:15
print(DateFormat.yMd("de").add_jms().format(time)); // 11.10.2021 20:00:15
print(DateFormat.yMd("de").add_Hms().format(time)); // 11.10.2021 20:00:15

According to the description above, jms and Hms return different formats. Let’s check the definitions again.

HOUR24_MINUTE_SECOND Hms
HOUR_MINUTE_SECOND jms

https://pub.dev/documentation/intl/latest/intl/DateFormat-class.html

However, the results are the same if the locale is not “en”. The intl version that I use in this article is 0.17.0. I didn’t find an issue in GitHub but it is a bug.

Add/Subtract to DateTime

Use add function to add time or subtract function to subtract time. The required argument is Duration class. We can specify neither month nor year. If we want to add a month or year, we need to calculate the number of days.

final datetime = DateTime(2021, 9, 12, 10, 11, 22, 33);
print(datetime); // 2021-09-12 10:11:22.033
print(datetime.add(Duration(days: 1)));          // 2021-09-13 10:11:22.033
print(datetime.add(Duration(hours: 10)));        // 2021-09-12 20:11:22.033
print(datetime.add(Duration(minutes: 10)));      // 2021-09-12 10:21:22.033
print(datetime.add(Duration(seconds: 10)));      // 2021-09-12 10:11:32.033
print(datetime.add(Duration(milliseconds: 10))); // 2021-09-12 10:11:22.043
print(datetime.add(Duration(microseconds: 10))); // 2021-09-12 10:11:22.033010
print(datetime.subtract(Duration(days: 1)));     // 2021-09-11 10:11:22.033

DateTime comparison

How can we compare two date-times? The first one is compareTo function. It returns 0, -1 or 1.

final datetime = DateTime(2021, 9, 12, 10, 11, 22, 33);
final datetime2 = datetime.add(Duration(days: 2));
print(datetime2.compareTo(datetime2)); // 0
print(datetime.compareTo(datetime2));  // -1
print(datetime2.compareTo(datetime));  // 1

X.compareTo(Y) -> 0 : X = Y
X.compareTo(Y) -> -1 : X < Y
X.compareTo(Y) -> 1 : X > Y

I prefer using isXXX unction instead because the intention is clearer than compareTo function and the code is more readable.

final datetime = DateTime(2021, 9, 12, 10, 11, 22, 33);
final datetime2 = datetime.add(Duration(days: 2));
print(datetime.isAtSameMomentAs(datetime)); // true
print(datetime.isAtSameMomentAs(datetime2)); // false
print(datetime.isBefore(datetime2)); // true
print(datetime.isBefore(datetime));  // false
print(datetime.isAfter(datetime2));  // false
print(datetime.isAfter(datetime));   // false

These functions can be used even if the two timestamps have a different timezone. In the following example, time1 is a local time which has +01:00 timezone offset but the functions return the correct result.

final time1 = DateTime(2020);
final time2 = DateTime.utc(2020);
print(time1.timeZoneName); // Western European Time
print(time1.timeZoneOffset.inHours); // 1
print(time1.toUtc()); // 2019-12-31 23:00:00.000Z
print(time2);         // 2020-01-01 00:00:00.000Z
print(time1.isAtSameMomentAs(time2)); // false
print(time1.compareTo(time2)); // -1
print(time1.isBefore(time2)); // true

If we need the difference of the two date times, use difference function. It returns Duration type.

print(datetime.difference(datetime2).inHours); // -48
print(datetime2.difference(datetime).inHours); // 48
print(datetime2.difference(datetime).inMinutes); // 2880

String to DateTime

The date-time input is sometimes string. We need to convert it to DateTime in this case. We can use parse or tryParse function.

void isDateTime(Object? object) {
    print(object is DateTime);
}

isDateTime(DateTime.parse("2020-11-11 10:10:12"));    // true
isDateTime(DateTime.tryParse("2020-11-11 10:10:12")); // true
isDateTime(DateTime.tryParse("20201111 10:10:12"));   // true
isDateTime(DateTime.tryParse("20201111101012"));      // false
isDateTime(DateTime.tryParse("20201111T101012"));     // true

tryParse returns null if the timestamp string can’t be parsed. That’s why the fourth one returns false. The format is not supported.
I tried the following code, but it throws an error.

// FormatException: Trying to read MM from 20201111101012 at position 14
isDateTime(new DateFormat("yyyyMMddhhmmss").parse("20201111101012"));

If we need to parse it we need to modify the string first.

final timestamp = "20201111101012";
final validStyle = timestamp.substring(0, 8) + "T" + timestamp.substring(8);
isDateTime(DateTime.parse(validStyle)); // true

Comments

Copied title and URL