001 package ezvcard.property; 002 003 import java.util.List; 004 import java.util.SimpleTimeZone; 005 import java.util.TimeZone; 006 007 import ezvcard.VCard; 008 import ezvcard.VCardVersion; 009 import ezvcard.Warning; 010 import ezvcard.util.UtcOffset; 011 import ezvcard.util.VCardDateFormatter; 012 013 /* 014 Copyright (c) 2013, Michael Angstadt 015 All rights reserved. 016 017 Redistribution and use in source and binary forms, with or without 018 modification, are permitted provided that the following conditions are met: 019 020 1. Redistributions of source code must retain the above copyright notice, this 021 list of conditions and the following disclaimer. 022 2. Redistributions in binary form must reproduce the above copyright notice, 023 this list of conditions and the following disclaimer in the documentation 024 and/or other materials provided with the distribution. 025 026 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 027 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 028 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 029 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 030 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 031 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 032 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 033 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 034 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 035 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 036 037 The views and conclusions contained in the software and documentation are those 038 of the authors and should not be interpreted as representing official policies, 039 either expressed or implied, of the FreeBSD Project. 040 */ 041 042 /** 043 * Contains the timezone that the person lives/works in. 044 * 045 * <p> 046 * <b>Code sample</b> 047 * </p> 048 * 049 * <pre class="brush:java"> 050 * VCard vcard = new VCard(); 051 * Timezone tz = new Timezone(-5, 0, "America/New_York"); 052 * vcard.addTimezone(tz); 053 * </pre> 054 * 055 * <p> 056 * <b>Property name:</b> {@code TZ} 057 * </p> 058 * <p> 059 * <b>Supported versions:</b> {@code 2.1, 3.0, 4.0} 060 * </p> 061 * 062 * @author Michael Angstadt 063 */ 064 065 //@formatter:off 066 /* 067 * Parsing=================== 068 * 069 * vCard 2.1: 070 * Parse as UTC offset. If invalid, throw CannotParseException. 071 * 072 * vCard 3.0, hCard: 073 * VALUE=text: Treat as text 074 * No VALUE param: Parse as UTC offset. If invalid, add warning and treat as text. 075 * 076 * vCard 4.0, jCard: 077 * VALUE=text: Treat as text 078 * VALUE=utc-offset: Parse as UTC offset. If invalid, throw CannotParseException 079 * VALUE=uri: Not going to support this, as there is no description of what a timezone URI looks like 080 * No VALUE param: Parse as UTC offset. If invalid, treat as text 081 * 082 * xCard: 083 * text | utc-offset | result 084 * no | no | throw CannotParseException 085 * yes | no | OK 086 * no | yes | OK 087 * no | invalid | throw CannotParseException 088 * yes | yes | Parse text 089 * yes | invalid | Parse text 090 * 091 * Writing=================== 092 * 093 * vCard 2.1: 094 * text | utc-offset | result 095 * no | no | empty string (validation warning) 096 * no | yes | Write UTC offset 097 * yes | no | empty string (validation warning) 098 * yes | yes | Write UTC offset 099 * 100 * vCard 3.0: 101 * text | utc-offset | result 102 * no | no | empty string (validation warning) 103 * no | yes | Write UTC offset 104 * yes | no | Write text, add "VALUE=text" parameter 105 * yes | yes | Write UTC offset 106 * 107 * vCard 4.0, xCard, jCard: 108 * text | utc-offset | result 109 * no | no | empty string (validation warning) 110 * no | yes | Write UTC offset, add "VALUE=utc-offset" parameter 111 * yes | no | Write text 112 * yes | yes | Write text 113 */ 114 //@formatter:on 115 public class Timezone extends VCardProperty implements HasAltId { 116 private UtcOffset offset; 117 private String text; 118 119 /** 120 * Creates a timezone property. 121 * @param text a free-form string representing the timezone, preferably a 122 * timezone ID from the <a 123 * href="http://en.wikipedia.org/wiki/List_of_tz_database_time_zones">Olson 124 * Database</a> (e.g. "America/New_York") 125 */ 126 public Timezone(String text) { 127 this(null, text); 128 } 129 130 /** 131 * Creates a timezone property. 132 * @param hourOffset the hour component of the UTC offset (e.g. -5) 133 * @param minuteOffset the minute component of the UTC offset (e.g. 0) 134 */ 135 public Timezone(Integer hourOffset, Integer minuteOffset) { 136 this(new UtcOffset(hourOffset, minuteOffset)); 137 } 138 139 /** 140 * Creates a timezone property. 141 * @param offset the UTC offset 142 */ 143 public Timezone(UtcOffset offset) { 144 this(offset, null); 145 } 146 147 /** 148 * Creates a timezone property. 149 * @param hourOffset the hour component of the UTC offset (e.g. -5) 150 * @param minuteOffset the minute component of the UTC offset (e.g. 0) 151 * @param text a free-form string representing the timezone, preferably a 152 * timezone ID from the <a 153 * href="http://en.wikipedia.org/wiki/List_of_tz_database_time_zones">Olson 154 * Database</a> (e.g. "America/New_York") 155 */ 156 public Timezone(Integer hourOffset, Integer minuteOffset, String text) { 157 this(new UtcOffset(hourOffset, minuteOffset), text); 158 } 159 160 /** 161 * Creates a timezone property. 162 * @param offset the UTC offset 163 * @param text a free-form string representing the timezone, preferably a 164 * timezone ID from the <a 165 * href="http://en.wikipedia.org/wiki/List_of_tz_database_time_zones">Olson 166 * Database</a> (e.g. "America/New_York") 167 */ 168 public Timezone(UtcOffset offset, String text) { 169 setOffset(offset); 170 setText(text); 171 } 172 173 /** 174 * Creates a timezone property. 175 * @param timezone the timezone 176 */ 177 public Timezone(TimeZone timezone) { 178 this(UtcOffset.parse(timezone), timezone.getID()); 179 } 180 181 /** 182 * Gets the hour component of the UTC offset. 183 * @return the hour component of the UTC offset or null if not set 184 */ 185 public Integer getHourOffset() { 186 return (offset == null) ? null : offset.getHour(); 187 } 188 189 /** 190 * Gets the minute component of the UTC offset. 191 * @return the minute component of the UTC offset or null if not set 192 */ 193 public Integer getMinuteOffset() { 194 return (offset == null) ? null : offset.getMinute(); 195 } 196 197 /** 198 * Gets the UTC offset. 199 * @return the UTC offset or null if not set 200 */ 201 public UtcOffset getOffset() { 202 return offset; 203 } 204 205 /** 206 * Sets the UTC offset. 207 * @param hourOffset the hour offset (e.g. -5) 208 * @param minuteOffset the minute offset (e.g. 0) 209 */ 210 public void setOffset(int hourOffset, int minuteOffset) { 211 setOffset(new UtcOffset(hourOffset, minuteOffset)); 212 } 213 214 /** 215 * Sets the UTC offset. 216 * @param offset the UTC offset 217 */ 218 public void setOffset(UtcOffset offset) { 219 this.offset = offset; 220 } 221 222 /** 223 * Gets the text portion of the timezone. 224 * @return the free-form string representing the timezone, such as a 225 * timezone ID from the <a 226 * href="http://en.wikipedia.org/wiki/List_of_tz_database_time_zones">Olson 227 * Database</a> (e.g. "America/New_York") 228 */ 229 public String getText() { 230 return text; 231 } 232 233 /** 234 * Sets the text portion of the timezone. 235 * @param text a free-form string representing the timezone, preferably a 236 * timezone ID from the <a 237 * href="http://en.wikipedia.org/wiki/List_of_tz_database_time_zones">Olson 238 * Database</a> (e.g. "America/New_York") 239 */ 240 public void setText(String text) { 241 this.text = text; 242 } 243 244 /** 245 * Creates a {@link java.util.TimeZone} representation of this class. 246 * @return a {@link TimeZone} object or null if this object contains no 247 * offset data 248 */ 249 public TimeZone toTimeZone() { 250 if (text != null) { 251 TimeZone timezone = VCardDateFormatter.parseTimeZoneId(text); 252 if (timezone != null) { 253 return timezone; 254 } 255 } 256 257 if (offset != null) { 258 int rawHourOffset = offset.getHour() * 60 * 60 * 1000; 259 int rawMinuteOffset = offset.getMinute() * 60 * 1000; 260 if (rawHourOffset < 0) { 261 rawMinuteOffset *= -1; 262 } 263 int rawOffset = rawHourOffset + rawMinuteOffset; 264 265 String id = (text == null) ? "" : text; 266 267 return new SimpleTimeZone(rawOffset, id); 268 } 269 270 return null; 271 } 272 273 /** 274 * Gets the TYPE parameter. 275 * <p> 276 * <b>Supported versions:</b> {@code 4.0} 277 * </p> 278 * @return the TYPE value (typically, this will be either "work" or "home") 279 * or null if it doesn't exist 280 */ 281 public String getType() { 282 return parameters.getType(); 283 } 284 285 /** 286 * Sets the TYPE parameter. 287 * <p> 288 * <b>Supported versions:</b> {@code 4.0} 289 * </p> 290 * @param type the TYPE value (this should be either "work" or "home") or 291 * null to remove 292 */ 293 public void setType(String type) { 294 parameters.setType(type); 295 } 296 297 /** 298 * Gets the MEDIATYPE parameter. 299 * <p> 300 * <b>Supported versions:</b> {@code 4.0} 301 * </p> 302 * @return the media type or null if not set 303 */ 304 public String getMediaType() { 305 return parameters.getMediaType(); 306 } 307 308 /** 309 * Sets the MEDIATYPE parameter. 310 * <p> 311 * <b>Supported versions:</b> {@code 4.0} 312 * </p> 313 * @param mediaType the media type or null to remove 314 */ 315 public void setMediaType(String mediaType) { 316 parameters.setMediaType(mediaType); 317 } 318 319 @Override 320 public List<Integer[]> getPids() { 321 return super.getPids(); 322 } 323 324 @Override 325 public void addPid(int localId, int clientPidMapRef) { 326 super.addPid(localId, clientPidMapRef); 327 } 328 329 @Override 330 public void removePids() { 331 super.removePids(); 332 } 333 334 @Override 335 public Integer getPref() { 336 return super.getPref(); 337 } 338 339 @Override 340 public void setPref(Integer pref) { 341 super.setPref(pref); 342 } 343 344 //@Override 345 public String getAltId() { 346 return parameters.getAltId(); 347 } 348 349 //@Override 350 public void setAltId(String altId) { 351 parameters.setAltId(altId); 352 } 353 354 @Override 355 protected void _validate(List<Warning> warnings, VCardVersion version, VCard vcard) { 356 if (offset == null && text == null) { 357 warnings.add(new Warning(8)); 358 } 359 if (offset == null && version == VCardVersion.V2_1) { 360 warnings.add(new Warning(20)); 361 } 362 if (offset != null && (offset.getMinute() < 0 || offset.getMinute() > 59)) { 363 warnings.add(new Warning(21)); 364 } 365 } 366 }