271

Can anyone tell me why this isn't working?

>>> import mock
>>> @mock.patch('datetime.date.today')
... def today(cls):
...  return date(2010, 1, 1)
...
>>> from datetime import date
>>> date.today()
datetime.date(2010, 12, 19)

Perhaps someone could suggest a better way?

4

23 Answers 23

234

Another option is to use https://github.com/spulec/freezegun/

Install it:

pip install freezegun

And use it:

from freezegun import freeze_time

@freeze_time("2012-01-01")
def test_something():

    from datetime import datetime
    print(datetime.now()) #  2012-01-01 00:00:00

    from datetime import date
    print(date.today()) #  2012-01-01

It also affects other datetime calls in method calls from other modules:

other_module.py:

from datetime import datetime

def other_method():
    print(datetime.now())    

main.py:

from freezegun import freeze_time

@freeze_time("2012-01-01")
def test_something():

    import other_module
    other_module.other_method()

And finally:

$ python main.py
# 2012-01-01
7
  • 20
    A very very useful library
    – Shaun
    Commented Jun 6, 2014 at 6:06
  • 5
    You might also try python-libfaketime if you notice your freezegun tests running slowly. Commented Apr 10, 2015 at 1:12
  • Great library, but unfortunately doesn't play well with Google App Engine NDB/Datastore.
    – brandones
    Commented Oct 30, 2016 at 23:22
  • 1
    Works, but freezegun seems to be slow, especially if you have complicated logic with multiple calls for current time. Commented Apr 29, 2019 at 23:26
  • 1
    time-machine is another option, arguably faster/better than freezegun
    – Shiva
    Commented Jan 19 at 10:53
179

For what it's worth, the Mock docs talk about datetime.date.today specifically, and it's possible to do this without having to create a dummy class:

https://docs.python.org/3/library/unittest.mock-examples.html#partial-mocking

>>> from datetime import date
>>> with patch('mymodule.date') as mock_date:
...     mock_date.today.return_value = date(2010, 10, 8)
...     mock_date.side_effect = lambda *args, **kw: date(*args, **kw)
...
...     assert mymodule.date.today() == date(2010, 10, 8)
...     assert mymodule.date(2009, 6, 8) == date(2009, 6, 8)
...
10
  • 3
    This didn't really work for me. Though I appreciate the effort in locating the entry.
    – Pradyot
    Commented Mar 27, 2015 at 17:33
  • 15
    what means "mymodule" at patch function ?
    – seufagner
    Commented Sep 2, 2015 at 15:21
  • 4
    Found the link here under "Partial Mocking"
    – BrockLee
    Commented Oct 14, 2015 at 19:26
  • 4
    @seufagner mymodule is explained in a rather confusing fashion at voidspace.org.uk/python/mock/patch.html#where-to-patch. It seems that if your module uses from datetime import date then it is the name of the module where from datetime import date and the call to date.today() appears
    – danio
    Commented Jul 19, 2016 at 13:15
  • 1
    Thanks. Worked! Example: with mock.patch('tests.views.datetime') as mock_date: mock_date.today.return_value = datetime.datetime(2016, 9, 18) mock_date.side_effect = lambda *args, **kw: date(*args, **kw)
    – Latrova
    Commented Sep 28, 2016 at 19:00
157

There are a few problems.

First of all, the way you're using mock.patch isn't quite right. When used as a decorator, it replaces the given function/class (in this case, datetime.date.today) with a Mock object only within the decorated function. So, only within your today() will datetime.date.today be a different function, which doesn't appear to be what you want.

What you really want seems to be more like this:

@mock.patch('datetime.date.today')
def test():
    datetime.date.today.return_value = date(2010, 1, 1)
    print datetime.date.today()

Unfortunately, this won't work:

>>> test()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "build/bdist.macosx-10.6-universal/egg/mock.py", line 557, in patched
  File "build/bdist.macosx-10.6-universal/egg/mock.py", line 620, in __enter__
TypeError: can't set attributes of built-in/extension type 'datetime.date'

This fails because Python built-in types are immutable - see this answer for more details.

In this case, I would subclass datetime.date myself and create the right function:

import datetime
class NewDate(datetime.date):
    @classmethod
    def today(cls):
        return cls(2010, 1, 1)
datetime.date = NewDate

And now you could do:

