In some of my tests I am having a problem that they fail on Travis because of time and time zone problems, so I want to mock system time for my test. How can I do this?
Asked
Active
Viewed 2.8k times
28
-
2What time function do you want to mock? If it's the Python datetime, it's a little tricky as explained [here](http://stackoverflow.com/questions/4481954/python-trying-to-mock-datetime-date-today-but-not-working) – Seb D. Jun 02 '14 at 08:00
-
1I want to do this for all modules. I think the freezegun example works in the link you gave. Thanks! – adarsh Jun 02 '14 at 08:11
4 Answers
39
@Brian-Kruger's answer is the best one. I've voted to undelete it. In the meantime...
From the README:
from freezegun import freeze_time
@freeze_time("2012-01-14")
def test():
assert datetime.datetime.now() == datetime.datetime(2012, 1, 14)

Jason R. Coombs
- 41,115
- 10
- 83
- 93
-
This answer is a lot more suitable for SO than the deleted one, thanks for re-posting it – scrowler Jul 18 '22 at 20:55
28
AFAIK, you can't mock builtin methods.
One approach I have often done is to change my code a bit to not use datetime
directly to obtain the date, but a wrapper function somewhere:
# mymodule.py
def get_today():
return datetime.date.today()
This makes it trivial to just mock
it in your test:
def test_something():
with mock.patch('mymodule.get_today', return_value=datetime.date(2014, 6, 2)):
...
You can also use the freezegun module.

Bruno Oliveira
- 13,694
- 5
- 43
- 41
-
-
As mentioned, this gives `TypeError: can't set attributes of built-in/extension type 'datetime.datetime'` on Python 2 and 3. – Bruno Oliveira Dec 22 '16 at 02:17
-
1Ah, yes. You have to replace the complete class `datetime`. You can inherit from datetime and override the methods you need. But `freezetime` works perfectly. – MaxNoe Dec 22 '16 at 07:54
-
I think that the idea of a wrapper function is the best answer given across every thread I've found because it is agnostic to unit testing libraries so it will always work. – Andrew Samuelson Aug 22 '21 at 21:14
18
There are two ways you can accomplish that:
Create function which you will call instead of
datetime.datetime.now()
as suggested by Bruno, but here is different implementation:import os import datetime def mytoday(): if 'MYDATE' in os.environ: return datetime.datetime.strptime(os.getenv('MYDATE'), '%m-%d-%Y').date() else: return datetime.date.today()
Then, in your test, you just monkeypatch environment variable:
import datetime def test_patched_date(monkeypatch): monkeytest.setenv('MYDATE', '05-31-2014') assert datetime.date.today() == datetime.date(2014, 5, 31)
Monkeypatch the
datetime
function:import datetime import pytest FAKE_TIME = datetime.datetime(2020, 12, 25, 17, 05, 55) @pytest.fixture def patch_datetime_now(monkeypatch): class mydatetime: @classmethod def now(cls): return FAKE_TIME monkeypatch.setattr(datetime, 'datetime', mydatetime) def test_patch_datetime(patch_datetime_now): assert datetime.datetime.now() == FAKE_TIME

sashk
- 3,946
- 2
- 33
- 41
-
is the indentation correct or something missing? after "def patch_datetime_now(monkeypatch): " there is no indented block. maybe at least add a comment in this code line, it confuses some people like me – SHernandez Jun 09 '15 at 12:08
-
For the second suggestion, if the module under test loads the datetime before patching (e.g. `from datetime import datetime`), it will hold an instance to the old datetime and not `mydatetime`. – Tim Diels Dec 14 '15 at 21:56
-
2I now realise I was referring to [this gotcha](http://www.voidspace.org.uk/python/mock/patch.html#where-to-patch) of patching. So, if the module under test (mut.py) imports datetime before you get to patch `datetime.datetime`, patch `mut.datetime` instead. – Tim Diels Dec 14 '15 at 22:42
3
I prefer to use this code.
from unittest.mock import MagicMock
@pytest.fixture
def mocking_datetime_now(monkeypatch):
datetime_mock = MagicMock(wrap=datetime.datetime)
datetime_mock.now.return_value = datetime.datetime(2020, 3, 11, 0, 0, 0)
monkeypatch.setattr(datetime, "datetime", datetime_mock)
@pytest.fixture
def setup_db(company, company_user, mocking_datetime_now):
assert datetime.datetime.now() == datetime.datetime(2020, 3, 11, 0, 0, 0)

Ehsan
- 3,711
- 27
- 30
-
Trying to use this, but from `conftest.py`. Yeah, I add it to the test parameters `def test_foo(mocking_datetime_now)`, but then what? – tim.rohrer Feb 05 '23 at 01:13
-
For my situation, I'm realizing now for my situation, mocking the entire class is problematic since I need to use `strptime` elsewhere. – tim.rohrer Feb 05 '23 at 01:45