{"record":{"id":"9b2ea74e4461e5db","repo":"python/cpython","slug":"timezone-changed-during-initialization","errorCode":null,"errorMessage":"timezone changed during initialization","messagePattern":"timezone changed during initialization","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"Lib/_strptime.py","lineNumber":117,"sourceCode":"        running.  The check here is done in case someone does not think about\n        doing this.\n\n        Only other possible issue is if someone changed the timezone and did\n        not call tz.tzset .  That is an issue for the programmer, though,\n        since changing the timezone is worthless without that call.\n\n        \"\"\"\n        self.lang = _getlang()\n        self.__calc_weekday()\n        self.__calc_month()\n        self.__calc_am_pm()\n        self.__calc_alt_digits()\n        self.__calc_timezone()\n        self.__calc_date_time()\n        if _getlang() != self.lang:\n            raise ValueError(\"locale changed during initialization\")\n        if time.tzname != self.tzname or time.daylight != self.daylight:\n            raise ValueError(\"timezone changed during initialization\")\n\n    def __calc_weekday(self):\n        # Set self.a_weekday and self.f_weekday using the calendar\n        # module.\n        a_weekday = [calendar.day_abbr[i].lower() for i in range(7)]\n        f_weekday = [calendar.day_name[i].lower() for i in range(7)]\n        self.a_weekday = a_weekday\n        self.f_weekday = f_weekday\n\n    def __calc_month(self):\n        # Set self.f_month and self.a_month using the calendar module.\n        a_month = [calendar.month_abbr[i].lower() for i in range(13)]\n        f_month = [calendar.month_name[i].lower() for i in range(13)]\n        self.a_month = a_month\n        self.f_month = f_month\n\n    def __calc_am_pm(self):\n        # Set self.am_pm by using time.strftime().","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/_strptime.py#L99-L135","documentation":"Raised by _strptime.LocaleTime.__init__ after it finishes computing cached locale tables (weekday/month names, AM/PM, timezone data). At the end it re-reads time.tzname and time.daylight and compares them to the values captured at the start; if they differ, the cached tables would be inconsistent, so a ValueError is raised. It is a concurrency/environment-consistency guard, not a user-input error.","triggerScenarios":"Another thread calls time.tzset() (or sets os.environ['TZ'] followed by tzset) while a strptime() call is rebuilding the _TimeRE_cache (e.g. first strptime call after locale/TZ change, or after cache invalidation because _getlang()/time.tzname/time.daylight no longer match the cache).","commonSituations":"Multithreaded servers or test suites where one thread changes the TZ environment variable or locale while other threads parse datetime strings with time.strptime or datetime.datetime.strptime; rare race on first use after a TZ change.","solutions":["Set the TZ environment variable and call time.tzset() once at process startup, before spawning worker threads that call strptime","Retry the strptime() call once in an except ValueError block to let the cache rebuild consistently","Serialize TZ/locale changes and strptime use behind a lock","Pass explicit tz-aware parsing (e.g. fromisoformat or dateutil) instead of relying on the process timezone"],"exampleFix":"# before\nos.environ['TZ'] = 'UTC'  # racing with strptime in other threads\ntime.tzset()\n\n# after\nos.environ['TZ'] = 'UTC'\ntime.tzset()  # do once at startup, before threads start parsing","handlingStrategy":"retry","validationCode":"def safe_strptime(s, fmt, retries=2):\n    for i in range(retries + 1):\n        try:\n            return _strptime_time(s, fmt)\n        except ValueError as e:\n            if 'changed during initialization' in str(e) and i < retries:\n                continue\n            raise","typeGuard":null,"tryCatchPattern":"try:\n    t = time.strptime(data, fmt)\nexcept ValueError as e:\n    if 'changed during initialization' in str(e):\n        t = time.strptime(data, fmt)  # cache rebuilt consistently on 2nd call\n    else:\n        raise","preventionTips":["Set TZ and call time.tzset() once at startup before threads begin parsing","Never mutate os.environ['TZ'] from worker threads while parsing is in flight","Pin parsing to explicit offsets (%z) instead of the process timezone"],"tags":["strptime","timezone","race-condition","locale","cpython"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}