>>> datetime.date.today()
NewDate(2010, 1, 1)
6
  • 14
    a nice solution, but unfortunately causes problems with pickling.
    – Baczek
    Commented Mar 22, 2011 at 9:15
  • 23
    While this answer is good, it's possible to mock datetime without creating a class: stackoverflow.com/a/25652721/117268 Commented Jan 22, 2015 at 15:03
  • How would you restore the datetime instance to it original value? with deepcoppy ? Commented Jan 10, 2017 at 15:48
  • 9
    Much easier to do: patch('mymodule.datetime', Mock(today=lambda: date(2017, 11, 29))) Commented Nov 29, 2017 at 17:26
  • 2
    More much easier to do @patch('module_you_want_to_test.date', Mock( today=Mock(return_value=datetime.date(2017, 11, 29)))).
    – Max
    Commented Jul 19, 2018 at 11:54
96
+100

Here's another way to mock datetime.date.today() with an added bonus that the rest of datetime functions continue to work, as the mock object is configured to wrap the original datetime module:

from unittest import mock, TestCase

import foo_module

class FooTest(TestCase):

    @mock.patch(f'{foo_module.__name__}.datetime', wraps=datetime)
    def test_something(self, mock_datetime):
        # mock only datetime.date.today()
        mock_datetime.date.today.return_value = datetime.date(2019, 3, 15)
        # other calls to datetime functions will be forwarded to original datetime

Note the wraps=datetime argument to mock.patch() – when the foo_module uses other datetime functions besides date.today() they will be forwarded to the original wrapped datetime module.

6
  • 5
    Great answer, most tests where you need to mock date you'll need to use datetime module
    – Antoine Vo
    Commented Oct 24, 2019 at 19:42
  • 9
    This should be the accepted answer. Thanks to this I now know about patch(wraps=) which doesn't seem to appear in official documentation. As stated, this solution also lets you keep the entire functionality for the rest of the module.
    – EliadL
    Commented Mar 18, 2021 at 23:38
  • 1
    Thank your for the bounty, @EliadL!
    – mrts
    Commented Mar 20, 2021 at 20:19
  • Works for me. NB for those not in the know (I was one), the patch fixture (if this the right term) here must be the first parameter of the test (after self) Commented Oct 30, 2021 at 12:19
  • 1
    @EliadL It is there in the docs, kind of: docs.python.org/3/library/unittest.mock.html#patch ... and look at the bottom of that para: "patch() takes arbitrary keyword arguments. These will be passed to AsyncMock if the patched object is asynchronous, to MagicMock otherwise or to new_callable if specified.". Commented Oct 31, 2021 at 8:36
46

I guess I came a little late for this but I think the main problem here is that you're patching datetime.date.today directly and, according to the documentation, this is wrong.

You should patch the reference imported in the file where the tested function is, for example.

Let's say you have a functions.py file where you have the following:

import datetime

def get_today():
    return datetime.date.today()

then, in your test, you should have something like this

import datetime
import unittest

from functions import get_today
from mock import patch, Mock

class GetTodayTest(unittest.TestCase):

    @patch('functions.datetime')
    def test_get_today(self, datetime_mock):
        datetime_mock.date.today = Mock(return_value=datetime.strptime('Jun 1 2005', '%b %d %Y'))
        value = get_today()
        # then assert your thing...

Hope this helps a little bit.

4
  • This looks very compelling, but I cannot get this to run (throws a NameError: name 'datetime' is not defined). Where does the datetime.strptime reference in Mock(return_value=...) come from if you are not importing datetime in your test file? UPDATE: It's OK, I just went ahead and imported the datetime module in the test file. I thought the trick was some how that you are hiding the datetime reference from the test file.
    – imrek
    Commented May 1, 2017 at 19:27
  • @DrunkenMaster I'd have to see an example of what you were doing and which reference you were mocking. were you doing import datetime or from datetime import strptime? if you were doing the first one, you'd have to mock datetime and do mocked_datetime.strptime.return_value = whatever, is the later one, you'd have to directly mock the strptime reference in the file where the tested method lives.
    – iferminm
    Commented May 4, 2017 at 14:08
  • @israelord What I meant to say is that your last code snippet (the test file) is missing an import for the datetime reference to make Mock(return_value=datetime...) work.
    – imrek
    Commented May 4, 2017 at 14:14
  • However, this would not work if the OP just wanted to mock the today method leaving the rest untouched.
    – Javi Torre
    Commented Jan 3, 2022 at 23:40
35

To add to Daniel G's solution:

from datetime import date

