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.
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
https://pub.dev/documentation/intl/latest/intl/DateFormat-class.html
HOUR_MINUTE_SECOND jms
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