fix: 포트 충돌 회피 — note_bridge 8098, intent_service 8099
Jellyfin(8096), OrbStack(8097) 포트 충돌으로 변경. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
"""This module helps identifying the timezone ids and where they differ.
|
||||
|
||||
The algorithm: We use the tzname and the utcoffset for each hour from
|
||||
1970 - 2030.
|
||||
We make a big map.
|
||||
If they are equivalent, they are equivalent within the time that is mostly used.
|
||||
|
||||
You can regenerate the information from this module.
|
||||
|
||||
See also:
|
||||
- https://stackoverflow.com/questions/79185519/which-timezones-are-equivalent
|
||||
|
||||
Run this module:
|
||||
|
||||
python -m icalendar.timezone.equivalent_timezone_ids
|
||||
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections import defaultdict
|
||||
from datetime import datetime, timedelta, tzinfo
|
||||
from pathlib import Path
|
||||
from pprint import pprint
|
||||
from typing import Callable, NamedTuple, Optional
|
||||
|
||||
from pytz import AmbiguousTimeError, NonExistentTimeError
|
||||
from zoneinfo import ZoneInfo, available_timezones
|
||||
|
||||
START = datetime(1970, 1, 1) # noqa: DTZ001
|
||||
END = datetime(2020, 1, 1) # noqa: DTZ001
|
||||
DISTANCE_FROM_TIMEZONE_CHANGE = timedelta(hours=12)
|
||||
|
||||
DTS = []
|
||||
dt = START
|
||||
while dt <= END:
|
||||
DTS.append(dt)
|
||||
dt += timedelta(
|
||||
hours=25
|
||||
) # This must be big enough to be fast and small enough to identify the timeszones before it is the present year
|
||||
del dt
|
||||
|
||||
|
||||
def main(
|
||||
create_timezones: list[Callable[[str], tzinfo]],
|
||||
name: str,
|
||||
):
|
||||
"""Generate a lookup table for timezone information if unknown timezones.
|
||||
|
||||
We cannot create one lookup for all because they seem to be all equivalent
|
||||
if we mix timezone implementations.
|
||||
"""
|
||||
print(create_timezones, name)
|
||||
unsorted_tzids = available_timezones()
|
||||
unsorted_tzids.remove("localtime")
|
||||
unsorted_tzids.remove("Factory")
|
||||
|
||||
class TZ(NamedTuple):
|
||||
tz: tzinfo
|
||||
id: str
|
||||
|
||||
tzs = [
|
||||
TZ(create_timezone(tzid), tzid)
|
||||
for create_timezone in create_timezones
|
||||
for tzid in unsorted_tzids
|
||||
]
|
||||
|
||||
def generate_tree(
|
||||
tzs: list[TZ],
|
||||
step: timedelta = timedelta(hours=1),
|
||||
start: datetime = START,
|
||||
end: datetime = END,
|
||||
todo: Optional[set[str]] = None,
|
||||
) -> tuple[datetime, dict[timedelta, set[str]]] | set[str]: # should be recursive
|
||||
"""Generate a lookup tree."""
|
||||
if todo is None:
|
||||
todo = [tz.id for tz in tzs]
|
||||
print(f"{len(todo)} left to compute")
|
||||
print(len(tzs))
|
||||
if len(tzs) == 0:
|
||||
raise ValueError("tzs cannot be empty")
|
||||
if len(tzs) == 1:
|
||||
todo.remove(tzs[0].id)
|
||||
return {tzs[0].id}
|
||||
while start < end:
|
||||
offsets: dict[timedelta, list[TZ]] = defaultdict(list)
|
||||
try:
|
||||
# if we are around a timezone change, we must move on
|
||||
# see https://github.com/collective/icalendar/issues/776
|
||||
around_tz_change = not all(
|
||||
tz.tz.utcoffset(start)
|
||||
== tz.tz.utcoffset(start - DISTANCE_FROM_TIMEZONE_CHANGE)
|
||||
== tz.tz.utcoffset(start + DISTANCE_FROM_TIMEZONE_CHANGE)
|
||||
for tz in tzs
|
||||
)
|
||||
except (NonExistentTimeError, AmbiguousTimeError):
|
||||
around_tz_change = True
|
||||
if around_tz_change:
|
||||
start += DISTANCE_FROM_TIMEZONE_CHANGE
|
||||
continue
|
||||
for tz in tzs:
|
||||
offsets[tz.tz.utcoffset(start)].append(tz)
|
||||
if len(offsets) == 1:
|
||||
start += step
|
||||
continue
|
||||
lookup = {}
|
||||
for offset, tzs in offsets.items():
|
||||
lookup[offset] = generate_tree(
|
||||
tzs=tzs, step=step, start=start + step, end=end, todo=todo
|
||||
)
|
||||
return start, lookup
|
||||
print(f"reached end with {len(tzs)} timezones - assuming they are equivalent.")
|
||||
result = set()
|
||||
for tz in tzs:
|
||||
result.add(tz.id)
|
||||
todo.remove(tz.id)
|
||||
return result
|
||||
|
||||
lookup = generate_tree(tzs, step=timedelta(hours=33))
|
||||
|
||||
file = Path(__file__).parent / f"equivalent_timezone_ids_{name}.py"
|
||||
print(f"The result is written to {file}.")
|
||||
print("lookup = ", end="")
|
||||
pprint(lookup)
|
||||
with file.open("w") as f:
|
||||
f.write(
|
||||
f"'''This file is automatically generated by {Path(__file__).name}'''\n"
|
||||
)
|
||||
f.write("import datetime\n\n")
|
||||
f.write("\nlookup = ")
|
||||
pprint(lookup, stream=f)
|
||||
f.write("\n\n__all__ = ['lookup']\n")
|
||||
|
||||
return lookup
|
||||
|
||||
|
||||
__all__ = ["main"]
|
||||
|
||||
if __name__ == "__main__":
|
||||
from dateutil.tz import gettz
|
||||
from pytz import timezone
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
# add more timezone implementations if you like
|
||||
main(
|
||||
[ZoneInfo, timezone, gettz],
|
||||
"result",
|
||||
)
|
||||
Reference in New Issue
Block a user