问题
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?
回答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.
回答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.
回答3:
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');
}
回答4:
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.
回答5:
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;
}
}
来源:https://stackoverflow.com/questions/61266922/how-can-i-tell-if-datetime-now-is-on-a-day-after-a-different-datetime