Why Tempo?

Why Tempo?

To understand why you’d want to use Tempo, let’s try to perform a commonly needed datetime operation: find the “same time next month.” More specifically, a date and time exactly one month in the future, with the same day and time.

First, think about how you would do this with Dart’s standard DateTime. You might initially try adding a Duration of 30 days, but that’s only an approximation. The result may not have the same day, and if there was a time change in between, the time would be off by an hour, as well:

DateTime.now().add(Duration(days: 30));

Your next attempt might be to increment the month component separately:

final now = DateTime.now();
DateTime(now.year, now.month + 1, now.day, now.hour, now.minute, now.second);

This works quite a bit better, but it still has issues. First, it’s more complicated and easier make a mistake. You’d definitely want to write tests. Second, it relies on undocumented behavior. What happens in December, when you attempt to use a month of 13? (Spoiler: it will work, but nothing in the docs says it will.)

Last, and most importantly, there are some edge cases you might be unhappy with. For example, what happens if you add one month to Jan 31? The result above would be March 3—unless it’s a leap year—in which case it would be March 2. Most people would call that “a month and 2 or 3 days.” Returning the last day of February would make a lot more sense.

You could continue refining the solution, adding tests, identifying edge cases, until you’re happy with it, but this is turning into a lot of work for such a conceptually simple operation. So lets see how Tempo can solve it.

For this example we’ll use ZonedDateTime, which stores a date and a time with a time zone. And we’ll add a Period of one month:

final now = ZonedDateTime.now();
final nextMonth = now.plusPeriod(Period(months: 1));

And that’s it. The result will always be exactly one month in the future, at exactly the same time, with exactly the same day of the month. Unless the resulting month has too few days, in which case it returns the last day of that month. So Jan 31 becomes Feb 28 (29 on leap years), and Aug 31 becomes Sep 30.

Finally, let’s briefly consider the opposite problem. How could you find the exact number of years, months and days between two dates? This is a tougher problem to approach. It’s full of edge cases and requires extensive testing. Tempo can do it, though. Even over a period that includes a leap year:

final date1 = ZonedDateTime(2025, 1, 1);
final date2 = ZonedDateTime(2029, 2, 2);
final period = date1.periodUntil(date2);
period == Period(years: 4, months: 1, days: 1);