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 }