I have a date object in python and I need to generate a time stamp in the C locale for a legacy system, using the %a (weekday) and %b (month) codes. However I do not wish to change the application's locale, since other parts need to respect the user's current locale. Is there a way to call strftime() with a certain locale?
3 Answers
The example given by Rob is great, but isn't threadsafe. Here's a version that works with threads:
import locale
import threading
from datetime import datetime
from contextlib import contextmanager
LOCALE_LOCK = threading.Lock()
@contextmanager
def setlocale(name):
with LOCALE_LOCK:
saved = locale.setlocale(locale.LC_ALL)
try:
yield locale.setlocale(locale.LC_ALL, name)
finally:
locale.setlocale(locale.LC_ALL, saved)
# Let's set a non-US locale
locale.setlocale(locale.LC_ALL, 'de_DE.UTF-8')
# Example to write a formatted English date
with setlocale('C'):
print(datetime.now().strftime('%a, %b')) # e.g. => "Thu, Jun"
# Example to read a formatted English date
with setlocale('C'):
mydate = datetime.strptime('Thu, Jun', '%a, %b')
It creates a threadsafe context manager using a global lock and allows you to have multiple threads running locale-dependent code by using the LOCALE_LOCK. It also handles exceptions from the yield statement to ensure the original locale is always restored.

- 8,212
- 2
- 43
- 36
-
3Note that for setlocale() to succeed, you need that locale installed at the system level. Which, generally speaking, you cannot rely on. For anything that means to be localizable, you need to stay away from strftime, and use a proper i18n library, like Babel. – ddaa Aug 20 '14 at 17:22
-
is that a typo on `saved = locale.setlocale(...` ? – vonPetrushev Oct 20 '14 at 18:57
-
I don't believe there's a typo - if the second argument to setlocale is None then you get the currently set locale returned. – Daniel Oct 20 '14 at 22:53
-
1@ddaa: Thanks for that suggestion. Indeed, one can't rely on those being installed, even if you live in the country for which you're trying to use the locale. Babel is really the way to go, and this should be a separate answer. – WhyNotHugo Mar 15 '15 at 13:02
-
Will it still `yield` if `setlocale` throws? Wouldn't this mess with the `with` construct? (like premature `StopIteration` raised etc.) (And BTW - cool answer, with a lot going on in there. I thought the problem "locale is per process" could not be dispatched so easy.) – Tomasz Gandor Apr 25 '16 at 11:14
-
Doesn't this just block other threads from also setting the locale at the same time? It does nothing to help isolate the global change from affecting other locale-aware code that doesn't use this construct. most wouldn't since it would normally just use the locale setup at the beginning of the program. Or am I missing something? – altendky Apr 07 '21 at 03:39
No, there is no way to call strftime()
with a specific locale.
Assuming that your app is not multi-threaded, save and restore the existing locale, and set your locale to 'C'
when you invoke strftime
.
#! /usr/bin/python3
import time
import locale
def get_c_locale_abbrev():
lc = locale.setlocale(locale.LC_TIME)
try:
locale.setlocale(locale.LC_TIME, "C")
return time.strftime("%a-%b")
finally:
locale.setlocale(locale.LC_TIME, lc)
# Let's suppose that we're french
locale.setlocale(locale.LC_ALL, 'fr_FR.utf8')
# Should print french, english, then french
print(time.strftime('%a-%b'))
print(get_c_locale_abbrev())
print(time.strftime('%a-%b'))
If you prefer with:
to try:
-finally:
, you could whip up a context manager:
#! /usr/bin/python3
import time
import locale
import contextlib
@contextlib.contextmanager
def setlocale(*args, **kw):
saved = locale.setlocale(locale.LC_ALL)
yield locale.setlocale(*args, **kw)
locale.setlocale(locale.LC_ALL, saved)
def get_c_locale_abbrev():
with setlocale(locale.LC_TIME, "C"):
return time.strftime("%a-%b")
# Let's suppose that we're french
locale.setlocale(locale.LC_ALL, 'fr_FR.utf8')
# Should print french, english, then french
print(time.strftime('%a-%b'))
print(get_c_locale_abbrev())
print(time.strftime('%a-%b'))

- 163,533
- 20
- 239
- 308
-
-
Yes, `locale.setlocale()` affects the entire program. The `try-finally` block or the `with` block sets and restores the locale so as not to disturb the rest of the program. – Robᵩ Sep 03 '13 at 14:22
take a look to the pytz package
you can use like this
import pytz
UTC = pytz.timezone('UTC') # utc
fr = pytz.timezone('Europe/Paris') #your local
from datetime import datetime
date = datetime.now(fr)
dateUTC = date.astimezone(UTC)
strftime will render in the timezone specified
for have month name in the locale use calendar for example :
import calendar
print calendar.month_name[dateUTC.month] #will print in the locale
inspect more deeply calendar for having more information

- 1,182
- 7
- 11
-
That's interesting, but I need to generate a date stamp with English words for weekdays (%a) and months (%b), not change the timezone. Can pytz do that too? – MagerValp Sep 03 '13 at 13:43
-
take a look to calendar http://docs.python.org/2/library/calendar.html#module-calendar and the calendar.month_name method perhaps – Philippe T. Sep 03 '13 at 13:47
-
Again, it's not what OP wants. `calendar.month_name` An array that represents the months of the year in the current locale. – Dima Tisnek Mar 11 '15 at 12:14