R Sahu
R Sahu

Reputation: 206607

Why datetime.now() and datetime.today() show time in UTC and not local time on my PC?

datetime.now() and datetime.today() return time in UTC on my computer even though the documentation says they should return local time.

Here's the script I ran:

#!/usr/bin/python

import time
import datetime

if __name__ == "__main__":
   print(datetime.datetime.now())
   print(datetime.datetime.today())
   print(datetime.datetime.fromtimestamp(time.time()))

and here's the output:

2017-11-29 22:47:35.339914
2017-11-29 22:47:35.340399
2017-11-29 22:47:35.340399

The output of running date right after it is:

Wed, Nov 29, 2017  3:47:43 PM

Why is my installation returning time in UTC?
What can I do get those functions to return local time?

PS We are in MST, which is UTC-7.

PS 2 I realize there are methods to convert a UTC time to local time, such as those explained in Convert a python UTC datetime to a local datetime using only python standard library?. However, I am trying to understand the cause of the fundamental problem and not looking for a method to patch the problem in my own code.


In response to comment by @jwodder:

The output of executing

print(time.altzone)
print(time.timezone)
print(time.tzname)

is:

-3600
0
('Ame', 'ric')

Upvotes: 13

Views: 3478

Answers (3)

oxer
oxer

Reputation: 1145

I think there is some odd behavior going on with things using the glibc time and timezone libraries on Windows. I started noticing this behavior in both python and emacs recently.

The best thing to do is probably to set TZ to the "ugly" version described in the best answer as that seems to fix issues in python and emacs and works correctly in cygwin as well.

Another workaround I tried is to make sure the TZ environment variable is NOT set. The following illustrates the problem around 10:18 New York time in python. I get similar results using either cygwin or CMD on Windows. Emacs illustrates the same problem using the current-time-string function suggesting it is a glibc issue or at least some library which both python and emacs are using. Interestingly the date command in cygwin gives the correct result with TZ set to "America/New York" but incorrect if TZ is unset.

Summary: some things (e.g., python, emacs) on Windows seem to not accept "America/New_York" for TZ while some things (e.g., cygwin) do accept it. Using something like EST+05EDT,M4.1.0,M10.5.0 for eastern time (or appropriate ugly equivalent) works.

$ echo $TZ
America/New_York

$ python -i
Python 3.6.4 |Anaconda, Inc.| (default, Jan 16 2018, 10:22:32) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import datetime
>>> datetime.datetime.now()
datetime.datetime(2018, 5, 14, 15, 38, 6, 174073)
>>> datetime.datetime.now()
datetime.datetime(2018, 5, 14, 15, 38, 57, 141708)
>>> quit()

$ export TZ=

$ python -i
Python 3.6.4 |Anaconda, Inc.| (default, Jan 16 2018, 10:22:32) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import datetime
>>> datetime.datetime.now()
datetime.datetime(2018, 5, 14, 10, 38, 41, 102117)

Upvotes: 1

Nathan Vērzemnieks
Nathan Vērzemnieks

Reputation: 5603

As you note in your answer, the TZ environment variable is the key here. On unix-type systems, this supports more "friendly" values like "US/Pacific" or, indeed, "America/Denver", but on Windows, it doesn't. Although it's not available on Windows, the documentation for the time.tzset function describes the format you'll need to set TZ in to get what you want. It's... not pretty. But it works:

C:\Users\zorb>set TZ=MST+07MDT,M3.2.0,M11.1.0
C:\Users\zorb>python.exe
>>> import time
>>> time.tzname
('MST', 'MDT')
>>> import datetime
>>> datetime.datetime.now()
datetime.datetime(2018, 2, 9, 16, 27, 7, 164062)

(This was at 15:27 in Pacific time.) The structure of this format is:

  • Standard time abbrevation (MST)
  • UTC offset of standard time, in hours (+07)
  • Daylight time abbreviation
  • When daylight time starts (see below)
  • When daylight time ends (see below)

The format for the start and end of daylight time is:

  • M (for "month-based")
  • Month number - 3/March or 11/November, in this case.
  • Week of the month - 1 through 5, meaning the 1st through 5th occurrence of the day named below.
  • Day of the week - 0 for Sunday through 6 for Saturday

There are also options to specify the time at which daylight time starts and ends (but it defaults to 02:00:00, so unnecessary in this case) and the offset for daylight time (but it defaults to 1 hour, so also not necessary).

(edit) Turns out this is actually a glibc feature, not directly a python one. More detailed info in the glibc docs.

Upvotes: 6

R Sahu
R Sahu

Reputation: 206607

Initially, it appeared to be a problem caused by the use of cygwin.

The question at Cygwin shows UTC time instead of local time helped further isolate the problem to the value of the environment variable TZ in cygwin.

The updated script:

import time
import datetime

if __name__ == "__main__":
   print(datetime.datetime.now())
   print(datetime.datetime.today())
   print(datetime.datetime.fromtimestamp(time.time()))
   print(time.altzone)
   print(time.timezone)
   print(time.tzname)

Output when run under a Windows CMD shell with, where TZ is not set:

"D:\Program Files\Python35\python.exe" test.py
2017-11-30 09:39:47.236798
2017-11-30 09:39:47.236799
2017-11-30 09:39:47.236799
21600
25200
('Mountain Standard Time', 'Mountain Daylight Time')

Output when run under a cygwin bash shell with, where TZ is set to "America/Denver":

 /cygdrive/D/Program\ Files/Python35/python.exe test.py
2017-11-30 16:39:45.419884
2017-11-30 16:39:45.419884
2017-11-30 16:39:45.419884
-3600
0
('Ame', 'ric')

It's set to "America/Denver". When I executed

env TZ="" /cygdrive/D/Program\ Files/Python35/python.exe test.py

I got a more sensible output:

2017-11-30 09:56:08.643368
2017-11-30 09:56:08.643368
2017-11-30 09:56:08.643368
21600
25200
('Mountain Standard Time', 'Mountain Daylight Time')

When I set the environment variable TZ to "America/Denver" in the windows CMD shell, I get the same output as when run in the cygwin shell.

It's not clear to me how Python uses the environment variable TZ and what the correct values are for it.

Upvotes: 2

Related Questions