iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more
A date parsed with datetime.strptime(..., "%Y-%m-%d") represents midnight at the start of that date. Comparing it with datetime.now() therefore makes an “inclusive through this date” rule expire as soon as the date begins. The fix depends on whether your setting means a whole calendar day or an exact moment.
Why the comparison fails on the end date
Consider this pattern:
end = datetime.strptime("2026-08-20", "%Y-%m-%d")
return datetime.now() <= end
The string supplies a year, month, and day, but no time. Python fills unspecified strptime components from 1900-01-01T00:00:00.000; in this case, the resulting value is 2026-08-20 00:00:00. That is the start of August 20, not the end of it. Python’s datetime documentation describes this defaulting behavior.
datetime.now() without a timezone returns the current local date and time. At 12:01 a.m. on August 20, the current datetime is already later than midnight, so the comparison is false. The operator <= is doing what it should; the value on the right represents an earlier cutoff than the rule intended.
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →The DEV Community article describing this pattern reports that it blocked requests for 12 hours. That duration is the author’s account; it is not independently confirmed by the Python documentation or the other sources cited here. Read the reported incident.
#1 Best Overall
Choose the contract: a calendar date or an exact instant
Before changing the comparison, decide what the configured end value means. “Valid through August 20” names a calendar date. “Valid until August 20 at 5 p.m.” names an instant. They need different representations and tests.
| Policy | What the end means | What to compare | Boundary to test |
|---|---|---|---|
| Inclusive calendar date | The entire named date is included; time of day does not matter. | Current date and configured end date in the policy’s intended timezone. | Valid during the final date; invalid when the next date begins. |
| Exact instant | Validity ends at a specific time, with a defined timezone or offset. | Timezone-aware datetimes representing the current time and deadline. | Instants immediately before, at, and after the deadline. |
| Exclusive next-day boundary | The interval ends at midnight starting the day after the last included date. | Current instant and the next date’s start in the intended timezone. | Valid immediately before the boundary; invalid at or after it. |
Make an end date inclusive
If the setting truly means “valid through this calendar date,” compare dates rather than treating the parsed date as a midnight deadline:
Rank #2
from datetime import date, datetime
end_date = date.fromisoformat("2026-08-20")
is_valid = datetime.now().date() <= end_date
This includes every local time on the end date and rejects dates after it. The use of datetime.now() here makes “today” the machine’s local date. If the policy defines dates in a different timezone, obtain the current date in that timezone instead; otherwise, a server near midnight can disagree with the timezone that governs the rule.
Free tools Windows power users keep installed
One-click scans. No signup required.
You can also parse with datetime.strptime and call .date(), but parsing directly to a date makes the calendar-date contract clearer. Do not apply .date() when the configuration is meant to specify a time of day: doing so discards that precision.
Keep a precise deadline as a timezone-aware datetime
For an expiration such as “August 20 at 5 p.m. UTC,” store or parse an explicit timestamp with its timezone, then compare it with an aware current datetime. Python recommends datetime.now(timezone.utc) for the current time in UTC:
from datetime import datetime, timezone
end = datetime.fromisoformat("2026-08-20T17:00:00+00:00")
now = datetime.now(timezone.utc)
is_valid = now <= end
Both values in this example are timezone-aware. Python raises TypeError when ordering a naive datetime against an aware one, so do not mix a value such as datetime.now() with a UTC-aware deadline. For aware datetimes with different timezone information, Python’s comparison rules account for their UTC instants; local-time transitions still deserve explicit tests. See the datetime documentation.
datetime.now() is not inherently wrong: it is appropriate when the events and policy are intentionally expressed in local time. Paul Ganssle, a Python committer, noted in a 2022 issue discussion: “Of course, if you are consuming a bunch of event dates stored in local time and you want to compare them to the current time, then datetime.now() would be appropriate.” Read the discussion.
Use a next-day boundary when the interval is exclusive
An alternative for a date-based rule is to model the interval as ending at the start of the following date. Then validity can be expressed as “now is earlier than the exclusive boundary,” rather than “now is no later than the last date’s midnight.” Construct that boundary in the timezone that defines the policy. Local midnight can be affected by timezone and daylight-saving rules, so do not assume every local day is a fixed 24-hour duration.
Best Value
Python’s discussion of local-time disambiguation explains why repeated or ambiguous local times need care around clock changes. PEP 495: Local Time Disambiguation.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Test the boundary, not just an ordinary date
For an inclusive calendar-date rule, tests should make the intended contract explicit:
- A moment shortly after midnight on the configured end date is valid.
- A late moment on that same date is valid.
- A moment just after the following date begins is invalid.
- A clearly earlier date is valid.
For an exact timestamp rule, test instants just before, exactly at, and just after the deadline, including conversions between the relevant timezones. A date-only test cannot establish that time-of-day behavior is correct.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Scan for outdated or missing drivers - takes under a minute3Clear out junk files and repair common Windows errorsTest names should describe the policy—such as “end date is inclusive”—and expected results should pin down its boundary. This makes a later change to parsing, timezone handling, or comparison operators less likely to silently change what “end date” means. Python’s documentation provides the parsing and comparison rules underlying these cases. Python datetime reference.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

