Recent chats
ASKGEEZ Q&A GUIDETechnology & devices

How can I test a function that depends on the current time?

Quick answer

Pass the time into the calculation instead of having the calculation fetch it internally. Your application can obtain the current time with datetime.now(), while tests supply a fixed datetime value. That makes the result repeatable and lets you check exact boundary cases without relying on when the test happens to run. If you use a clock function, keep the same idea: substitute a predictable clock in the test.

LET’S WORK THROUGH IT

The question, the details, the next step.

Question

How can I test a function that depends on the current time without getting different results on different runs?

Geez

Make the time an input to the decision you want to test. For example, instead of having an is_expired function ask the system for the time, pass it both the deadline and the time to compare against. The surrounding application can get the current time with datetime.now(); Python documents that this returns the current local date and time when no timezone is supplied. [S1]

The key is that the test does not call now(). It chooses a fixed time and passes it in, so the expected answer does not depend on when the test runs. This example intentionally keeps the comparison simple:

from datetime import datetime


def is_expired(deadline: datetime, now: datetime) -> bool:
    return now >= deadline

The function has one clear job: compare two supplied values. The code that chooses the time is outside it.

Follow-up question

What would the test look like, including the exact deadline boundary?

Geez

Use fixed values for the deadline and the time being checked. Then test the moment just before the deadline, the deadline itself, and a moment after it. Those cases make the chosen rule—expired at the deadline or only afterward—visible. Here, >= means that equality counts as expired.

import unittest
from datetime import datetime

from expiry import is_expired


class IsExpiredTests(unittest.TestCase):
    def test_before_deadline_is_not_expired(self):
        deadline = datetime(2030, 5, 1, 12, 0)
        now = datetime(2030, 5, 1, 11, 59)
        self.assertFalse(is_expired(deadline, now))

    def test_at_deadline_is_expired(self):
        deadline = datetime(2030, 5, 1, 12, 0)
        now = datetime(2030, 5, 1, 12, 0)
        self.assertTrue(is_expired(deadline, now))

    def test_after_deadline_is_expired(self):
        deadline = datetime(2030, 5, 1, 12, 0)
        now = datetime(2030, 5, 1, 12, 1)
        self.assertTrue(is_expired(deadline, now))

Replace expiry with the name of your module. The test values are examples, not a claim about any real deadline. Keep the boundary expectation aligned with the behavior your program is meant to implement.

Follow-up question

My application code still needs to use the actual current time. Where should that happen?

Geez

Keep reading the clock at the edge of the application, then pass the result to the calculation. For example:

from datetime import datetime
from expiry import is_expired


def check_expiry(deadline: datetime) -> bool:
    current_time = datetime.now()
    return is_expired(deadline, current_time)

Now the comparison is independently testable, while check_expiry connects it to the real clock. If you also need to test code that calls check_expiry, consider passing in a clock callable, such as a function that returns a datetime. The real application can supply a callable that reads the clock; a test can supply one that returns a chosen value.

Avoid reading the clock in multiple places for a single decision. Capturing one value and passing it through makes it clear which instant that decision uses. The example uses local time because it calls datetime.now() without a timezone argument. This guide does not establish what timezone or time representation is appropriate for your application; choose that deliberately for your use case.

Follow-up question

What should I check before adding this pattern to my own code?

Geez

Start by identifying the exact rule that depends on time, then make that rule accept its time as an input. Write tests for both sides of the boundary and the boundary itself. If production code needs to obtain time, keep that responsibility separate and pass the value—or a clock callable—to the rule.

A reusable mini-template is:

def decision(deadline, now):
    # Put the time-dependent rule here.
    return now >= deadline


def test_decision():
    deadline = ...  # chosen test value
    now = ...       # chosen test value
    assert decision(deadline, now) is ...

For tests using unittest, replace the final assertion with an appropriate self.assertTrue(...) or self.assertFalse(...). The example covers a direct comparison only; it does not decide how your application should handle timezones, daylight-saving transitions, or invalid inputs. Those requirements need their own explicit design choices and tests.

A practical checklist

  • Identify the time-based rule and make the time an explicit input.

  • Keep reading the real clock outside the calculation being tested.

  • Use fixed test times rather than calling datetime.now() in the test.

  • Test before, at, and after the boundary, matching the intended rule.

  • Decide explicitly how your application represents time and handles invalid inputs.

A few more useful answers

Should I patch `datetime.now()` in every test?

Not for a calculation that can accept a time value directly: pass a fixed value to it. Patching or injecting a clock can be useful when testing code whose responsibility includes obtaining the time.

Why test the exact deadline, not just before and after?

The equality case reveals whether your rule treats the deadline itself as expired. Make that behavior explicit in both the comparison and the test.

Does this example settle which timezone my code should use?

No. It shows how to control the time input in a test, not which timezone or time representation fits your application.

Sources

References used for this guide.

  1. [S1] Python 3.14 datetime — Basic date and time types
    docs.python.org · Checked

YOUR QUESTION. YOUR DETAILS.

Let’s work through your situation.

Get a tailored answer or help with your next task. Starts at $1, with a quote before you pay.

Ask your own question
← Back to Geez at Work