Skip to content

Commit 7d466f8

Browse files
authored
Merge pull request #8 from rkdarst/meta-timezone
Add per-calendar default timezone (in meta header)
2 parents 464e18e + 54113fb commit 7d466f8

3 files changed

Lines changed: 54 additions & 6 deletions

File tree

example/test_calendar.yaml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
1+
meta:
2+
tz: America/Los_Angeles
3+
14
events:
25
- summary: Event of the Century
3-
begin: 2021-09-21 15:00:00 -07:00
4-
end: 2021-09-21 15:30:00 -07:00
6+
begin: 2021-09-21 15:00:00
7+
end: 2021-09-21 15:30:00
58
description: |
69
Meet the team on the northern side of the field.
710
811
- summary: Half-an-hour meeting
9-
begin: 2021-09-23 15:00:00
12+
begin: 2021-09-23 15:00:00 -07:00
1013
duration:
1114
minutes: 30
1215
location: |

tests/test_calendar.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import datetime
12
import io
23
import textwrap
34

@@ -28,3 +29,39 @@ def test_calendar_event():
2829
assert cal_str.startswith('BEGIN:VCALENDAR')
2930
assert 'SUMMARY:Earth Day' in cal_str
3031
assert cal_str.endswith('END:VCALENDAR')
32+
33+
def test_calendar_default_timezone():
34+
cal = files_to_calendar(
35+
[io.StringIO(textwrap.dedent(
36+
'''
37+
meta:
38+
tz: Europe/Helsinki
39+
40+
events:
41+
- summary: New year's day
42+
begin: 2022-01-01 00:00:00
43+
duration: {hours: 1}
44+
45+
- summary: February 1
46+
begin: 2022-02-01 00:00:00 +02:00
47+
duration: {hours: 1}
48+
'''
49+
))]
50+
)
51+
cal_str = cal.serialize()
52+
assert cal_str.startswith('BEGIN:VCALENDAR')
53+
assert 'SUMMARY:New year' in cal_str
54+
# It is possible that the ics-py TZID string changes, but hopefully this
55+
# substring is fairly safe to test against.
56+
assert 'Europe/Helsinki:20220101T000000' in cal_str
57+
# Second event: explicit UTC offset specified.
58+
assert '"UTC+02:00":20220201T000000' in cal_str
59+
assert cal_str.endswith('END:VCALENDAR')
60+
61+
# Test again by normalizing to UTC. Helsinki is two hours ahead, so the
62+
# times should be 22:00:00.
63+
cal.normalize(datetime.timezone.utc)
64+
cal_norm_str = cal.serialize()
65+
# 1 Feb midnight
66+
assert 'DTSTART:20211231T220000Z' # 1 jan
67+
assert 'DTSTART:20220131T220000Z' # 1 feb

yaml2ics.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import yaml
22
import sys
33
import os
4-
from datetime import datetime
4+
from datetime import datetime, tzinfo
55

66
import ics
77
import dateutil
88
import dateutil.rrule
9+
from dateutil.tz import gettz
910

1011

1112
interval_type = {
@@ -19,7 +20,7 @@
1920
}
2021

2122

22-
def event_from_yaml(event_yaml: dict) -> ics.Event:
23+
def event_from_yaml(event_yaml: dict, tz: tzinfo=None) -> ics.Event:
2324
d = event_yaml
2425
repeat = d.pop('repeat', None)
2526

@@ -73,6 +74,8 @@ def event_from_yaml(event_yaml: dict) -> ics.Event:
7374
))
7475

7576
event.dtstamp = datetime.utcnow().replace(tzinfo=dateutil.tz.UTC)
77+
if tz and event.floating:
78+
event.replace_timezone(tz)
7679
return event
7780

7881

@@ -85,13 +88,18 @@ def events_to_calendar(events: list) -> str:
8588
def files_to_calendar(files: list) -> ics.Calendar:
8689
"""'main' function: list of files to our result"""
8790
all_events = [ ]
91+
name = None
8892
for f in files:
8993
if hasattr(f, 'read'):
9094
calendar_yaml = yaml.load(f.read(), Loader=yaml.FullLoader)
9195
else:
9296
calendar_yaml = yaml.load(open(f, 'r'), Loader=yaml.FullLoader)
97+
tz = None
98+
if 'meta' in calendar_yaml:
99+
if 'tz' in calendar_yaml['meta']:
100+
tz = gettz(calendar_yaml['meta']['tz'])
93101
for event in calendar_yaml['events']:
94-
all_events.append(event_from_yaml(event))
102+
all_events.append(event_from_yaml(event, tz=tz))
95103
calendar = events_to_calendar(all_events)
96104
return calendar
97105

0 commit comments

Comments
 (0)