1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package net.fortuna.ical4j.model.component;
35
36 import java.io.IOException;
37 import java.util.TimeZone;
38
39 import net.fortuna.ical4j.data.BuilderException;
40 import net.fortuna.ical4j.data.CalendarBuilder;
41 import net.fortuna.ical4j.model.Calendar;
42 import net.fortuna.ical4j.model.Component;
43 import net.fortuna.ical4j.model.ComponentList;
44 import net.fortuna.ical4j.model.ParameterList;
45 import net.fortuna.ical4j.model.Property;
46 import net.fortuna.ical4j.model.PropertyList;
47 import net.fortuna.ical4j.model.ValidationException;
48 import net.fortuna.ical4j.model.property.DtStart;
49 import net.fortuna.ical4j.model.property.TzId;
50 import net.fortuna.ical4j.model.property.TzName;
51 import net.fortuna.ical4j.model.property.TzOffsetFrom;
52 import net.fortuna.ical4j.model.property.TzOffsetTo;
53 import net.fortuna.ical4j.util.PropertyValidator;
54 import net.fortuna.ical4j.util.TimeZoneUtils;
55
56 import org.apache.commons.logging.Log;
57 import org.apache.commons.logging.LogFactory;
58
59 /***
60 * Defines an iCalendar VTIMEZONE component.
61 *
62 * @author benf
63 */
64 public class VTimeZone extends Component {
65
66 /***
67 * 'tzid' is required, but MUST NOT occur more than once
68 */
69 public static final String TZID = "TZID";
70
71 /***
72 * 'last-mod' and 'tzurl' are optional, but MUST NOT occur more than once
73 */
74 public static final String LAST_MOD = "LAST-MOD";
75
76 public static final String TZURL = "TZURL";
77
78 private static Log log = LogFactory.getLog(VTimeZone.class);
79
80 private ComponentList types;
81
82 /***
83 * Constructor.
84 *
85 * @param aList
86 * a list of properties
87 * @param cList
88 * a list of timezone types
89 */
90 public VTimeZone(final PropertyList aList, final ComponentList cList) {
91
92 super(VTIMEZONE, aList);
93
94 this.types = cList;
95 }
96
97 /***
98 * @see java.lang.Object#toString()
99 */
100 public final String toString() {
101
102 return BEGIN + ":" + getName() + "\r\n" + getProperties() + types + END
103 + ":" + getName() + "\r\n";
104 }
105
106
107
108
109
110
111 public final void validate(boolean recurse) throws ValidationException {
112
113
114
115
116
117
118 PropertyValidator.getInstance().validateOne(Property.TZID,
119 getProperties());
120
121
122
123
124
125 PropertyValidator.getInstance().validateOneOrLess(
126 Property.LAST_MODIFIED, getProperties());
127 PropertyValidator.getInstance().validateOneOrLess(Property.TZURL,
128 getProperties());
129
130
131
132
133
134
135
136 if (types.getComponent(Time.STANDARD) == null
137 && types.getComponent(Time.DAYLIGHT) == null) { throw new ValidationException(
138 "Sub-components [" + Time.STANDARD + "," + Time.DAYLIGHT
139 + "] must be specified at least once"); }
140
141
142
143
144
145
146
147 if (recurse) {
148 validateProperties();
149 }
150 }
151
152 /***
153 * Returns an instance of VTimeZone representing the user's default timezone.
154 * @return a VTimeZone
155 */
156 public static VTimeZone getDefault() {
157 return getVTimeZone(TimeZone.getDefault());
158 }
159
160 /***
161 * Returns an instance of VTimeZone representing the specified Java timezone.
162 * @return a VTimeZone
163 */
164 public static VTimeZone getVTimeZone(final TimeZone timezone) {
165 try {
166 VTimeZone vTimezone = loadVTimeZone(timezone);
167
168 if (vTimezone != null) {
169 return vTimezone;
170 }
171 }
172 catch (Exception e) {
173 log.debug("Error loading VTimeZone", e);
174 }
175
176 return createVTimeZone(timezone);
177 }
178
179 /***
180 * Loads an existing VTimeZone from the classpath corresponding
181 * to the specified Java timezone.
182 */
183 private static VTimeZone loadVTimeZone(final TimeZone timezone) throws IOException, BuilderException {
184 String resource = "/" + timezone.getID() + ".ics";
185
186 CalendarBuilder builder = new CalendarBuilder();
187
188 Calendar calendar = builder.build(VTimeZone.class.getResourceAsStream(resource));
189
190 return (VTimeZone) calendar.getComponents().getComponent(Component.VTIMEZONE);
191 }
192
193 /***
194 * Creates a new VTimeZone based on the specified Java timezone.
195 */
196 private static VTimeZone createVTimeZone(final TimeZone timezone) {
197 TzId tzId = new TzId(null, timezone.getID());
198
199 PropertyList tzProps = new PropertyList();
200 tzProps.add(tzId);
201
202 ComponentList tzComponents = new ComponentList();
203
204 TzName standardTzName = new TzName(new ParameterList(), timezone.getDisplayName());
205 DtStart standardTzStart = new DtStart(new ParameterList(), TimeZoneUtils.getDaylightEnd(timezone));
206 TzOffsetTo standardTzOffsetTo = new TzOffsetTo(new ParameterList(), timezone.getRawOffset());
207 TzOffsetFrom standardTzOffsetFrom = new TzOffsetFrom(null, timezone.getRawOffset() + timezone.getDSTSavings());
208
209 PropertyList standardTzProps = new PropertyList();
210 standardTzProps.add(standardTzName);
211 standardTzProps.add(standardTzStart);
212 standardTzProps.add(standardTzOffsetTo);
213 standardTzProps.add(standardTzOffsetFrom);
214
215 tzComponents.add(new Standard(standardTzProps));
216
217 if (timezone.useDaylightTime()) {
218 TzName daylightTzName = new TzName(new ParameterList(), timezone.getDisplayName() + " (DST)");
219 DtStart daylightTzStart = new DtStart(new ParameterList(), TimeZoneUtils.getDaylightStart(timezone));
220 TzOffsetTo daylightTzOffsetTo = new TzOffsetTo(new ParameterList(), timezone.getRawOffset() + timezone.getDSTSavings());
221 TzOffsetFrom daylightTzOffsetFrom = new TzOffsetFrom(null, timezone.getRawOffset());
222
223 PropertyList daylightTzProps = new PropertyList();
224 daylightTzProps.add(daylightTzName);
225 daylightTzProps.add(daylightTzStart);
226 daylightTzProps.add(daylightTzOffsetTo);
227 daylightTzProps.add(daylightTzOffsetFrom);
228
229 tzComponents.add(new Daylight(daylightTzProps));
230 }
231
232 return new VTimeZone(tzProps, tzComponents);
233 }
234 }