klockslag 1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
klockslag-1.1/PKG-INFO ADDED
@@ -0,0 +1,53 @@
1
+ Metadata-Version: 2.4
2
+ Name: klockslag
3
+ Version: 1.1
4
+ Summary: A tool for showing times in different timezones
5
+ Author-email: Lars Arvestad <arve@math.su.se>
6
+ Maintainer-email: Lars Arvestad <arve@math.su.se>
7
+ License-Expression: GPL-3.0-or-later
8
+ Project-URL: homepage, https://github.com/arvestad/klockslag
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.6
12
+ Description-Content-Type: text/markdown
13
+ Requires-Dist: geonamescache
14
+
15
+ # Klockslag
16
+
17
+ Find out what a time is in some other timezones.
18
+
19
+ Example: I am planning an online meeting with participants on the east coast of USA,
20
+ Paris, Tokyo, and Seoul. The plan is at 16:00 my time (in Stockholm), but what time is that
21
+ for the others?
22
+
23
+ ```
24
+ $ klockslag 16:00 seoul paris eastern
25
+ US/Eastern 10:00:00
26
+ Canada/Eastern 10:00:00
27
+ Europe/Paris 16:00:00
28
+ Asia/Seoul 23:00:00
29
+ Asia/Tokyo 23:00:00
30
+ ```
31
+
32
+ You may need to disambiguate sometimes. For example:
33
+
34
+ ```
35
+ $ klockslag 16:00 stockholm springfield paris
36
+ Oregon/Springfield 07:00:00
37
+ Illinois/Springfield 09:00:00
38
+ Missouri/Springfield 09:00:00
39
+ Tennessee/Springfield 09:00:00
40
+ Ohio/Springfield 10:00:00
41
+ Pennsylvania/Springfield 10:00:00
42
+ Virginia/Springfield 10:00:00
43
+ Massachusetts/Springfield 10:00:00
44
+ Europe/Stockholm 16:00:00
45
+ Europe/Paris 16:00:00
46
+ ```
47
+ There are too many matching Springfields, and I wanted Paris, TX, so I add qualifiers for a better presentation:
48
+ ```
49
+ $ klockslag 16:00 stockholm pennsylvania/springfield texas/paris
50
+ Texas/Paris 09:00:00
51
+ Pennsylvania/Springfield 10:00:00
52
+ Europe/Stockholm 16:00:00
53
+ ```
@@ -0,0 +1,39 @@
1
+ # Klockslag
2
+
3
+ Find out what a time is in some other timezones.
4
+
5
+ Example: I am planning an online meeting with participants on the east coast of USA,
6
+ Paris, Tokyo, and Seoul. The plan is at 16:00 my time (in Stockholm), but what time is that
7
+ for the others?
8
+
9
+ ```
10
+ $ klockslag 16:00 seoul paris eastern
11
+ US/Eastern 10:00:00
12
+ Canada/Eastern 10:00:00
13
+ Europe/Paris 16:00:00
14
+ Asia/Seoul 23:00:00
15
+ Asia/Tokyo 23:00:00
16
+ ```
17
+
18
+ You may need to disambiguate sometimes. For example:
19
+
20
+ ```
21
+ $ klockslag 16:00 stockholm springfield paris
22
+ Oregon/Springfield 07:00:00
23
+ Illinois/Springfield 09:00:00
24
+ Missouri/Springfield 09:00:00
25
+ Tennessee/Springfield 09:00:00
26
+ Ohio/Springfield 10:00:00
27
+ Pennsylvania/Springfield 10:00:00
28
+ Virginia/Springfield 10:00:00
29
+ Massachusetts/Springfield 10:00:00
30
+ Europe/Stockholm 16:00:00
31
+ Europe/Paris 16:00:00
32
+ ```
33
+ There are too many matching Springfields, and I wanted Paris, TX, so I add qualifiers for a better presentation:
34
+ ```
35
+ $ klockslag 16:00 stockholm pennsylvania/springfield texas/paris
36
+ Texas/Paris 09:00:00
37
+ Pennsylvania/Springfield 10:00:00
38
+ Europe/Stockholm 16:00:00
39
+ ```
@@ -0,0 +1,35 @@
1
+ [project]
2
+ name = "klockslag"
3
+ authors = [
4
+ {name = "Lars Arvestad", email = "arve@math.su.se"}
5
+ ]
6
+ maintainers = [
7
+ {name = "Lars Arvestad", email = "arve@math.su.se"},
8
+ ]
9
+ description = "A tool for showing times in different timezones"
10
+ readme = "README.md"
11
+ license = "GPL-3.0-or-later"
12
+ classifiers = [
13
+ "Programming Language :: Python :: 3",
14
+ "Operating System :: OS Independent",
15
+ ]
16
+ dynamic = ["version"]
17
+
18
+ dependencies = ["geonamescache"]
19
+ requires-python = ">= 3.6"
20
+
21
+ [build-system]
22
+ requires = ["setuptools"]
23
+ build-backend = "setuptools.build_meta"
24
+
25
+
26
+ [project.scripts]
27
+ klockslag = "klockslag:main"
28
+
29
+
30
+ [project.urls]
31
+ homepage = "https://github.com/arvestad/klockslag"
32
+
33
+
34
+ [tool.setuptools.dynamic]
35
+ version = {attr = "version.__version__"}
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
File without changes
@@ -0,0 +1,53 @@
1
+ Metadata-Version: 2.4
2
+ Name: klockslag
3
+ Version: 1.1
4
+ Summary: A tool for showing times in different timezones
5
+ Author-email: Lars Arvestad <arve@math.su.se>
6
+ Maintainer-email: Lars Arvestad <arve@math.su.se>
7
+ License-Expression: GPL-3.0-or-later
8
+ Project-URL: homepage, https://github.com/arvestad/klockslag
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.6
12
+ Description-Content-Type: text/markdown
13
+ Requires-Dist: geonamescache
14
+
15
+ # Klockslag
16
+
17
+ Find out what a time is in some other timezones.
18
+
19
+ Example: I am planning an online meeting with participants on the east coast of USA,
20
+ Paris, Tokyo, and Seoul. The plan is at 16:00 my time (in Stockholm), but what time is that
21
+ for the others?
22
+
23
+ ```
24
+ $ klockslag 16:00 seoul paris eastern
25
+ US/Eastern 10:00:00
26
+ Canada/Eastern 10:00:00
27
+ Europe/Paris 16:00:00
28
+ Asia/Seoul 23:00:00
29
+ Asia/Tokyo 23:00:00
30
+ ```
31
+
32
+ You may need to disambiguate sometimes. For example:
33
+
34
+ ```
35
+ $ klockslag 16:00 stockholm springfield paris
36
+ Oregon/Springfield 07:00:00
37
+ Illinois/Springfield 09:00:00
38
+ Missouri/Springfield 09:00:00
39
+ Tennessee/Springfield 09:00:00
40
+ Ohio/Springfield 10:00:00
41
+ Pennsylvania/Springfield 10:00:00
42
+ Virginia/Springfield 10:00:00
43
+ Massachusetts/Springfield 10:00:00
44
+ Europe/Stockholm 16:00:00
45
+ Europe/Paris 16:00:00
46
+ ```
47
+ There are too many matching Springfields, and I wanted Paris, TX, so I add qualifiers for a better presentation:
48
+ ```
49
+ $ klockslag 16:00 stockholm pennsylvania/springfield texas/paris
50
+ Texas/Paris 09:00:00
51
+ Pennsylvania/Springfield 10:00:00
52
+ Europe/Stockholm 16:00:00
53
+ ```
@@ -0,0 +1,11 @@
1
+ README.md
2
+ pyproject.toml
3
+ src/__init__.py
4
+ src/klockslag.py
5
+ src/version.py
6
+ src/klockslag.egg-info/PKG-INFO
7
+ src/klockslag.egg-info/SOURCES.txt
8
+ src/klockslag.egg-info/dependency_links.txt
9
+ src/klockslag.egg-info/entry_points.txt
10
+ src/klockslag.egg-info/requires.txt
11
+ src/klockslag.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ klockslag = klockslag:main
@@ -0,0 +1 @@
1
+ geonamescache
@@ -0,0 +1,3 @@
1
+ __init__
2
+ klockslag
3
+ version
@@ -0,0 +1,143 @@
1
+ import argparse
2
+ import datetime as dt
3
+ import re
4
+ import sys
5
+ import zoneinfo
6
+
7
+ import geonamescache
8
+
9
+ def setup_args():
10
+ ap = argparse.ArgumentParser(description='What time is it in other timezones?')
11
+ ap.add_argument('time', nargs='?', default=None,
12
+ help='List time in other timezones for this time in your current timezone.'),
13
+ ap.add_argument('timezones', nargs='*',
14
+ help='Named timezones or city names, e.g. Europe/Oslo, "Tel Aviv", or '
15
+ 'Massachusetts/Springfield to disambiguate a common city name.')
16
+ ap.add_argument('-tz', '--list-time-zones', action='store_true',
17
+ help='Provide a list of available timezones.')
18
+ return ap
19
+
20
+
21
+ def show_timezones():
22
+ for tz in sorted(zoneinfo.available_timezones()):
23
+ print(tz)
24
+
25
+
26
+ def iana_zone_matches(name):
27
+ pattern = re.compile(name, re.IGNORECASE)
28
+ return {tz for tz in zoneinfo.available_timezones() if pattern.search(tz)}
29
+
30
+
31
+ def split_qualifier(term):
32
+ """Split "Qualifier/City" (e.g. "Massachusetts/Springfield") into
33
+ (qualifier, city). qualifier is None if `term` has no '/'."""
34
+ if '/' in term:
35
+ qualifier, _, city = term.rpartition('/')
36
+ return qualifier, city
37
+ return None, term
38
+
39
+
40
+ def city_hints(city, countries, us_states):
41
+ """Strings that can be used as a qualifier to disambiguate this city."""
42
+ country = countries.get(city['countrycode'], {}).get('name', city['countrycode'])
43
+ hints = [country, city['countrycode']]
44
+ if city['countrycode'] == 'US' and city['admin1code'] in us_states:
45
+ state = us_states[city['admin1code']]
46
+ hints += [state['name'], state['code']]
47
+ return hints
48
+
49
+
50
+ def city_label(city, countries, us_states):
51
+ """Render a city as "Qualifier/City", matching IANA's "Region/City" style."""
52
+ if city['countrycode'] == 'US' and city['admin1code'] in us_states:
53
+ qualifier = us_states[city['admin1code']]['name']
54
+ else:
55
+ qualifier = countries.get(city['countrycode'], {}).get('name', city['countrycode'])
56
+ return f"{qualifier}/{city['name']}"
57
+
58
+
59
+ def city_matches(name, qualifier=None):
60
+ """Return a list of (place_label, iana_zone_name) for cities named `name`,
61
+ optionally narrowed to those matching `qualifier` (a state or country name/code)."""
62
+ gc = geonamescache.GeonamesCache()
63
+ countries = gc.get_countries()
64
+ us_states = gc.get_us_states()
65
+ candidates = [c for c in gc.get_cities().values() if c['name'].lower() == name.lower()]
66
+
67
+ if qualifier:
68
+ pattern = re.compile(qualifier, re.IGNORECASE)
69
+ narrowed = [c for c in candidates
70
+ if any(pattern.search(hint) for hint in city_hints(c, countries, us_states))]
71
+ if narrowed:
72
+ candidates = narrowed
73
+ else:
74
+ print(f'warning: no location "{qualifier}" found among matches for "{name}"; showing all',
75
+ file=sys.stderr)
76
+
77
+ return [(city_label(c, countries, us_states), c['timezone']) for c in candidates]
78
+
79
+
80
+ def matching_timezones(str_list):
81
+ """Map each search term to timezone(s), preferring an IANA zone-name match
82
+ and falling back to a city-name lookup (which may yield several places,
83
+ e.g. "Springfield", unless narrowed with a "Qualifier/City" term such as
84
+ "Massachusetts/Springfield")."""
85
+ res = {}
86
+ for s in str_list:
87
+ zones = iana_zone_matches(s)
88
+ if zones:
89
+ for tz in zones:
90
+ res[tz] = zoneinfo.ZoneInfo(tz)
91
+ continue
92
+
93
+ qualifier, city_name = split_qualifier(s)
94
+ cities = city_matches(city_name, qualifier)
95
+ if cities:
96
+ for place, tz in cities:
97
+ res[place] = zoneinfo.ZoneInfo(tz)
98
+ else:
99
+ print(f'warning: no timezone or city found matching "{s}"', file=sys.stderr)
100
+ return res
101
+
102
+
103
+ def combine_time_and_zone(t, z):
104
+ date = dt.date.today()
105
+ t = dt.time.fromisoformat(t)
106
+ d = dt.datetime.combine(date, t)
107
+ d2 = d.astimezone(z)
108
+ return d2
109
+
110
+
111
+ def show_in_other_timezones(t, tz_dict):
112
+ entries = []
113
+ for label, tz in tz_dict.items():
114
+ d = combine_time_and_zone(t, tz)
115
+ entries.append((label, d.time()))
116
+ entries.sort(key=lambda e: e[1])
117
+ width = max((len(label) for label, _ in entries), default=0)
118
+ for label, time in entries:
119
+ print(f'{label.ljust(width)} {time}')
120
+
121
+
122
+ def main():
123
+ ap = setup_args()
124
+ args = ap.parse_args()
125
+
126
+ if args.list_time_zones:
127
+ show_timezones()
128
+ return
129
+
130
+ if not args.time or not args.timezones:
131
+ ap.error('time and at least one timezone are required unless -tz is given')
132
+
133
+ if args.time == 'now':
134
+ t = dt.datetime.now().time().isoformat()
135
+ else:
136
+ t = args.time
137
+
138
+ tz_list = matching_timezones(args.timezones)
139
+ show_in_other_timezones(t, tz_list)
140
+
141
+
142
+ if __name__ == '__main__':
143
+ main()
@@ -0,0 +1 @@
1
+ __version__ = '1.1'