62 package java.time.zone; |
62 package java.time.zone; |
63 |
63 |
64 import java.io.DataInput; |
64 import java.io.DataInput; |
65 import java.io.DataOutput; |
65 import java.io.DataOutput; |
66 import java.io.IOException; |
66 import java.io.IOException; |
|
67 import java.io.InvalidObjectException; |
67 import java.io.Serializable; |
68 import java.io.Serializable; |
68 import java.time.Duration; |
69 import java.time.Duration; |
69 import java.time.Instant; |
70 import java.time.Instant; |
70 import java.time.LocalDate; |
71 import java.time.LocalDate; |
71 import java.time.LocalDateTime; |
72 import java.time.LocalDateTime; |
143 */ |
144 */ |
144 private final ZoneOffsetTransitionRule[] lastRules; |
145 private final ZoneOffsetTransitionRule[] lastRules; |
145 /** |
146 /** |
146 * The map of recent transitions. |
147 * The map of recent transitions. |
147 */ |
148 */ |
148 private final ConcurrentMap<Integer, ZoneOffsetTransition[]> lastRulesCache = |
149 private final transient ConcurrentMap<Integer, ZoneOffsetTransition[]> lastRulesCache = |
149 new ConcurrentHashMap<Integer, ZoneOffsetTransition[]>(); |
150 new ConcurrentHashMap<Integer, ZoneOffsetTransition[]>(); |
150 /** |
151 /** |
151 * The zero-length long array. |
152 * The zero-length long array. |
152 */ |
153 */ |
153 private static final long[] EMPTY_LONG_ARRAY = new long[0]; |
154 private static final long[] EMPTY_LONG_ARRAY = new long[0]; |
313 this.wallOffsets = standardOffsets; |
314 this.wallOffsets = standardOffsets; |
314 this.lastRules = EMPTY_LASTRULES; |
315 this.lastRules = EMPTY_LASTRULES; |
315 } |
316 } |
316 |
317 |
317 /** |
318 /** |
318 * Uses a serialization delegate. |
319 * Defend against malicious streams. |
319 * |
320 * @return never |
|
321 * @throws InvalidObjectException always |
|
322 */ |
|
323 private Object readResolve() throws InvalidObjectException { |
|
324 throw new InvalidObjectException("Deserialization via serialization delegate"); |
|
325 } |
|
326 |
|
327 /** |
|
328 * Writes the object using a |
|
329 * <a href="../../../serialized-form.html#java.time.zone.Ser">dedicated serialized form</a>. |
|
330 * @serialData |
|
331 * <pre style="font-size:1.0em">{@code |
|
332 * |
|
333 * out.writeByte(1); // identifies a ZoneRules |
|
334 * out.writeInt(standardTransitions.length); |
|
335 * for (long trans : standardTransitions) { |
|
336 * Ser.writeEpochSec(trans, out); |
|
337 * } |
|
338 * for (ZoneOffset offset : standardOffsets) { |
|
339 * Ser.writeOffset(offset, out); |
|
340 * } |
|
341 * out.writeInt(savingsInstantTransitions.length); |
|
342 * for (long trans : savingsInstantTransitions) { |
|
343 * Ser.writeEpochSec(trans, out); |
|
344 * } |
|
345 * for (ZoneOffset offset : wallOffsets) { |
|
346 * Ser.writeOffset(offset, out); |
|
347 * } |
|
348 * out.writeByte(lastRules.length); |
|
349 * for (ZoneOffsetTransitionRule rule : lastRules) { |
|
350 * rule.writeExternal(out); |
|
351 * } |
|
352 * } |
|
353 * </pre> |
|
354 * <p> |
|
355 * Epoch second values used for offsets are encoded in a variable |
|
356 * length form to make the common cases put fewer bytes in the stream. |
|
357 * <pre style="font-size:1.0em">{@code |
|
358 * |
|
359 * static void writeEpochSec(long epochSec, DataOutput out) throws IOException { |
|
360 * if (epochSec >= -4575744000L && epochSec < 10413792000L && epochSec % 900 == 0) { // quarter hours between 1825 and 2300 |
|
361 * int store = (int) ((epochSec + 4575744000L) / 900); |
|
362 * out.writeByte((store >>> 16) & 255); |
|
363 * out.writeByte((store >>> 8) & 255); |
|
364 * out.writeByte(store & 255); |
|
365 * } else { |
|
366 * out.writeByte(255); |
|
367 * out.writeLong(epochSec); |
|
368 * } |
|
369 * } |
|
370 * } |
|
371 * </pre> |
|
372 * <p> |
|
373 * ZoneOffset values are encoded in a variable length form so the |
|
374 * common cases put fewer bytes in the stream. |
|
375 * <pre style="font-size:1.0em">{@code |
|
376 * |
|
377 * static void writeOffset(ZoneOffset offset, DataOutput out) throws IOException { |
|
378 * final int offsetSecs = offset.getTotalSeconds(); |
|
379 * int offsetByte = offsetSecs % 900 == 0 ? offsetSecs / 900 : 127; // compress to -72 to +72 |
|
380 * out.writeByte(offsetByte); |
|
381 * if (offsetByte == 127) { |
|
382 * out.writeInt(offsetSecs); |
|
383 * } |
|
384 * } |
|
385 *} |
|
386 * </pre> |
320 * @return the replacing object, not null |
387 * @return the replacing object, not null |
321 */ |
388 */ |
322 private Object writeReplace() { |
389 private Object writeReplace() { |
323 return new Ser(Ser.ZRULES, this); |
390 return new Ser(Ser.ZRULES, this); |
324 } |
391 } |