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 +53 -0
- klockslag-1.1/README.md +39 -0
- klockslag-1.1/pyproject.toml +35 -0
- klockslag-1.1/setup.cfg +4 -0
- klockslag-1.1/src/__init__.py +0 -0
- klockslag-1.1/src/klockslag.egg-info/PKG-INFO +53 -0
- klockslag-1.1/src/klockslag.egg-info/SOURCES.txt +11 -0
- klockslag-1.1/src/klockslag.egg-info/dependency_links.txt +1 -0
- klockslag-1.1/src/klockslag.egg-info/entry_points.txt +2 -0
- klockslag-1.1/src/klockslag.egg-info/requires.txt +1 -0
- klockslag-1.1/src/klockslag.egg-info/top_level.txt +3 -0
- klockslag-1.1/src/klockslag.py +143 -0
- klockslag-1.1/src/version.py +1 -0
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
|
+
```
|
klockslag-1.1/README.md
ADDED
|
@@ -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__"}
|
klockslag-1.1/setup.cfg
ADDED
|
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 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
geonamescache
|
|
@@ -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'
|