'How can I tell if DateTime.Now() is on a day AFTER a different DateTime

I'm running this on flutter, but I guess this could be a more general issue.

I am saving a DateTime in the preferences. I want to be able to then tell if DateTime.now() is on at least a day after the last saved DateTime, i.e.

(pseudocode)
lastDailyCheck = 2020.04.10
now = 2020.04.11

=> now is a day after the lastDailyCheck.

This should already work if it is 00:01 on the new day, even if the lastDailyCheck was on 23:58 the day before, meaning the difference can be as low as minutes between the 2 DateTimes.

Turns out this is really complicated!

Here's what doesn't work:

DateTime.Now().isAfter(lastDailyCheck)

This only checks if now is after the last one, it also return true after a second, and on the same day.

DateTime.Now().isAfter(lastDailyCheck) && lastDailyCheck.day != DateTime.Now().day

I thought this was clever. If the day is different and it is after the last then it does work in recognizing it is a day later - but then I realized it would bug out when both days are say on the 15th of the month - then lastDailyCheck.day would equal DateTime.Now().day.

What do you think would be possible here?



Solution 1:[1]

I don't know flutter, but my approach would be to not store the last check, but store the date at which the next check should occur. So when you perform a check you calculate the next midnight and store that. Now you can use isAfter.

In javascript this would look something like this:

const now = new Date();

//this also handles overflow into the next month
const nextCheck = new Date(now.getYear(), now.getMonth(), now.getDate() + 1)

//store nextCheck somewhere

//in js there is no isAfter, you just use >
if(new Date() > nextCheck) {
   //do the thing
}

of course you could also calculate nextCheck every time you want to compare it, but I dislike performing the same calculation over and over if I can avoid it.

A thing to mention here is timezones, depending on your date library and if your system and user timezones align, you may need to shift the date.

Solution 2:[2]

I cannot write a complete code for now but this is what it would look like:

(pseudocode)

expirationDay = lastDailyCheck.add(oneDayDuration);
isOneDayAfter = DateTime.now().isAfter(expirationDay);

You give an expiration date and compare the DateTime to that. You have to use isAfter for reliability, instead of .day check.

Solution 3:[3]

I would compute the difference between midnight of the day of the last timestamp and midnight of the current timestamp. That is, consider only the date portion of a DateTime and ignore the time.

DateTime date(DateTime dateTime) =>
    DateTime(dateTime.year, dateTime.month, dateTime.day);

// Intentionally check for a positive difference in hours instead of days
// so we don't need to worry about 23-hour days from DST.  Any non-zero
// number of hours here means a difference of at least a "day".
if (date(DateTime.now()).difference(date(lastDailyCheck)).inHours > 0) {
  // "One day" after.
}

If you're using UTC timestamps and don't care about when midnight is in whatever the local time is, the comparison could more intuitively use .inDays >= 1.

Solution 4:[4]

Figured out another potential solution!

In addition to checking if the day is different (which by itself won't work) you can also check the month and year. Only 1 of those needs to differ for it be true :)

if (now.isAfter(lastDailyCheck)) {
  if (now.day != lastDailyCheck.day ||
      now.month != lastDailyCheck.month ||
      now.year != lastDailyCheck.year) {
    return true;
  }
}

Solution 5:[5]

this is the way I prefer to do some logics based on the comparison between two different times:

var now = DateTime.now();
var myDate = new DateTime.utc(2022, 1, 1);
if(myDate.compareTo(now)>0) //positive value means myDate is greater than DateTime.now()
{
  // here is your logic based on the comparison between two times
} else {
 //your logic if DateTime.now() pass myDate
}

Solution 6:[6]

You can use the difference method to get the difference between 2 dates and check whether those differs in hours with at-least 24 hours. So your if condition becomes:

if (now.isAfter(lastDailyCheck) &&
    (lastDailyCheck.day != now.day ||
    now.difference(lastDailyCheck).inHours > 24)) {
    print('After');
}

Solution 7:[7]

Here's an attempt to a succint answer. Simply export this extension and use it. With it you can say if a date is at least one day after the current day.

extension DateExt on DateTime {
  bool isAtLeastOneDayAfterToday() {
    final now = DateTime.now();

    return (isAfter(now) &&
        (day != now.day || month != now.month || year != now.year));
  }
}

Use it like so:

final isAfter = myDay.isAtLeastOneDayAfterToday(); //will be true or false

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Rialgar
Solution 2 andras
Solution 3
Solution 4 matthias_code
Solution 5 Siavash Mirzaei-Fard
Solution 6 Midhun MP
Solution 7