|
2 | 2 |
|
3 | 3 | import contextlib |
4 | 4 | import os |
5 | | -import re |
6 | 5 | import sys |
7 | 6 | import warnings |
8 | 7 |
|
@@ -158,63 +157,26 @@ def _get_darwin_timezone() -> Timezone: |
158 | 157 |
|
159 | 158 |
|
160 | 159 | def _get_unix_timezone(_root: str = "/") -> Timezone: |
161 | | - tzenv = os.environ.get("TZ") |
162 | | - if tzenv: |
| 160 | + if tzenv := os.environ.get("TZ"): |
163 | 161 | with contextlib.suppress(ValueError): |
164 | 162 | return _tz_from_env(tzenv) |
165 | 163 |
|
166 | | - # Now look for distribution specific configuration files |
167 | | - # that contain the timezone name. |
168 | | - tzpath = Path(_root) / "etc" / "timezone" |
169 | | - if tzpath.is_file(): |
170 | | - tzfile_data = tzpath.read_bytes() |
171 | | - # Issue #3 was that /etc/timezone was a zoneinfo file. |
172 | | - # That's a misconfiguration, but we need to handle it gracefully: |
173 | | - if not tzfile_data.startswith(b"TZif2"): |
174 | | - etctz = tzfile_data.strip().decode() |
175 | | - # Get rid of host definitions and comments: |
176 | | - etctz, _, _ = etctz.partition(" ") |
177 | | - etctz, _, _ = etctz.partition("#") |
178 | | - return Timezone(etctz.replace(" ", "_")) |
179 | | - |
180 | | - # CentOS has a ZONE setting in /etc/sysconfig/clock, |
181 | | - # OpenSUSE has a TIMEZONE setting in /etc/sysconfig/clock and |
182 | | - # Gentoo has a TIMEZONE setting in /etc/conf.d/clock |
183 | | - # We look through these files for a timezone: |
184 | | - zone_re = re.compile(r'\s*(TIME)?ZONE\s*=\s*"([^"]+)?"') |
185 | | - |
186 | | - for filename in ("etc/sysconfig/clock", "etc/conf.d/clock"): |
187 | | - tzpath = Path(_root) / filename |
188 | | - if tzpath.is_file(): |
189 | | - data = tzpath.read_text().splitlines() |
190 | | - for line in data: |
191 | | - # Look for the ZONE= or TIMEZONE= setting. |
192 | | - match = zone_re.match(line) |
193 | | - if match: |
194 | | - etctz = match.group(2) |
195 | | - parts = list(reversed(etctz.replace(" ", "_").split(os.path.sep))) |
196 | | - tzpath_parts: list[str] = [] |
197 | | - while parts: |
198 | | - tzpath_parts.insert(0, parts.pop(0)) |
199 | | - with contextlib.suppress(InvalidTimezone): |
200 | | - return Timezone(os.path.sep.join(tzpath_parts)) |
201 | | - |
202 | | - # systemd distributions use symlinks that include the zone name, |
203 | | - # see manpage of localtime(5) and timedatectl(1) |
204 | | - tzpath = Path(_root) / "etc" / "localtime" |
205 | | - if tzpath.is_file() and tzpath.is_symlink(): |
206 | | - parts = [p.replace(" ", "_") for p in reversed(tzpath.resolve().parts)] |
207 | | - tzpath_parts: list[str] = [] # type: ignore[no-redef] |
208 | | - while parts: |
209 | | - tzpath_parts.insert(0, parts.pop(0)) |
210 | | - with contextlib.suppress(InvalidTimezone): |
211 | | - return Timezone(os.path.sep.join(tzpath_parts)) |
| 164 | + localtime = Path(_root) / "etc" / "localtime" |
212 | 165 |
|
213 | | - # No explicit setting existed. Use localtime |
214 | | - for filename in ("etc/localtime", "usr/local/etc/localtime"): |
215 | | - tzpath = Path(_root) / filename |
216 | | - if tzpath.is_file(): |
217 | | - with tzpath.open("rb") as f: |
| 166 | + # Symlink → IANA name |
| 167 | + if localtime.is_symlink() and localtime.is_file(): |
| 168 | + parts = [p.replace(" ", "_") for p in localtime.resolve().parts] |
| 169 | + for i in range(1, len(parts) + 1): |
| 170 | + with contextlib.suppress(InvalidTimezone): |
| 171 | + return Timezone(os.path.sep.join(parts[-i:])) |
| 172 | + |
| 173 | + # Fallback: read tzfile data |
| 174 | + for tzfile in ( |
| 175 | + localtime, |
| 176 | + Path(_root) / "usr/local/etc/localtime", |
| 177 | + ): |
| 178 | + if tzfile.is_file(): |
| 179 | + with tzfile.open("rb") as f: |
218 | 180 | return Timezone.from_file(f) |
219 | 181 |
|
220 | 182 | warnings.warn( |
|
0 commit comments