class FakeDate(date):
    "A manipulable date replacement"
    def __new__(cls, *args, **kwargs):
        return date.__new__(date, *args, **kwargs)

This creates a class which, when instantiated, will return a normal datetime.date object, but which is also able to be changed.

@mock.patch('datetime.date', FakeDate)
def test():
    from datetime import date
    FakeDate.today = classmethod(lambda cls: date(2010, 1, 1))
    return date.today()

test() # datetime.date(2010, 1, 1)
3
  • 2
    Be very careful here - you must use the from version, otherwise you may get weirdness if you use datetime.date (or datetime or others). IE - stack depth reached when your fake new calls itself. Commented Aug 17, 2012 at 16:41
  • You won't have that problem if the fake object is in its own module: dpaste.com/790309 . Though, even if it's in the same module as the mocked function, it doesn't import date/datetime itself, it uses the globally-available variable, so there should be no problem: dpaste.com/790310
    – eternicode
    Commented Aug 23, 2012 at 0:12
  • a less brief explanation can be found here: williamjohnbert.com/2011/07/…
    – ezdazuzena
    Commented Aug 8, 2014 at 13:44
18

The easiest way for me is doing this:

import datetime
from unittest.mock import Mock, patch

def test():
    datetime_mock = Mock(wraps=datetime.datetime)
    datetime_mock.now.return_value = datetime.datetime(1999, 1, 1)
    with patch('datetime.datetime', new=datetime_mock):
        assert datetime.datetime.now() == datetime.datetime(1999, 1, 1)

CAUTION for this solution: all functionality from datetime module from the target_module will stop working.

