Commit f5dcc112 authored by Ricki Hirner's avatar Ricki Hirner

Minify VTIMEZONEs

parent 3a4e2163
......@@ -221,8 +221,12 @@ class Event: ICalendar() {
exception.dtEnd?.timeZone?.let(usedTimeZones::add)
}
// add VTIMEZONE components
usedTimeZones.forEach { ical.components += it.vTimeZone }
// add minified VTIMEZONE components
usedTimeZones.forEach {
val tz = it.vTimeZone
dtStart?.let { minifyVTimeZone(tz, it.date) }
ical.components += tz
}
CalendarOutputter(false).output(ical, os)
}
......
......@@ -12,10 +12,11 @@ import net.fortuna.ical4j.data.CalendarBuilder
import net.fortuna.ical4j.data.CalendarParserFactory
import net.fortuna.ical4j.data.ParserException
import net.fortuna.ical4j.model.*
import net.fortuna.ical4j.model.component.VAlarm
import net.fortuna.ical4j.model.component.VTimeZone
import net.fortuna.ical4j.model.Date
import net.fortuna.ical4j.model.component.*
import net.fortuna.ical4j.model.property.DateProperty
import net.fortuna.ical4j.model.property.ProdId
import net.fortuna.ical4j.model.property.TzUrl
import net.fortuna.ical4j.util.Strings
import java.io.StringReader
import java.util.*
......@@ -60,6 +61,60 @@ open class ICalendar {
fun isDateTime(date: DateProperty?) = date != null && date.date is DateTime
/**
* Minifies a VTIMEZONE so that only components after [start] are kept.
* Doesn't return the smallest possible VTIMEZONE at the moment, but
* reduces its size significantly.
*
* @param tz Time zone definition to minify. Attention: the observances of this object
* will be modified!
* @param start Start date for components
*/
fun minifyVTimeZone(tz: VTimeZone, start: Date) {
// find latest matching STANDARD/DAYLIGHT component,
// keep components at/after "start"
val iter = tz.observances.iterator()
var latestDaylight: Pair<Date, Observance>? = null
var latestStandard: Pair<Date, Observance>? = null
val keep = mutableSetOf<Observance>()
while (iter.hasNext()) {
val entry = iter.next() as Observance
val latest = entry.getLatestOnset(start)
if (latest == null /* observance begins after "start" */ ||
latest >= start /* observance has onsets at/after "start" */ ) {
keep += entry
continue
}
when (entry) {
is Standard -> {
if (latestStandard == null || latest.after(latestStandard.first))
latestStandard = Pair(latest, entry)
}
is Daylight -> {
if (latestDaylight == null || latest.after(latestDaylight.first))
latestDaylight = Pair(latest, entry)
}
}
}
latestStandard?.second?.let { keep += it }
latestDaylight?.second?.let { keep += it }
// actually remove all observances that shall not be kept
val iter2 = tz.observances.iterator()
while (iter2.hasNext()) {
val entry = iter2.next() as Observance
if (!keep.contains(entry))
iter2.remove()
}
// remove TZURL
tz.properties.filter { it is TzUrl }.forEach {
tz.properties.remove(it)
}
}
/**
* Takes a string with a timezone definition and returns the time zone ID.
* @param timezoneDef time zone definition (VCALENDAR with VTIMEZONE component)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment