12

I'm puzzled why a function that freezes time with freezegun outputs different UTC times depending on whether datetime.datetime.utcnow() is called, or datetime.datetime.now(pytz.utc). I'm not saying it's broken, just that I don't understand why, and would like to know!

eg, using this function:

@freeze_time("2012-01-14 03:21:34", tz_offset=-4)
def test():
    print("utcnow(): %s" % datetime.datetime.utcnow())
    print("pytz.utc: %s" % datetime.datetime.now(pytz.utc))

the output is:

utcnow(): 2012-01-14 03:21:34
pytz.utc: 2012-01-13 23:21:34+00:00

I guess the first is a naive datetime, but why are they different times?

(Ultimately why I want to know: if I'm using freezegun in my tests, and I use pytz to generate times in my code being tested, I want to know what its 'correct' behaviour should be.)

azmeuk
  • 4,026
  • 3
  • 37
  • 64
Phil Gyford
  • 13,432
  • 14
  • 81
  • 143
  • Isn't that correct considering `tz_offset=-4` ? One is aware the other is naive – Padraic Cunningham Jul 02 '15 at 20:14
  • I don't know, that's why I'm asking :) I assumed that given you can set a timezone offset with freezegun, and you're asking for UTC from each, that they would both have the same time. Even if only one had the timezone attached. – Phil Gyford Jul 02 '15 at 20:17
  • I mean, if you output `datetime.datetime.now()` in that function you get `2012-01-13 23:21:34`. Is freezegun freezing the time to 2012-01-14 03:21 UTC or 2012-01-13 23:21 UTC? – Phil Gyford Jul 02 '15 at 20:21
  • Using now the date and time are converted to the tz‘s time zone. utcnow is gmt – Padraic Cunningham Jul 02 '15 at 20:38
  • So you're saying: freezegun is setting the time to 2012-01-14 03:21 UTC, and timezone to -4 hrs. `datetime.datetime.now()` is the local time (ie, 2012-01-13 23:21) and I'm artificially forcing that time to have UTC timezone info? – Phil Gyford Jul 02 '15 at 20:46
  • Yes `2012-01-13 23:21)` is the local time, it is also shown in the docs under timezones https://github.com/spulec/freezegun although the assert would fail for datetime.today because the time is not in datetime.today so it would be `00:00:00` for `datetime.datetime(2012, 01, 13)`. If you use `assert datetime.date.today() == datetime.datetime(2012, 01, 13).date()` it should pass – Padraic Cunningham Jul 02 '15 at 20:48
  • No worries, datetimes can be confusing at the best of times, the fact the assertion fails in the docs would not help. – Padraic Cunningham Jul 02 '15 at 21:06
  • [According to the docs](https://github.com/spulec/freezegun#timezones), the 2nd one should show: `2012-01-14 03:21:34+00:00`. `23:21:34+00:00` looks like a bug. – jfs Jul 02 '15 at 21:46
  • @J.F.Sebastian, why should it be `03:21:34+00:00`? – Padraic Cunningham Jul 02 '15 at 22:33
  • @PadraicCunningham: what is unclear? Do you understand that `utcnow() == now(pytz.utc).replace(tzinfo=None)`? – jfs Jul 02 '15 at 22:36
  • @J.F.Sebastian,I thought you were referring to the example in the docs, so basically in the OPs code `pytz.utc` is being ignored? – Padraic Cunningham Jul 02 '15 at 23:03
  • I *think* that applying `pytz.utc` like that doesn't affect the calculation of the time value - it simply takes the time that `now()` generated and gives it the UTC timezone, without actually *changing* the time. I may be wrong, but that's what I'm assuming is happening. So the docs are correct. – Phil Gyford Jul 03 '15 at 08:46
  • @PadraicCunningham: click the link in my comment: it shows the example from the docs that asserts that `utcnow() == 03:21:34` and therefore `now(pytz.utc)` must be `03:21:34+00:00`. – jfs Jul 03 '15 at 12:03

1 Answers1

5

This is an issue within freezegun see here and here.

It does not look like that this will be fixed soon. In the end I used this as a workaround:

def freezegun_utc_workaround():
    return datetime.utcnow().replace(tzinfo=pytz.utc)

For this

 datetime.datetime.now(pytz.utc)

May be it is even better to wrap this and patch it manually.

crasu
  • 195
  • 3
  • 12
  • 1
    How did you use this? Can you include a full code sample? – spacether Jun 15 '22 at 18:28
  • Replace all occurances of "datetime.datetime.now(pytz.utc)" with "freezegun_utc_workaround()". After that use "patch" from "unittest.mock" to make "freezegun_utc_workaround" return whatever you desire. – crasu Jun 16 '22 at 15:26