6
  • 1
    This is really nice and concise. The line datetime_mock.now = Mock(return_value=datetime(1999, 1, 1) could even be shortened to datetime_mock.now.return_value = datetime(1999, 1, 1). Instead of starting the patch with start(), consider using the with patch(...): context manager to make sure that datetime behaves regular (unmocked) again when your test ends.
    – Dirk
    Commented Jun 1, 2018 at 16:24
  • Always favor of solution that make use of the built-in library
    – Nam G VU
    Commented Jul 24, 2018 at 8:54
  • @frx08 May I know how to reset this mocking? I mean how to get datetime.datetime.now() unmocked ^^?
    – Nam G VU
    Commented Jul 24, 2018 at 8:55
  • Well after trying to use this mock - one CAUTION for this solution is all functionality from datetime module from the target_module will stop working.
    – Nam G VU
    Commented Jul 24, 2018 at 15:44
  • 2
    Agree @frx08 the with() would subtle the pain. Though inside that block all e.g. date, timedelta will stop working. What if we need now mocked but date math still go on? Sorry, we must have .now() mocked only not the whole datetime module.
    – Nam G VU
    Commented Jul 31, 2018 at 17:48
11

I faced the same situation a couple of days ago, and my solution was to define a function in the module to test and just mock that:

def get_date_now():
    return datetime.datetime.now()

Today I found out about FreezeGun, and it seems to cover this case beautifully

from freezegun import freeze_time
import datetime
import unittest


@freeze_time("2012-01-14")
def test():
    assert datetime.datetime.now() == datetime.datetime(2012, 1, 14)
8

You can use the following approach, based on Daniel G solution. This one has advantage of not breaking type checking with isinstance(d, datetime.date).

import mock

def fixed_today(today):
    from datetime import date

    class FakeDateType(type):
        def __instancecheck__(self, instance):
            return isinstance(instance, date)

    class FakeDate(date):
        __metaclass__ = FakeDateType

        def __new__(cls, *args, **kwargs):
            return date.__new__(date, *args, **kwargs)

        @staticmethod
        def today():
            return today

    return mock.patch("datetime.date", FakeDate)

Basically, we replace C-based datetime.date class with our own python subclass, that produces original datetime.date instances and responds to isinstance() queries exactly as native datetime.date.

Use it as context manager in your tests:

with fixed_today(datetime.date(2013, 11, 22)):
    # run the code under test
    # note, that these type checks will not break when patch is active:
    assert isinstance(datetime.date.today(), datetime.date)

Similar approach can be used to mock datetime.datetime.now() function.

3
  • 1
    I'm not sure this works in Python 2.7. I'm getting a maximum recursion depth RuntimeError with the __instancecheck__ method. Commented Dec 12, 2014 at 22:28
  • 1
    This indeed works in Python 2.7, and it solved my problem with instance type check, thanks! Commented Jul 6, 2017 at 14:54
  • For those who meet the maximum recursion error: the trick is to do the import with from datetime import date inside the fixed_today function exactly as reported in the answer. Just using import datetime leads to the recursion error, not sure why.
    – Valentino
    Commented Nov 19, 2022 at 22:25
8

CPython actually implements the datetime module using both a pure-Python Lib/datetime.py and a C-optimized Modules/_datetimemodule.c. The C-optimized version cannot be patched but the pure-Python version can.

At the bottom of the pure-Python implementation in Lib/datetime.py is this code:

try:
    from _datetime import *  # <-- Import from C-optimized module.
except ImportError:
    pass

This code imports all the C-optimized definitions and effectively replaces all the pure-Python definitions. We can force CPython to use the pure-Python implementation of the datetime module by doing:

import datetime
import importlib
import sys

sys.modules["_datetime"] = None
importlib.reload(datetime)

By setting sys.modules["_datetime"] = None, we tell Python to ignore the C-optimized module. Then we reload the module which causes the import from _datetime to fail. Now the pure-Python definitions remain and can be patched normally.

If you're using Pytest then include the snippet above in conftest.py and you can patch datetime objects normally.

0
6

We can use pytest-mock (https://pypi.org/project/pytest-mock/) mocker object to mock datetime behaviour in a particular module

Let's say you want to mock date time in the following file

# File path - source_dir/x/a.py
import datetime

def name_function():
     name = datetime.now()
     return f"name_{name}"

In the test function, mocker will be added to the function when test runs

def test_name_function(mocker):
     mocker.patch('x.a.datetime')
     x.a.datetime.now.return_value = datetime(2019, 1, 1)

     actual = name_function()

     assert actual == "name_2019-01-01"
1
  • 2
    This is the best answer by far, and easily adaptable to regular mock or unittest.mock (since pytest-mock is just a syntax wrapper around that). Patch the C module itself and then use a series of Mock objects to get the patch you need on functions or attributes.
    – ely
    Commented Sep 25, 2020 at 14:56
4

Generally speaking, you would have datetime or perhaps datetime.date imported into a module somewhere. A more effective way of mocking the method would be to patch it on the module that is importing it. Example:

a.py

from datetime import date

def my_method():
    return date.today()

Then for your test, the mock object itself would be passed as an argument to the test method. You would set up the mock with the result value you want, and then call your method under test. Then you would assert that your method did what you want.

>>> import mock
>>> import a
>>> @mock.patch('a.date')
... def test_my_method(date_mock):
...     date_mock.today.return_value = mock.sentinel.today
...     result = a.my_method()
...     print result
...     date_mock.today.assert_called_once_with()
...     assert mock.sentinel.today == result
...
>>> test_my_method()
sentinel.today

A word of warning. It is most certainly possible to go overboard with mocking. When you do, it makes your tests longer, harder to understand, and impossible to maintain. Before you mock a method as simple as datetime.date.today, ask yourself if you really need to mock it. If your test is short and to the point and works fine without mocking the function, you may just be looking at an internal detail of the code you're testing rather than an object you need to mock.

1
  • I have build on your idea but I am patching my_method like that: date_mock.return_value = datetime.strptime('28 May 2130', '%d %b %Y'). It works like a charm. Thanks Commented Jul 29, 2020 at 16:31
3

Minimal working example with monkeypatch

This solution uses monkeypatch from the https://pypi.org/project/pytest-mock/ package.

Features:

  • mock only datetime.today(), but datetime.now() still works as expected
  • mock only in a specific scope (i.e. block)
import sys
from datetime import datetime

MOCKED_DATETIME_TODAY = datetime(1900, 1, 1, 0, 0, 0)

class MockedDatetime(datetime):
    @classmethod
    def today(cls):
        return MOCKED_DATETIME_TODAY

def test_mock_datetime_today(monkeypatch):
    """Only datetime.today() is mocked and returns some date in 1900. datetime.now() returns still the current date."""
    with monkeypatch.context() as mpc:
        mpc.setattr(sys.modules[__name__], 'datetime', MockedDatetime)
        assert datetime.today() == MOCKED_DATETIME_TODAY  # datetime.today() mocked
        assert datetime.now() > MOCKED_DATETIME_TODAY    # datetime.now() not mocked

    assert datetime.today() > MOCKED_DATETIME_TODAY  # not mocked anymore
2
  • 1
    At last, a solution with only pytest and not some variant of mock or freezegun.
    – NeilG
    Commented Sep 5, 2023 at 9:56
  • 1
    Really like this solution, it's minimally invasive and doesn't have to rely on the shenanigans of the return_value or side_effects of mock Commented Nov 29, 2023 at 13:58
2

It's possible to mock functions from datetime module without adding side_effects

import mock
from datetime import datetime
from where_datetime_used import do

initial_date = datetime.strptime('2018-09-27', "%Y-%m-%d")
with mock.patch('where_datetime_used.datetime') as mocked_dt:
    mocked_dt.now.return_value = initial_date
    do()
2

The best approach for me is a combination of @Daniel G and @frx08 solutions:

class Test_mock_date:
    class NewDate(datetime.datetime):
        @classmethod
        def now(cls, tz=None):
            return cls(2021, 5, 12)

    def test_mock_date(self):
        with patch('datetime.datetime', new = self.NewDate):
            assert datetime.datetime.now() == datetime.datetime(2021, 5, 12, 0, 0)

You can take a look at the following medium article I wrote with different examples about how to use MagicMock https://medium.com/@camposer/d2113513b365

1
  • thx, that worked, and its simple Commented Mar 20 at 9:31
2

For those of you using pytest with pytest-mock (more info on pytest-mock at the end) here is how I mocked datetime.datetime.now() which is very similar to the original question.

test_get_now(mocker):
    datetime_mock = mocker.patch("blackline_accounts_import.datetime",)
    datetime_mock.datetime.now.return_value=datetime.datetime(2019,3,11,6,2,0,0)
    
    now == function_being_tested()  # run function

    assert now == datetime.datetime(2019,3,11,6,2,0,0)

Essentially the mock has to be set to return the specified date. You aren't able to patch over datetime's object directly.

Pytest-mock is a library that makes a mock object a fixture. More detail can be found here

6
  • I believe mocker is from pytest-mock. It might be nice to give a link/explain a bit. Commented Oct 30, 2021 at 12:06
  • Good point! I always install it with pytest, so I never think of them separately. Commented Oct 31, 2021 at 0:01
  • Thanks. I'm a novice with these Python mocks, patches, etc., so I think I have enough to try to understand already with modules unittest, pytest and pytest-qt before I try one day to understand the need for even more tools. Mind you, looking at that page I see it provides a "spy". In the Java/Groovy/Spock universe I tended to use Spy a lot. Although usually seasoned TDD hands seem to say you should probably never ever need a Spy, I always found them very useful. Commented Oct 31, 2021 at 8:27
  • @mikerodent totally get it. It took me a while to even want to try to use them. Pytest-mock is only a thin wrapper around unitest's mocks and the patch functionality. Once you get down the unittest mock pytest-mock removes a bit of boilerplate code - nothing special. I found this very helpful when starting to tackle mocks realpython.com/python-mock-library Commented Nov 2, 2021 at 20:50
  • I'm not sure why this is not working.. even if I add my_module.callable = callable_mock. What could be the problem ? Commented May 27, 2022 at 10:45
0

Maybe you could use your own "today()" method that you will patch where needed. Example with mocking utcnow() can be found here: https://bitbucket.org/k_bx/blog/src/tip/source/en_posts/2012-07-13-double-call-hack.rst?at=default

1
0

I implemented @user3016183 method using a custom decorator:

def changeNow(func, newNow = datetime(2015, 11, 23, 12, 00, 00)):
    """decorator used to change datetime.datetime.now() in the tested function."""
    def retfunc(self):                             
        with mock.patch('mymodule.datetime') as mock_date:                         
            mock_date.now.return_value = newNow
            mock_date.side_effect = lambda *args, **kw: datetime(*args, **kw)
            func(self)
    return retfunc

I thought that might help someone one day...

0

Several solutions are discussed in http://blog.xelnor.net/python-mocking-datetime/. In summary:

Mock object - Simple and efficient but breaks isinstance() checks:

target = datetime.datetime(2009, 1, 1)
with mock.patch.object(datetime, 'datetime', mock.Mock(wraps=datetime.datetime)) as patched:
    patched.now.return_value = target
    print(datetime.datetime.now())

Mock class

import datetime
import mock

real_datetime_class = datetime.datetime

def mock_datetime_now(target, dt):
    class DatetimeSubclassMeta(type):
        @classmethod
        def __instancecheck__(mcs, obj):
            return isinstance(obj, real_datetime_class)

    class BaseMockedDatetime(real_datetime_class):
        @classmethod
        def now(cls, tz=None):
            return target.replace(tzinfo=tz)

        @classmethod
        def utcnow(cls):
            return target

    # Python2 & Python3 compatible metaclass
    MockedDatetime = DatetimeSubclassMeta('datetime', (BaseMockedDatetime,), {})

    return mock.patch.object(dt, 'datetime', MockedDatetime)

Use as:

with mock_datetime_now(target, datetime):
   ....
0

I made this work by importing datetime as realdatetime and replacing the methods I needed in the mock with the real methods:

import datetime as realdatetime

@mock.patch('datetime')
def test_method(self, mock_datetime):
    mock_datetime.today = realdatetime.today
    mock_datetime.now.return_value = realdatetime.datetime(2019, 8, 23, 14, 34, 8, 0)
0

You can mock datetime using this:

In the module sources.py:

import datetime


class ShowTime:
    def current_date():
        return datetime.date.today().strftime('%Y-%m-%d')

In your tests.py:

from unittest import TestCase, mock
import datetime


class TestShowTime(TestCase):
    def setUp(self) -> None:
        self.st = sources.ShowTime()
        super().setUp()

    @mock.patch('sources.datetime.date')
    def test_current_date(self, date_mock):
        date_mock.today.return_value = datetime.datetime(year=2019, month=10, day=1)
        current_date = self.st.current_date()
        self.assertEqual(current_date, '2019-10-01')
2
  • 1
    what is sources in your patch decorator?
    – elena
    Commented Jun 30, 2020 at 17:58
  • Dear @elena, it is rather hard to remember what I was thinking about almost one year ago)). I guess I meant just any module of our app sources - just the code of your application.
    – MTMobile
    Commented Jul 4, 2020 at 12:04
