What I learned recently is the way Python strptime deals with this. It only parses the current time zone or "GMT" or "UTC" and all have the same effect (of returning a tz-naive object). This behavior is amazing because I don't think it's ever what you want.
$ TZ=Asia/Shanghai python -c "import datetime; print(datetime.datetime.strptime('4CST', '%H%Z').astimezone(datetime.timezone.utc))"
1899-12-31 19:54:17+00:00
$ TZ=America/Chicago python -c "import datetime; print(datetime.datetime.strptime('4CST', '%H%Z').astimezone(datetime.timezone.utc))"
1900-01-01 10:00:00+00:00
$ TZ=America/Havana python -c "import datetime; print(datetime.datetime.strptime('4CST', '%H%Z').astimezone(datetime.timezone.utc))"
1900-01-01 09:29:36+00:00
$ TZ=America/Havana python -c "import datetime; print(datetime.datetime.strptime('4CDT', '%H%Z').astimezone(datetime.timezone.utc))"
1900-01-01 09:29:36+00:00
$ TZ=America/Los_Angeles python -c "import datetime; print(datetime.datetime.strptime('4CST', '%H%Z').astimezone(datetime.timezone.utc))"
ValueError: time data '4CST' does not match format '%H%Z'
That last error was real fun to debug when something worked in production but not locally.