Skip to content

Commit

Permalink
More complete UTC offset parsing #102 #236
Browse files Browse the repository at this point in the history
  • Loading branch information
Rian Stockbower committed Feb 8, 2017
1 parent 73e2ab5 commit 76025b3
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 5 deletions.
1 change: 1 addition & 0 deletions release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ A listing of what each [Nuget package](https://www.nuget.org/packages/Ical.Net)

### v2

* 2.2.31: .NET's UTC offset parsing semantics don't match the RFC (which allows for `hhmmss` UTC offsets), so I extended the offset serializer to account for these differences. ([#102](https://github.com/rianjs/ical.net/issues/102), [#236](https://github.com/rianjs/ical.net/issues/236))
* 2.2.30: `Event.Resources` is an `IList` again. Event.Resources wasn't being deserialized, so I have reverted back to an IList to fix this. Sorry everyone. I'm intentionally violating my own semver rules. In the future, I'll call version n+1 "vNext" so I can more freely rev the major version number.
* 2.2.29: Calling `GetOccurrences()` on a recurrable component should recompute the recurrence set. Specifying `EXDATE` values that don't have a `TimeOfDay` component should "black out" that day from a recurring component's `StartTime`.[#223](https://github.com/rianjs/ical.net/issues/223)
* 2.2.25: Fix for Collection was modified exception, and better handling of recurrence ids when calling `Calendar.GetOccurrences` ([#188](https://github.com/rianjs/ical.net/issues/188)) ([#148](https://github.com/rianjs/ical.net/issues/148))
Expand Down
2 changes: 1 addition & 1 deletion v2/Ical.Net.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>Ical.Net</id>
<version>2.2.31</version>
<version>2.2.32</version>
<title>Ical.Net</title>
<authors>Rian Stockbower, Douglas Day, M. David Peterson</authors>
<owners>Rian Stockbower</owners>
Expand Down
52 changes: 52 additions & 0 deletions v2/ical.NET.UnitTests/EventTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Ical.Net.General;
using Ical.Net.Interfaces.DataTypes;
using Ical.Net.Serialization.iCalendar.Serializers;

Expand Down Expand Up @@ -396,5 +397,56 @@ public void EventResourcesCanBeZeroedOut()
//See https://github.com/rianjs/ical.net/issues/208 -- this should be changed later so the collection is really null
Assert.AreEqual(0, e.Resources?.Count);
}

[Test]
public void HourMinuteSecondOffsetParsingTest()
{
const string ical =
@"BEGIN:VCALENDAR
PRODID:-//1&1 Mail & Media GmbH/GMX Kalender Server 3.10.0//NONSGML//DE
VERSION:2.0
CALSCALE:GREGORIAN
METHOD:REQUEST
BEGIN:VTIMEZONE
TZID:Europe/Brussels
TZURL:http://tzurl.org/zoneinfo/Europe/Brussels
X-LIC-LOCATION:Europe/Brussels
BEGIN:DAYLIGHT
TZOFFSETFROM:-001730
TZOFFSETTO:-001730
TZNAME:CEST
DTSTART:19810329T020000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+001730
TZOFFSETTO:+001730
TZNAME:BMT
DTSTART:18800101T000000
RDATE:18800101T000000
END:STANDARD
END:VTIMEZONE
END:VCALENDAR";
using (var reader = new StringReader(ical))
{
var timezones = Calendar.LoadFromStream(reader)
.First()
.TimeZones.First()
.Children.Cast<CalendarComponent>();

var positiveOffset = timezones
.Skip(1).Take(1).First()
.Properties.First().Value as UtcOffset;
var expectedPositive = TimeSpan.FromMinutes(17.5);
Assert.AreEqual(expectedPositive, positiveOffset?.Offset);

var negativeOffset = timezones
.First()
.Properties.First().Value as UtcOffset;

var expectedNegative = TimeSpan.FromMinutes(-17.5);
Assert.AreEqual(expectedNegative, negativeOffset?.Offset);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Ical.Net.DataTypes;
using Ical.Net.Interfaces.DataTypes;
Expand Down Expand Up @@ -39,8 +41,29 @@ public static TimeSpan GetOffset(string rawOffset)
{
rawOffset = rawOffset.Substring(0, rawOffset.Length - 2);
}
var dummyOffset = DateTimeOffset.Parse("2016-01-01 00:00:00 " + rawOffset);
return dummyOffset.Offset;

DateTimeOffset temp;
if (DateTimeOffset.TryParse("2016-01-01 00:00:00 " + rawOffset, out temp))
{
return temp.Offset;
}

TimeSpan ts;
var isNegative = rawOffset.StartsWith("-");

if (isNegative || rawOffset.StartsWith("+"))
{
rawOffset = rawOffset.Substring(1, rawOffset.Length - 1);
}

if (!TimeSpan.TryParseExact(rawOffset, "hhmmss", CultureInfo.InvariantCulture, out ts))
{
throw new FormatException($"{rawOffset} is not a valid UTC offset");
}

return isNegative
? -ts
: ts;
}
}
}
52 changes: 52 additions & 0 deletions v3/ical.NET.UnitTests/CalendarEventTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -393,5 +393,57 @@ public void EventResourcesCanBeZeroedOut()
//See https://github.com/rianjs/ical.net/issues/208 -- this should be changed later so the collection is really null
Assert.AreEqual(0, e.Resources?.Count);
}

[Test]
public void HourMinuteSecondOffsetParsingTest()
{
const string ical =
@"BEGIN:VCALENDAR
PRODID:-//1&1 Mail & Media GmbH/GMX Kalender Server 3.10.0//NONSGML//DE
VERSION:2.0
CALSCALE:GREGORIAN
METHOD:REQUEST
BEGIN:VTIMEZONE
TZID:Europe/Brussels
TZURL:http://tzurl.org/zoneinfo/Europe/Brussels
X-LIC-LOCATION:Europe/Brussels
BEGIN:DAYLIGHT
TZOFFSETFROM:-001730
TZOFFSETTO:-001730
TZNAME:CEST
DTSTART:19810329T020000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+001730
TZOFFSETTO:+001730
TZNAME:BMT
DTSTART:18800101T000000
RDATE:18800101T000000
END:STANDARD
END:VTIMEZONE
END:VCALENDAR";

using (var reader = new StringReader(ical))
{
var timezones = Calendar.LoadFromStream(reader)
.First()
.TimeZones.First()
.Children.Cast<CalendarComponent>();

var positiveOffset = timezones
.Skip(1).Take(1).First()
.Properties.First().Value as UtcOffset;
var expectedPositive = TimeSpan.FromMinutes(17.5);
Assert.AreEqual(expectedPositive, positiveOffset?.Offset);

var negativeOffset = timezones
.First()
.Properties.First().Value as UtcOffset;

var expectedNegative = TimeSpan.FromMinutes(-17.5);
Assert.AreEqual(expectedNegative, negativeOffset?.Offset);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Globalization;
using System.IO;
using System.Text.RegularExpressions;
using Ical.Net.DataTypes;
Expand Down Expand Up @@ -38,8 +39,29 @@ public static TimeSpan GetOffset(string rawOffset)
{
rawOffset = rawOffset.Substring(0, rawOffset.Length - 2);
}
var dummyOffset = DateTimeOffset.Parse("2016-01-01 00:00:00 " + rawOffset);
return dummyOffset.Offset;

DateTimeOffset temp;
if (DateTimeOffset.TryParse("2016-01-01 00:00:00 " + rawOffset, out temp))
{
return temp.Offset;
}

TimeSpan ts;
var isNegative = rawOffset.StartsWith("-");

if (isNegative || rawOffset.StartsWith("+"))
{
rawOffset = rawOffset.Substring(1, rawOffset.Length - 1);
}

if (!TimeSpan.TryParseExact(rawOffset, "hhmmss", CultureInfo.InvariantCulture, out ts))
{
throw new FormatException($"{rawOffset} is not a valid UTC offset");
}

return isNegative
? -ts
: ts;
}
}
}

0 comments on commit 76025b3

Please sign in to comment.