0

For those using patchers in a test class, here's how I'm successfully patching datetime functionality:

from datetime import datetime
import unittest
from unittest.mock import Mock, patch

# Replace with the proper path to the module you would
# like datetime to be mocked
from path.to.my_module

class MyTestCases(unittest.TestCase):

    def setUp(self):
        """execute on class instantiation"""
        # Record both times at the same moment
        self.dt_now, self.dt_utcnow = datetime.now(), datetime.utcnow()

        # After retrieving real (or hardcoded datetime values), 
        # proceed to mock them in desired module
        self.patch_datetime_functions()


    def patch_datetime_functions(self) -> None:
        """
        Patch datetime.now() and datetime.utcnow() to prevent issues when
        comparing expected dates
        """

        # Create a patcher
        self.patcher_dt = patch(
            'path.to.my_module'
        )

        # Start but make sure cleanup always occurs
        self.patcher_dt.start()
        self.addCleanup(self.patcher_dt.stop)

        # Perform the actual patch – use lambdas as mock functions
        datetime_mock = Mock(wraps=datetime)
        datetime_mock.now.return_value = self.dt_now
        datetime_mock.utcnow.return_value = self.dt_utcnow

        my_module.datetime = datetime_mock


    # Here's what it will look like when testing:
    def some_test(self):
        curr_dt = self.dt_now
        returned_dt = my_module.datetime.utcnow()
        
        # Compare the dates
        self.assertEqual(curr_dt, returned_dt,
            'Datetime values should be equal'
        )

0

You can use time-machine library. I found it easy to use. It's originally inspired by freezegun (already mentioned in the answers) which is great and popular solution, but time-machine is faster.

Installation: python -m pip install time-machine

Example:

import datetime as dt
import time_machine

@time_machine.travel("2024-01-01 12:00")
def test_date():
    assert dt.datetime.now() ==  dt.datetime(2024, 1, 1, 12)

It also works as a pytest plugin

import datetime as dt

def test_date(time_machine):
    time_machine.move_to(dt.datetime(2024, 1, 1, 12))
    assert dt.date.today().isoformat() == "2024-01-01"

You can also bypass time-machine using escape_hatch

import datetime as dt
import time_machine

@time_machine.travel("2024-01-01 12:00", tick=False)
def test_date():
    print(dt.datetime.now())
    assert dt.datetime.now() ==  dt.datetime(2024, 1, 1, 12)

    real_now = time_machine.escape_hatch.datetime.datetime.now()
    print(real_now)
    assert real_now > dt.datetime.now()

# Print output (second will change base on your current datetime):
# 2024-01-01 12:00:00
# 2024-11-08 10:28:58.953853

And there are more features including a context manager, shift method and other parameters. If you come from libfaketime or freezegun you can check the migration paragraph.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.