Skip to content
This repository has been archived by the owner on Apr 25, 2023. It is now read-only.

Commit

Permalink
Fix off-by-one dates on events pages
Browse files Browse the repository at this point in the history
  • Loading branch information
bclozel committed Feb 11, 2020
1 parent 853b1bd commit 281fa12
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 65 deletions.
45 changes: 27 additions & 18 deletions sagan-site/src/main/java/sagan/site/events/Event.java
@@ -1,34 +1,35 @@
package sagan.site.events;

import java.net.URI;
import java.time.ZonedDateTime;
import java.util.TimeZone;
import java.time.Duration;
import java.time.LocalDate;
import java.time.ZoneId;

import biweekly.component.VEvent;

public class Event {
public class Event implements Comparable<Event> {

private final ZonedDateTime startTime;
private final LocalDate firstDay;

private final ZonedDateTime endTime;
private final LocalDate lastDay;

private final String summary;

private final URI link;

private final String location;

protected Event(ZonedDateTime startTime, ZonedDateTime endTime, String summary, URI link, String location) {
this.startTime = startTime;
this.endTime = endTime;
protected Event(LocalDate firstDay, LocalDate lastDay, String summary, URI link, String location) {
this.firstDay = firstDay;
this.lastDay = lastDay;
this.summary = summary;
this.link = link;
this.location = location;
}

protected Event(VEvent event, TimeZone timeZone) {
this.startTime = ZonedDateTime.ofInstant(event.getDateStart().getValue().toInstant(), timeZone.toZoneId());
this.endTime = ZonedDateTime.ofInstant(event.getDateEnd().getValue().toInstant(), timeZone.toZoneId());
protected Event(VEvent event) {
this.firstDay = event.getDateStart().getValue().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
this.lastDay = event.getDateEnd().getValue().toInstant().minus(Duration.ofMinutes(1)).atZone(ZoneId.systemDefault()).toLocalDate();
this.summary = event.getSummary().getValue();
this.link = parseLink(event);
this.location = event.getLocation().getValue();
Expand All @@ -43,24 +44,32 @@ private URI parseLink(VEvent event) {
}
}

public ZonedDateTime getStartTime() {
return startTime;
public LocalDate getFirstDay() {
return this.firstDay;
}

public ZonedDateTime getEndTime() {
return endTime;
public LocalDate getLastDay() {
return this.lastDay;
}

public boolean isSingleDayEvent() {
return this.firstDay.equals(this.lastDay);
}

public String getSummary() {
return summary;
return this.summary;
}

public URI getLink() {
return link;
return this.link;
}

public String getLocation() {
return location;
return this.location;
}

@Override
public int compareTo(Event other) {
return this.firstDay.compareTo(other.firstDay);
}
}
@@ -1,9 +1,7 @@
package sagan.site.events;

import java.net.URI;
import java.util.Comparator;
import java.util.List;
import java.util.TimeZone;
import java.util.stream.Collectors;

import biweekly.Biweekly;
Expand Down Expand Up @@ -34,12 +32,11 @@ public List<Event> findEvents(Period period) {
try {
String rawCalendar = this.client.getForEntity(this.calendarUri.toString(), String.class).getBody();
ICalendar iCalendar = Biweekly.parse(rawCalendar).first();
TimeZone calendarTimeZone = getCalendarTimeZone(iCalendar);
List<VEvent> events = iCalendar.getEvents();
return events.stream()
.filter(period.toCalendarFilter())
.map(event -> new Event(event, calendarTimeZone))
.sorted(Comparator.comparingLong(event -> event.getStartTime().toInstant().toEpochMilli()))
.map(Event::new)
.sorted()
.collect(Collectors.toList());
}
catch (HttpClientErrorException ex) {
Expand All @@ -50,13 +47,4 @@ public List<Event> findEvents(Period period) {
}
}

private TimeZone getCalendarTimeZone(ICalendar iCalendar) {
if (iCalendar.getTimezoneInfo().getDefaultTimezone() != null) {
return iCalendar.getTimezoneInfo().getDefaultTimezone().getTimeZone();
}
if (iCalendar.getExperimentalProperties("X-WR-TIMEZONE").size() > 0) {
return TimeZone.getTimeZone(iCalendar.getExperimentalProperties("X-WR-TIMEZONE").get(0).getValue());
}
return TimeZone.getDefault();
}
}
@@ -1,6 +1,5 @@
package sagan.site.events;


import java.util.List;

import org.junit.Test;
Expand Down Expand Up @@ -71,8 +70,8 @@ public void shouldReturnSingleEvent() {
assertThat(events).hasSize(1);
Event event = events.get(0);
assertThat(event.getSummary()).isEqualTo("Spring IO conference");
assertThat(event.getStartTime().toString()).isEqualTo("2020-05-14T00:00-07:00[America/Los_Angeles]");
assertThat(event.getEndTime().toString()).isEqualTo("2020-05-15T09:00-07:00[America/Los_Angeles]");
assertThat(event.getFirstDay().toString()).isEqualTo("2020-05-14");
assertThat(event.getLastDay().toString()).isEqualTo("2020-05-15");
assertThat(event.getLocation()).isEqualTo("Barcelona, Spain");
assertThat(event.getLink().toString()).isEqualTo("https://springio.net");
}
Expand All @@ -84,11 +83,19 @@ public void shouldReturnManyEvents() {
List<Event> events = this.calendarService.findEvents(Period.of("2020-05-01", 30));
assertThat(events).hasSize(2);
Event event = events.get(0);
assertThat(event.getSummary()).isEqualTo("Spring @ San Francisco JUG");
assertThat(event.getStartTime().toString()).isEqualTo("2020-05-11T18:00-07:00[America/Los_Angeles]");
assertThat(event.getEndTime().toString()).isEqualTo("2020-05-11T21:00-07:00[America/Los_Angeles]");
assertThat(event.getLocation()).isEqualTo("San Francisco, California");
assertThat(event.getLink().toString()).isEqualTo("https://spring.io");
assertThat(event.getSummary()).isEqualTo("Spring IO conference");
assertThat(event.getFirstDay().toString()).isEqualTo("2020-05-14");
assertThat(event.getLastDay().toString()).isEqualTo("2020-05-15");
assertThat(event.isSingleDayEvent()).isFalse();
assertThat(event.getLocation()).isEqualTo("Barcelona, Spain");
assertThat(event.getLink().toString()).isEqualTo("https://springio.net");
event = events.get(1);
assertThat(event.getSummary()).isEqualTo("Sample Event");
assertThat(event.getFirstDay().toString()).isEqualTo("2020-05-20");
assertThat(event.getLastDay().toString()).isEqualTo("2020-05-20");
assertThat(event.isSingleDayEvent()).isTrue();
assertThat(event.getLocation()).isEqualTo("Seattle, WA, USA");
assertThat(event.getLink().toString()).isEqualTo("https://example.org/sample");
}

private ClassPathResource getClassPathResource(String path) {
Expand Down
54 changes: 34 additions & 20 deletions sagan-site/src/test/resources/sagan/site/events/multi-events.ics
Expand Up @@ -6,31 +6,45 @@ METHOD:PUBLISH
X-WR-CALNAME:Spring Events
X-WR-TIMEZONE:America/Los_Angeles
BEGIN:VEVENT
DTSTART:20200512T010000Z
DTEND:20200512T040000Z
DTSTAMP:20200128T141410Z
UID:jug-event@example.org
CREATED:20200128T135531Z
DESCRIPTION:https://spring.io
LAST-MODIFIED:20200128T141357Z
LOCATION:San Francisco\, California
SEQUENCE:2
STATUS:CONFIRMED
SUMMARY:Spring @ San Francisco JUG
TRANSP:OPAQUE
END:VEVENT
BEGIN:VEVENT
DTSTART:20200514T070000Z
DTEND:20200515T160000Z
DTSTAMP:20200128T141410Z
UID:springio-event@example.org
DTSTART;VALUE=DATE:20200514
DTEND;VALUE=DATE:20200516
DTSTAMP:20200211T210141Z
UID:springio@example.org
CREATED:20200128T095717Z
DESCRIPTION:https://springio.net
LAST-MODIFIED:20200128T140810Z
LAST-MODIFIED:20200211T210129Z
LOCATION:Barcelona\, Spain
SEQUENCE:1
SEQUENCE:2
STATUS:CONFIRMED
SUMMARY:Spring IO conference
TRANSP:TRANSPARENT
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20200520
DTEND;VALUE=DATE:20200521
DTSTAMP:20200211T210141Z
UID:sample@example.org
CREATED:20200201T145735Z
DESCRIPTION:https://example.org/sample
LAST-MODIFIED:20200204T084706Z
LOCATION:Seattle\, WA\, USA
SEQUENCE:0
STATUS:CONFIRMED
SUMMARY:Sample Event
TRANSP:TRANSPARENT
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20200309
DTEND;VALUE=DATE:20200311
DTSTAMP:20200211T210141Z
UID:s1t-seattle@example.org
CREATED:20200201T145735Z
DESCRIPTION:https://springonetour.io/2020/seattle
LAST-MODIFIED:20200204T084706Z
LOCATION:Seattle\, WA\, USA
SEQUENCE:0
STATUS:CONFIRMED
SUMMARY:SpringOneTour Seattle
TRANSP:TRANSPARENT
END:VEVENT
END:VCALENDAR
11 changes: 6 additions & 5 deletions sagan-site/src/test/resources/sagan/site/events/single-event.ics
Expand Up @@ -6,17 +6,18 @@ METHOD:PUBLISH
X-WR-CALNAME:Spring Events
X-WR-TIMEZONE:America/Los_Angeles
BEGIN:VEVENT
DTSTART:20200514T070000Z
DTEND:20200515T160000Z
DTSTAMP:20200128T141410Z
DTSTART;VALUE=DATE:20200514
DTEND;VALUE=DATE:20200516
DTSTAMP:20200211T210141Z
UID:springio-event@example.org
CREATED:20200128T095717Z
DESCRIPTION:https://springio.net
LAST-MODIFIED:20200128T140810Z
LAST-MODIFIED:20200211T210129Z
LOCATION:Barcelona\, Spain
SEQUENCE:1
SEQUENCE:2
STATUS:CONFIRMED
SUMMARY:Spring IO conference
TRANSP:TRANSPARENT
END:VEVENT

END:VCALENDAR

0 comments on commit 281fa12

Please sign in to comment.