001package ezvcard.property; 002 003import java.time.DateTimeException; 004import java.time.OffsetDateTime; 005import java.time.ZoneId; 006import java.time.ZoneOffset; 007import java.util.LinkedHashMap; 008import java.util.List; 009import java.util.Map; 010 011import ezvcard.VCard; 012import ezvcard.VCardVersion; 013import ezvcard.ValidationWarning; 014import ezvcard.parameter.Pid; 015 016/* 017 Copyright (c) 2012-2023, Michael Angstadt 018 All rights reserved. 019 020 Redistribution and use in source and binary forms, with or without 021 modification, are permitted provided that the following conditions are met: 022 023 1. Redistributions of source code must retain the above copyright notice, this 024 list of conditions and the following disclaimer. 025 2. Redistributions in binary form must reproduce the above copyright notice, 026 this list of conditions and the following disclaimer in the documentation 027 and/or other materials provided with the distribution. 028 029 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 030 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 031 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 032 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 033 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 034 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 035 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 036 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 037 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 038 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 039 040 The views and conclusions contained in the software and documentation are those 041 of the authors and should not be interpreted as representing official policies, 042 either expressed or implied, of the FreeBSD Project. 043 */ 044 045/** 046 * <p> 047 * Defines the timezone that the person lives/works in. 048 * </p> 049 * 050 * <p> 051 * <b>Code sample</b> 052 * </p> 053 * 054 * <pre class="brush:java"> 055 * VCard vcard = new VCard(); 056 * 057 * Timezone tz = new Timezone(ZoneOffset.ofHours(-5), "America/New_York"); 058 * vcard.addTimezone(tz); 059 * 060 * //using a Java "ZoneId" object 061 * ZoneId zoneId = ZoneId.of("America/New_York"); 062 * tz = new Timezone(zoneId); 063 * vcard.addTimezone(tz); 064 * </pre> 065 * 066 * <p> 067 * <b>Property name:</b> {@code TZ} 068 * </p> 069 * <p> 070 * <b>Supported versions:</b> {@code 2.1, 3.0, 4.0} 071 * </p> 072 * 073 * @author Michael Angstadt 074 * @see <a href="http://tools.ietf.org/html/rfc6350#page-22">RFC 6350 p.22</a> 075 * @see <a href="http://tools.ietf.org/html/rfc2426#page-16">RFC 2426 p.16</a> 076 * @see <a href="http://www.imc.org/pdi/vcard-21.doc">vCard 2.1 p.16</a> 077 */ 078public class Timezone extends VCardProperty implements HasAltId { 079 private ZoneOffset offset; 080 private String text; 081 082 /** 083 * Creates a timezone property. 084 * @param text a free-form string representing the timezone, preferably a 085 * timezone ID from the <a 086 * href="http://en.wikipedia.org/wiki/List_of_tz_database_time_zones">Olson 087 * Database</a> (e.g. "America/New_York") 088 */ 089 public Timezone(String text) { 090 this(null, text); 091 } 092 093 /** 094 * Creates a timezone property. 095 * @param offset the UTC offset 096 */ 097 public Timezone(ZoneOffset offset) { 098 this(offset, null); 099 } 100 101 /** 102 * Creates a timezone property. 103 * @param offset the UTC offset 104 * @param text a free-form string representing the timezone, preferably a 105 * timezone ID from the <a 106 * href="http://en.wikipedia.org/wiki/List_of_tz_database_time_zones">Olson 107 * Database</a> (e.g. "America/New_York") 108 */ 109 public Timezone(ZoneOffset offset, String text) { 110 setOffset(offset); 111 setText(text); 112 } 113 114 /** 115 * Creates a timezone property. 116 * @param timezone the timezone 117 */ 118 public Timezone(ZoneId timezone) { 119 this(OffsetDateTime.now(timezone).getOffset(), timezone.getId()); 120 } 121 122 /** 123 * Copy constructor. 124 * @param original the property to make a copy of 125 */ 126 public Timezone(Timezone original) { 127 super(original); 128 offset = original.offset; 129 text = original.text; 130 } 131 132 /** 133 * Gets the UTC offset. 134 * @return the UTC offset or null if not set 135 */ 136 public ZoneOffset getOffset() { 137 return offset; 138 } 139 140 /** 141 * Sets the UTC offset. 142 * @param offset the UTC offset 143 */ 144 public void setOffset(ZoneOffset offset) { 145 this.offset = offset; 146 } 147 148 /** 149 * Gets the text portion of the timezone. 150 * @return the free-form string representing the timezone, such as a 151 * timezone ID from the <a 152 * href="http://en.wikipedia.org/wiki/List_of_tz_database_time_zones">Olson 153 * Database</a> (e.g. "America/New_York") 154 */ 155 public String getText() { 156 return text; 157 } 158 159 /** 160 * Sets the text portion of the timezone. 161 * @param text a free-form string representing the timezone, preferably a 162 * timezone ID from the <a 163 * href="http://en.wikipedia.org/wiki/List_of_tz_database_time_zones">Olson 164 * Database</a> (e.g. "America/New_York") 165 */ 166 public void setText(String text) { 167 this.text = text; 168 } 169 170 /** 171 * Creates a {@link ZoneId} representation of this class. 172 * @return a {@link ZoneId} object or null if this object contains no 173 * offset data 174 */ 175 public ZoneId toTimeZone() { 176 if (text != null) { 177 try { 178 return ZoneId.of(text); 179 } catch (DateTimeException ignore) { 180 //not a recognized timezone 181 } 182 } 183 184 if (offset != null) { 185 return offset; 186 } 187 188 return null; 189 } 190 191 /** 192 * Gets the TYPE parameter. 193 * <p> 194 * <b>Supported versions:</b> {@code 4.0} 195 * </p> 196 * @return the TYPE value (typically, this will be either "work" or "home") 197 * or null if it doesn't exist 198 */ 199 public String getType() { 200 return parameters.getType(); 201 } 202 203 /** 204 * Sets the TYPE parameter. 205 * <p> 206 * <b>Supported versions:</b> {@code 4.0} 207 * </p> 208 * @param type the TYPE value (this should be either "work" or "home") or 209 * null to remove 210 */ 211 public void setType(String type) { 212 parameters.setType(type); 213 } 214 215 /** 216 * Gets the MEDIATYPE parameter. 217 * <p> 218 * <b>Supported versions:</b> {@code 4.0} 219 * </p> 220 * @return the media type or null if not set 221 */ 222 public String getMediaType() { 223 return parameters.getMediaType(); 224 } 225 226 /** 227 * Sets the MEDIATYPE parameter. 228 * <p> 229 * <b>Supported versions:</b> {@code 4.0} 230 * </p> 231 * @param mediaType the media type or null to remove 232 */ 233 public void setMediaType(String mediaType) { 234 parameters.setMediaType(mediaType); 235 } 236 237 @Override 238 public List<Pid> getPids() { 239 return super.getPids(); 240 } 241 242 @Override 243 public Integer getPref() { 244 return super.getPref(); 245 } 246 247 @Override 248 public void setPref(Integer pref) { 249 super.setPref(pref); 250 } 251 252 //@Override 253 public String getAltId() { 254 return parameters.getAltId(); 255 } 256 257 //@Override 258 public void setAltId(String altId) { 259 parameters.setAltId(altId); 260 } 261 262 @Override 263 protected void _validate(List<ValidationWarning> warnings, VCardVersion version, VCard vcard) { 264 if (offset == null && text == null) { 265 warnings.add(new ValidationWarning(8)); 266 } 267 if (offset == null && version == VCardVersion.V2_1) { 268 warnings.add(new ValidationWarning(20)); 269 } 270 } 271 272 @Override 273 protected Map<String, Object> toStringValues() { 274 Map<String, Object> values = new LinkedHashMap<>(); 275 values.put("offset", offset); 276 values.put("text", text); 277 return values; 278 } 279 280 @Override 281 public Timezone copy() { 282 return new Timezone(this); 283 } 284 285 @Override 286 public int hashCode() { 287 final int prime = 31; 288 int result = super.hashCode(); 289 result = prime * result + ((offset == null) ? 0 : offset.hashCode()); 290 result = prime * result + ((text == null) ? 0 : text.hashCode()); 291 return result; 292 } 293 294 @Override 295 public boolean equals(Object obj) { 296 if (this == obj) return true; 297 if (!super.equals(obj)) return false; 298 Timezone other = (Timezone) obj; 299 if (offset == null) { 300 if (other.offset != null) return false; 301 } else if (!offset.equals(other.offset)) return false; 302 if (text == null) { 303 if (other.text != null) return false; 304 } else if (!text.equals(other.text)) return false; 305 return true; 306 } 307}