001package biweekly.component; 002 003import java.util.Date; 004import java.util.List; 005 006import biweekly.Warning; 007import biweekly.property.Comment; 008import biweekly.property.DateStart; 009import biweekly.property.ExceptionDates; 010import biweekly.property.RecurrenceDates; 011import biweekly.property.RecurrenceRule; 012import biweekly.property.TimezoneName; 013import biweekly.property.TimezoneOffsetFrom; 014import biweekly.property.TimezoneOffsetTo; 015import biweekly.util.DateTimeComponents; 016import biweekly.util.Recurrence; 017 018/* 019 Copyright (c) 2013, Michael Angstadt 020 All rights reserved. 021 022 Redistribution and use in source and binary forms, with or without 023 modification, are permitted provided that the following conditions are met: 024 025 1. Redistributions of source code must retain the above copyright notice, this 026 list of conditions and the following disclaimer. 027 2. Redistributions in binary form must reproduce the above copyright notice, 028 this list of conditions and the following disclaimer in the documentation 029 and/or other materials provided with the distribution. 030 031 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 032 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 033 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 034 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 035 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 036 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 037 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 038 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 039 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 040 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 041 */ 042 043/** 044 * Represents a timezone observance (i.e. "daylight savings" and "standard" 045 * times). 046 * @author Michael Angstadt 047 * @see DaylightSavingsTime 048 * @see StandardTime 049 * @see <a href="http://tools.ietf.org/html/rfc5545#page-62">RFC 5545 050 * p.62-71</a> 051 */ 052public class Observance extends ICalComponent { 053 /** 054 * Gets the date that the timezone observance starts. 055 * @return the start date or null if not set 056 * @see <a href="http://tools.ietf.org/html/rfc5545#page-97">RFC 5545 057 * p.97-8</a> 058 */ 059 public DateStart getDateStart() { 060 return getProperty(DateStart.class); 061 } 062 063 /** 064 * Sets the date that the timezone observance starts. 065 * @param dateStart the start date or null to remove 066 * @see <a href="http://tools.ietf.org/html/rfc5545#page-97">RFC 5545 067 * p.97-8</a> 068 */ 069 public void setDateStart(DateStart dateStart) { 070 if (dateStart != null) { 071 dateStart.setLocalTime(true); 072 } 073 setProperty(DateStart.class, dateStart); 074 } 075 076 /** 077 * Sets the date that the timezone observance starts. 078 * @param components the raw components of the start date or null to remove 079 * @return the property that was created 080 * @see <a href="http://tools.ietf.org/html/rfc5545#page-97">RFC 5545 081 * p.97-8</a> 082 */ 083 public DateStart setDateStart(DateTimeComponents components) { 084 DateStart prop = (components == null) ? null : new DateStart(components); 085 setDateStart(prop); 086 return prop; 087 } 088 089 /** 090 * Gets the UTC offset that the timezone observance transitions to. 091 * @return the UTC offset or null if not set 092 * @see <a href="http://tools.ietf.org/html/rfc5545#page-105">RFC 5545 093 * p.105-6</a> 094 */ 095 public TimezoneOffsetTo getTimezoneOffsetTo() { 096 return getProperty(TimezoneOffsetTo.class); 097 } 098 099 /** 100 * Sets the UTC offset that the timezone observance transitions to. 101 * @param timezoneOffsetTo the UTC offset or null to remove 102 * @see <a href="http://tools.ietf.org/html/rfc5545#page-105">RFC 5545 103 * p.105-6</a> 104 */ 105 public void setTimezoneOffsetTo(TimezoneOffsetTo timezoneOffsetTo) { 106 setProperty(TimezoneOffsetTo.class, timezoneOffsetTo); 107 } 108 109 /** 110 * Sets the UTC offset that the timezone observance transitions to. 111 * @param hour the hour offset (e.g. "-5") 112 * @param minute the minute offset (e.g. "0") 113 * @return the property that was created 114 * @see <a href="http://tools.ietf.org/html/rfc5545#page-105">RFC 5545 115 * p.105-6</a> 116 */ 117 public TimezoneOffsetTo setTimezoneOffsetTo(Integer hour, Integer minute) { 118 TimezoneOffsetTo prop = new TimezoneOffsetTo(hour, minute); 119 setTimezoneOffsetTo(prop); 120 return prop; 121 } 122 123 /** 124 * Gets the UTC offset that the timezone observance transitions from. 125 * @return the UTC offset or null if not set 126 * @see <a href="http://tools.ietf.org/html/rfc5545#page-104">RFC 5545 127 * p.104-5</a> 128 */ 129 public TimezoneOffsetFrom getTimezoneOffsetFrom() { 130 return getProperty(TimezoneOffsetFrom.class); 131 } 132 133 /** 134 * Sets the UTC offset that the timezone observance transitions from. 135 * @param timezoneOffsetFrom the UTC offset or null to remove 136 * @see <a href="http://tools.ietf.org/html/rfc5545#page-104">RFC 5545 137 * p.104-5</a> 138 */ 139 public void setTimezoneOffsetFrom(TimezoneOffsetFrom timezoneOffsetFrom) { 140 setProperty(TimezoneOffsetFrom.class, timezoneOffsetFrom); 141 } 142 143 /** 144 * Sets the UTC offset that the timezone observance transitions from. 145 * @param hour the hour offset (e.g. "-5") 146 * @param minute the minute offset (e.g. "0") 147 * @return the property that was created 148 * @see <a href="http://tools.ietf.org/html/rfc5545#page-104">RFC 5545 149 * p.104-5</a> 150 */ 151 public TimezoneOffsetFrom setTimezoneOffsetFrom(Integer hour, Integer minute) { 152 TimezoneOffsetFrom prop = new TimezoneOffsetFrom(hour, minute); 153 setTimezoneOffsetFrom(prop); 154 return prop; 155 } 156 157 /** 158 * Gets how often the timezone observance repeats. 159 * @return the recurrence rule or null if not set 160 * @see <a href="http://tools.ietf.org/html/rfc5545#page-122">RFC 5545 161 * p.122-32</a> 162 */ 163 public RecurrenceRule getRecurrenceRule() { 164 return getProperty(RecurrenceRule.class); 165 } 166 167 /** 168 * Sets how often the timezone observance repeats. 169 * @param recur the recurrence rule or null to remove 170 * @return the property that was created 171 * @see <a href="http://tools.ietf.org/html/rfc5545#page-122">RFC 5545 172 * p.122-32</a> 173 */ 174 public RecurrenceRule setRecurrenceRule(Recurrence recur) { 175 RecurrenceRule prop = (recur == null) ? null : new RecurrenceRule(recur); 176 setRecurrenceRule(prop); 177 return prop; 178 } 179 180 /** 181 * Sets how often the timezone observance repeats. 182 * @param recurrenceRule the recurrence rule or null to remove 183 * @see <a href="http://tools.ietf.org/html/rfc5545#page-122">RFC 5545 184 * p.122-32</a> 185 */ 186 public void setRecurrenceRule(RecurrenceRule recurrenceRule) { 187 setProperty(RecurrenceRule.class, recurrenceRule); 188 } 189 190 /** 191 * Gets the comments attached to the timezone observance. 192 * @return the comments 193 * @see <a href="http://tools.ietf.org/html/rfc5545#page-83">RFC 5545 194 * p.83-4</a> 195 */ 196 public List<Comment> getComments() { 197 return getProperties(Comment.class); 198 } 199 200 /** 201 * Adds a comment to the timezone observance. 202 * @param comment the comment to add 203 * @see <a href="http://tools.ietf.org/html/rfc5545#page-83">RFC 5545 204 * p.83-4</a> 205 */ 206 public void addComment(Comment comment) { 207 addProperty(comment); 208 } 209 210 /** 211 * Adds a comment to the timezone observance. 212 * @param comment the comment to add 213 * @return the property that was created 214 * @see <a href="http://tools.ietf.org/html/rfc5545#page-83">RFC 5545 215 * p.83-4</a> 216 */ 217 public Comment addComment(String comment) { 218 Comment prop = new Comment(comment); 219 addComment(prop); 220 return prop; 221 } 222 223 /** 224 * Gets the list of dates/periods that help define the recurrence rule of 225 * this timezone observance (if one is defined). 226 * @return the recurrence dates 227 * @see <a href="http://tools.ietf.org/html/rfc5545#page-120">RFC 5545 228 * p.120-2</a> 229 */ 230 public List<RecurrenceDates> getRecurrenceDates() { 231 return getProperties(RecurrenceDates.class); 232 } 233 234 /** 235 * Adds a list of dates/periods that help define the recurrence rule of this 236 * timezone observance (if one is defined). 237 * @param recurrenceDates the recurrence dates 238 * @see <a href="http://tools.ietf.org/html/rfc5545#page-120">RFC 5545 239 * p.120-2</a> 240 */ 241 public void addRecurrenceDates(RecurrenceDates recurrenceDates) { 242 addProperty(recurrenceDates); 243 } 244 245 /** 246 * Gets the traditional, non-standard names for the timezone observance. 247 * @return the timezone observance names 248 * @see <a href="http://tools.ietf.org/html/rfc5545#page-103">RFC 5545 249 * p.103-4</a> 250 */ 251 public List<TimezoneName> getTimezoneNames() { 252 return getProperties(TimezoneName.class); 253 } 254 255 /** 256 * Adds a traditional, non-standard name for the timezone observance. 257 * @param timezoneName the timezone observance name 258 * @see <a href="http://tools.ietf.org/html/rfc5545#page-103">RFC 5545 259 * p.103-4</a> 260 */ 261 public void addTimezoneName(TimezoneName timezoneName) { 262 addProperty(timezoneName); 263 } 264 265 /** 266 * Adds a traditional, non-standard name for the timezone observance. 267 * @param timezoneName the timezone observance name (e.g. "EST") 268 * @return the property that was created 269 * @see <a href="http://tools.ietf.org/html/rfc5545#page-103">RFC 5545 270 * p.103-4</a> 271 */ 272 public TimezoneName addTimezoneName(String timezoneName) { 273 TimezoneName prop = new TimezoneName(timezoneName); 274 addTimezoneName(prop); 275 return prop; 276 } 277 278 /** 279 * Gets the list of exceptions to the timezone observance. 280 * @return the list of exceptions 281 * @see <a href="http://tools.ietf.org/html/rfc5545#page-118">RFC 5545 282 * p.118-20</a> 283 */ 284 public List<ExceptionDates> getExceptionDates() { 285 return getProperties(ExceptionDates.class); 286 } 287 288 /** 289 * Adds a list of exceptions to the timezone observance. Note that this 290 * property can contain multiple dates. 291 * @param exceptionDates the list of exceptions 292 * @see <a href="http://tools.ietf.org/html/rfc5545#page-118">RFC 5545 293 * p.118-20</a> 294 */ 295 public void addExceptionDates(ExceptionDates exceptionDates) { 296 addProperty(exceptionDates); 297 } 298 299 @SuppressWarnings("unchecked") 300 @Override 301 protected void validate(List<ICalComponent> components, List<Warning> warnings) { 302 checkRequiredCardinality(warnings, DateStart.class, TimezoneOffsetTo.class, TimezoneOffsetFrom.class); 303 304 //BYHOUR, BYMINUTE, and BYSECOND cannot be specified in RRULE if DTSTART's data type is "date" 305 //RFC 5545 p. 167 306 DateStart dateStart = getDateStart(); 307 RecurrenceRule rrule = getRecurrenceRule(); 308 if (dateStart != null && rrule != null) { 309 Date start = dateStart.getValue(); 310 Recurrence recur = rrule.getValue(); 311 if (start != null && recur != null) { 312 if (!dateStart.hasTime() && (!recur.getByHour().isEmpty() || !recur.getByMinute().isEmpty() || !recur.getBySecond().isEmpty())) { 313 warnings.add(Warning.validate(5)); 314 } 315 } 316 } 317 318 //there *should* be only 1 instance of RRULE 319 //RFC 5545 p. 167 320 if (getProperties(RecurrenceRule.class).size() > 1) { 321 warnings.add(Warning.validate(6)); 322 } 323 } 324}