Unexpected strftime() behaviour on Python and macOS

Question:

I’m obtaining inconsistent behaviour with the output of datetime.strftime().

I’m using macOS Sierra 10.12.6 and Python 3.6.2. I have a Python program, named wut.py, that is

#!/usr/bin/python
from datetime import datetime
import locale
if __name__ == "__main__":
    print(locale.getlocale())
    print(datetime.today().strftime('%c'))

In a terminal, I write

$ date
Gio 24 Ago 2017 18:54:01 CEST

which is the Italian way of writing dates. Then

$ python3 ~/Desktop/wut.py 
('it_IT', 'UTF-8')
Thu Aug 24 18:54:03 2017

where the date and time are written in another locale. How is this happening? Is this a bug or is there any reason for this behaviour?

I’m puzzled because the Python docs mention that %c refers to “Locale’s appropriate date and time representation.”, so I thought that the system’s locale is the “appropriate” one 😉 (see https://docs.python.org/3/library/datetime.html, sec 8.1.8)

Asked By: LordM'zn

||

Answers:

The Python result is correct. strftime('%c') returns same result format.

Answered By: Dharmesh Fumakiya

Digging into the locale module a bit, I find this under the description of getdefaultlocale():

According to POSIX, a program which has not called
setlocale(LC_ALL, “”) runs using the portable ‘C’ locale.
Calling setlocale(LC_ALL, “”) lets it use the default locale as
defined by the LANG variable. Since we don’t want to interfere
with the current locale setting we thus emulate the behavior
in the way described above.

From this, I gather it is good practice to call

locale.setlocale(locale.LC_ALL, '')

to set your locale to the one you expect to inherit from the caller’s evironment. Do that, and you should get the expected output from strftime.


That said, I noticed a difference in behavior between Python 2.7 and Python 3.6 on my macOS 10.12 installation. On startup, locale.getdefaultlocale() and locale.getlocale() both return ('en_US', 'UTF-8') in Python 3. In Python 2, though, getlocale() returns (None, None) until I call setlocale. In either case, the call to setlocale is still required for strftime to actually use the set locale, rather than the default C locale. I do not know if this represents a bug, or if so, which one is the buggy instance.

Answered By: chepner

There are a number of different locale categories that are all configured independently, and locale.getlocale() only gets you the settting of the LC_CTYPE category. Time formatting is controlled by the LC_TIME category, which you can check with locale.getlocale(locale.LC_TIME).

You can use locale.setlocale(locale.LC_ALL, '') to set the settings for all locale categories to the user’s default settings (typically specified in the LANG environment variable). setlocale isn’t threadsafe, so this usually goes near the start of a program.

Answered By: user2357112