Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/java/time/zone/ZoneOffsetTransitionRule.java
38918 views
1
/*
2
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
/*
27
* This file is available under and governed by the GNU General Public
28
* License version 2 only, as published by the Free Software Foundation.
29
* However, the following notice accompanied the original version of this
30
* file:
31
*
32
* Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
33
*
34
* All rights reserved.
35
*
36
* Redistribution and use in source and binary forms, with or without
37
* modification, are permitted provided that the following conditions are met:
38
*
39
* * Redistributions of source code must retain the above copyright notice,
40
* this list of conditions and the following disclaimer.
41
*
42
* * Redistributions in binary form must reproduce the above copyright notice,
43
* this list of conditions and the following disclaimer in the documentation
44
* and/or other materials provided with the distribution.
45
*
46
* * Neither the name of JSR-310 nor the names of its contributors
47
* may be used to endorse or promote products derived from this software
48
* without specific prior written permission.
49
*
50
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
51
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
52
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
53
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
54
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
55
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
56
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
57
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
58
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
59
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
60
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
61
*/
62
package java.time.zone;
63
64
import static java.time.temporal.TemporalAdjusters.nextOrSame;
65
import static java.time.temporal.TemporalAdjusters.previousOrSame;
66
67
import java.io.DataInput;
68
import java.io.DataOutput;
69
import java.io.IOException;
70
import java.io.InvalidObjectException;
71
import java.io.ObjectInputStream;
72
import java.io.Serializable;
73
import java.time.DayOfWeek;
74
import java.time.LocalDate;
75
import java.time.LocalDateTime;
76
import java.time.LocalTime;
77
import java.time.Month;
78
import java.time.ZoneOffset;
79
import java.time.chrono.IsoChronology;
80
import java.util.Objects;
81
82
/**
83
* A rule expressing how to create a transition.
84
* <p>
85
* This class allows rules for identifying future transitions to be expressed.
86
* A rule might be written in many forms:
87
* <ul>
88
* <li>the 16th March
89
* <li>the Sunday on or after the 16th March
90
* <li>the Sunday on or before the 16th March
91
* <li>the last Sunday in February
92
* </ul>
93
* These different rule types can be expressed and queried.
94
*
95
* @implSpec
96
* This class is immutable and thread-safe.
97
*
98
* @since 1.8
99
*/
100
public final class ZoneOffsetTransitionRule implements Serializable {
101
102
/**
103
* Serialization version.
104
*/
105
private static final long serialVersionUID = 6889046316657758795L;
106
107
/**
108
* The month of the month-day of the first day of the cutover week.
109
* The actual date will be adjusted by the dowChange field.
110
*/
111
private final Month month;
112
/**
113
* The day-of-month of the month-day of the cutover week.
114
* If positive, it is the start of the week where the cutover can occur.
115
* If negative, it represents the end of the week where cutover can occur.
116
* The value is the number of days from the end of the month, such that
117
* {@code -1} is the last day of the month, {@code -2} is the second
118
* to last day, and so on.
119
*/
120
private final byte dom;
121
/**
122
* The cutover day-of-week, null to retain the day-of-month.
123
*/
124
private final DayOfWeek dow;
125
/**
126
* The cutover time in the 'before' offset.
127
*/
128
private final LocalTime time;
129
/**
130
* Whether the cutover time is midnight at the end of day.
131
*/
132
private final boolean timeEndOfDay;
133
/**
134
* The definition of how the local time should be interpreted.
135
*/
136
private final TimeDefinition timeDefinition;
137
/**
138
* The standard offset at the cutover.
139
*/
140
private final ZoneOffset standardOffset;
141
/**
142
* The offset before the cutover.
143
*/
144
private final ZoneOffset offsetBefore;
145
/**
146
* The offset after the cutover.
147
*/
148
private final ZoneOffset offsetAfter;
149
150
/**
151
* Obtains an instance defining the yearly rule to create transitions between two offsets.
152
* <p>
153
* Applications should normally obtain an instance from {@link ZoneRules}.
154
* This factory is only intended for use when creating {@link ZoneRules}.
155
*
156
* @param month the month of the month-day of the first day of the cutover week, not null
157
* @param dayOfMonthIndicator the day of the month-day of the cutover week, positive if the week is that
158
* day or later, negative if the week is that day or earlier, counting from the last day of the month,
159
* from -28 to 31 excluding 0
160
* @param dayOfWeek the required day-of-week, null if the month-day should not be changed
161
* @param time the cutover time in the 'before' offset, not null
162
* @param timeEndOfDay whether the time is midnight at the end of day
163
* @param timeDefnition how to interpret the cutover
164
* @param standardOffset the standard offset in force at the cutover, not null
165
* @param offsetBefore the offset before the cutover, not null
166
* @param offsetAfter the offset after the cutover, not null
167
* @return the rule, not null
168
* @throws IllegalArgumentException if the day of month indicator is invalid
169
* @throws IllegalArgumentException if the end of day flag is true when the time is not midnight
170
*/
171
public static ZoneOffsetTransitionRule of(
172
Month month,
173
int dayOfMonthIndicator,
174
DayOfWeek dayOfWeek,
175
LocalTime time,
176
boolean timeEndOfDay,
177
TimeDefinition timeDefnition,
178
ZoneOffset standardOffset,
179
ZoneOffset offsetBefore,
180
ZoneOffset offsetAfter) {
181
Objects.requireNonNull(month, "month");
182
Objects.requireNonNull(time, "time");
183
Objects.requireNonNull(timeDefnition, "timeDefnition");
184
Objects.requireNonNull(standardOffset, "standardOffset");
185
Objects.requireNonNull(offsetBefore, "offsetBefore");
186
Objects.requireNonNull(offsetAfter, "offsetAfter");
187
if (dayOfMonthIndicator < -28 || dayOfMonthIndicator > 31 || dayOfMonthIndicator == 0) {
188
throw new IllegalArgumentException("Day of month indicator must be between -28 and 31 inclusive excluding zero");
189
}
190
if (timeEndOfDay && time.equals(LocalTime.MIDNIGHT) == false) {
191
throw new IllegalArgumentException("Time must be midnight when end of day flag is true");
192
}
193
return new ZoneOffsetTransitionRule(month, dayOfMonthIndicator, dayOfWeek, time, timeEndOfDay, timeDefnition, standardOffset, offsetBefore, offsetAfter);
194
}
195
196
/**
197
* Creates an instance defining the yearly rule to create transitions between two offsets.
198
*
199
* @param month the month of the month-day of the first day of the cutover week, not null
200
* @param dayOfMonthIndicator the day of the month-day of the cutover week, positive if the week is that
201
* day or later, negative if the week is that day or earlier, counting from the last day of the month,
202
* from -28 to 31 excluding 0
203
* @param dayOfWeek the required day-of-week, null if the month-day should not be changed
204
* @param time the cutover time in the 'before' offset, not null
205
* @param timeEndOfDay whether the time is midnight at the end of day
206
* @param timeDefnition how to interpret the cutover
207
* @param standardOffset the standard offset in force at the cutover, not null
208
* @param offsetBefore the offset before the cutover, not null
209
* @param offsetAfter the offset after the cutover, not null
210
* @throws IllegalArgumentException if the day of month indicator is invalid
211
* @throws IllegalArgumentException if the end of day flag is true when the time is not midnight
212
*/
213
ZoneOffsetTransitionRule(
214
Month month,
215
int dayOfMonthIndicator,
216
DayOfWeek dayOfWeek,
217
LocalTime time,
218
boolean timeEndOfDay,
219
TimeDefinition timeDefnition,
220
ZoneOffset standardOffset,
221
ZoneOffset offsetBefore,
222
ZoneOffset offsetAfter) {
223
this.month = month;
224
this.dom = (byte) dayOfMonthIndicator;
225
this.dow = dayOfWeek;
226
this.time = time;
227
this.timeEndOfDay = timeEndOfDay;
228
this.timeDefinition = timeDefnition;
229
this.standardOffset = standardOffset;
230
this.offsetBefore = offsetBefore;
231
this.offsetAfter = offsetAfter;
232
}
233
234
//-----------------------------------------------------------------------
235
/**
236
* Defend against malicious streams.
237
*
238
* @param s the stream to read
239
* @throws InvalidObjectException always
240
*/
241
private void readObject(ObjectInputStream s) throws InvalidObjectException {
242
throw new InvalidObjectException("Deserialization via serialization delegate");
243
}
244
245
/**
246
* Writes the object using a
247
* <a href="../../../serialized-form.html#java.time.zone.Ser">dedicated serialized form</a>.
248
* @serialData
249
* Refer to the serialized form of
250
* <a href="../../../serialized-form.html#java.time.zone.ZoneRules">ZoneRules.writeReplace</a>
251
* for the encoding of epoch seconds and offsets.
252
* <pre style="font-size:1.0em">{@code
253
*
254
* out.writeByte(3); // identifies a ZoneOffsetTransition
255
* final int timeSecs = (timeEndOfDay ? 86400 : time.toSecondOfDay());
256
* final int stdOffset = standardOffset.getTotalSeconds();
257
* final int beforeDiff = offsetBefore.getTotalSeconds() - stdOffset;
258
* final int afterDiff = offsetAfter.getTotalSeconds() - stdOffset;
259
* final int timeByte = (timeSecs % 3600 == 0 ? (timeEndOfDay ? 24 : time.getHour()) : 31);
260
* final int stdOffsetByte = (stdOffset % 900 == 0 ? stdOffset / 900 + 128 : 255);
261
* final int beforeByte = (beforeDiff == 0 || beforeDiff == 1800 || beforeDiff == 3600 ? beforeDiff / 1800 : 3);
262
* final int afterByte = (afterDiff == 0 || afterDiff == 1800 || afterDiff == 3600 ? afterDiff / 1800 : 3);
263
* final int dowByte = (dow == null ? 0 : dow.getValue());
264
* int b = (month.getValue() << 28) + // 4 bits
265
* ((dom + 32) << 22) + // 6 bits
266
* (dowByte << 19) + // 3 bits
267
* (timeByte << 14) + // 5 bits
268
* (timeDefinition.ordinal() << 12) + // 2 bits
269
* (stdOffsetByte << 4) + // 8 bits
270
* (beforeByte << 2) + // 2 bits
271
* afterByte; // 2 bits
272
* out.writeInt(b);
273
* if (timeByte == 31) {
274
* out.writeInt(timeSecs);
275
* }
276
* if (stdOffsetByte == 255) {
277
* out.writeInt(stdOffset);
278
* }
279
* if (beforeByte == 3) {
280
* out.writeInt(offsetBefore.getTotalSeconds());
281
* }
282
* if (afterByte == 3) {
283
* out.writeInt(offsetAfter.getTotalSeconds());
284
* }
285
* }
286
* </pre>
287
*
288
* @return the replacing object, not null
289
*/
290
private Object writeReplace() {
291
return new Ser(Ser.ZOTRULE, this);
292
}
293
294
/**
295
* Writes the state to the stream.
296
*
297
* @param out the output stream, not null
298
* @throws IOException if an error occurs
299
*/
300
void writeExternal(DataOutput out) throws IOException {
301
final int timeSecs = (timeEndOfDay ? 86400 : time.toSecondOfDay());
302
final int stdOffset = standardOffset.getTotalSeconds();
303
final int beforeDiff = offsetBefore.getTotalSeconds() - stdOffset;
304
final int afterDiff = offsetAfter.getTotalSeconds() - stdOffset;
305
final int timeByte = (timeSecs % 3600 == 0 ? (timeEndOfDay ? 24 : time.getHour()) : 31);
306
final int stdOffsetByte = (stdOffset % 900 == 0 ? stdOffset / 900 + 128 : 255);
307
final int beforeByte = (beforeDiff == 0 || beforeDiff == 1800 || beforeDiff == 3600 ? beforeDiff / 1800 : 3);
308
final int afterByte = (afterDiff == 0 || afterDiff == 1800 || afterDiff == 3600 ? afterDiff / 1800 : 3);
309
final int dowByte = (dow == null ? 0 : dow.getValue());
310
int b = (month.getValue() << 28) + // 4 bits
311
((dom + 32) << 22) + // 6 bits
312
(dowByte << 19) + // 3 bits
313
(timeByte << 14) + // 5 bits
314
(timeDefinition.ordinal() << 12) + // 2 bits
315
(stdOffsetByte << 4) + // 8 bits
316
(beforeByte << 2) + // 2 bits
317
afterByte; // 2 bits
318
out.writeInt(b);
319
if (timeByte == 31) {
320
out.writeInt(timeSecs);
321
}
322
if (stdOffsetByte == 255) {
323
out.writeInt(stdOffset);
324
}
325
if (beforeByte == 3) {
326
out.writeInt(offsetBefore.getTotalSeconds());
327
}
328
if (afterByte == 3) {
329
out.writeInt(offsetAfter.getTotalSeconds());
330
}
331
}
332
333
/**
334
* Reads the state from the stream.
335
*
336
* @param in the input stream, not null
337
* @return the created object, not null
338
* @throws IOException if an error occurs
339
*/
340
static ZoneOffsetTransitionRule readExternal(DataInput in) throws IOException {
341
int data = in.readInt();
342
Month month = Month.of(data >>> 28);
343
int dom = ((data & (63 << 22)) >>> 22) - 32;
344
int dowByte = (data & (7 << 19)) >>> 19;
345
DayOfWeek dow = dowByte == 0 ? null : DayOfWeek.of(dowByte);
346
int timeByte = (data & (31 << 14)) >>> 14;
347
TimeDefinition defn = TimeDefinition.values()[(data & (3 << 12)) >>> 12];
348
int stdByte = (data & (255 << 4)) >>> 4;
349
int beforeByte = (data & (3 << 2)) >>> 2;
350
int afterByte = (data & 3);
351
LocalTime time = (timeByte == 31 ? LocalTime.ofSecondOfDay(in.readInt()) : LocalTime.of(timeByte % 24, 0));
352
ZoneOffset std = (stdByte == 255 ? ZoneOffset.ofTotalSeconds(in.readInt()) : ZoneOffset.ofTotalSeconds((stdByte - 128) * 900));
353
ZoneOffset before = (beforeByte == 3 ? ZoneOffset.ofTotalSeconds(in.readInt()) : ZoneOffset.ofTotalSeconds(std.getTotalSeconds() + beforeByte * 1800));
354
ZoneOffset after = (afterByte == 3 ? ZoneOffset.ofTotalSeconds(in.readInt()) : ZoneOffset.ofTotalSeconds(std.getTotalSeconds() + afterByte * 1800));
355
return ZoneOffsetTransitionRule.of(month, dom, dow, time, timeByte == 24, defn, std, before, after);
356
}
357
358
//-----------------------------------------------------------------------
359
/**
360
* Gets the month of the transition.
361
* <p>
362
* If the rule defines an exact date then the month is the month of that date.
363
* <p>
364
* If the rule defines a week where the transition might occur, then the month
365
* if the month of either the earliest or latest possible date of the cutover.
366
*
367
* @return the month of the transition, not null
368
*/
369
public Month getMonth() {
370
return month;
371
}
372
373
/**
374
* Gets the indicator of the day-of-month of the transition.
375
* <p>
376
* If the rule defines an exact date then the day is the month of that date.
377
* <p>
378
* If the rule defines a week where the transition might occur, then the day
379
* defines either the start of the end of the transition week.
380
* <p>
381
* If the value is positive, then it represents a normal day-of-month, and is the
382
* earliest possible date that the transition can be.
383
* The date may refer to 29th February which should be treated as 1st March in non-leap years.
384
* <p>
385
* If the value is negative, then it represents the number of days back from the
386
* end of the month where {@code -1} is the last day of the month.
387
* In this case, the day identified is the latest possible date that the transition can be.
388
*
389
* @return the day-of-month indicator, from -28 to 31 excluding 0
390
*/
391
public int getDayOfMonthIndicator() {
392
return dom;
393
}
394
395
/**
396
* Gets the day-of-week of the transition.
397
* <p>
398
* If the rule defines an exact date then this returns null.
399
* <p>
400
* If the rule defines a week where the cutover might occur, then this method
401
* returns the day-of-week that the month-day will be adjusted to.
402
* If the day is positive then the adjustment is later.
403
* If the day is negative then the adjustment is earlier.
404
*
405
* @return the day-of-week that the transition occurs, null if the rule defines an exact date
406
*/
407
public DayOfWeek getDayOfWeek() {
408
return dow;
409
}
410
411
/**
412
* Gets the local time of day of the transition which must be checked with
413
* {@link #isMidnightEndOfDay()}.
414
* <p>
415
* The time is converted into an instant using the time definition.
416
*
417
* @return the local time of day of the transition, not null
418
*/
419
public LocalTime getLocalTime() {
420
return time;
421
}
422
423
/**
424
* Is the transition local time midnight at the end of day.
425
* <p>
426
* The transition may be represented as occurring at 24:00.
427
*
428
* @return whether a local time of midnight is at the start or end of the day
429
*/
430
public boolean isMidnightEndOfDay() {
431
return timeEndOfDay;
432
}
433
434
/**
435
* Gets the time definition, specifying how to convert the time to an instant.
436
* <p>
437
* The local time can be converted to an instant using the standard offset,
438
* the wall offset or UTC.
439
*
440
* @return the time definition, not null
441
*/
442
public TimeDefinition getTimeDefinition() {
443
return timeDefinition;
444
}
445
446
/**
447
* Gets the standard offset in force at the transition.
448
*
449
* @return the standard offset, not null
450
*/
451
public ZoneOffset getStandardOffset() {
452
return standardOffset;
453
}
454
455
/**
456
* Gets the offset before the transition.
457
*
458
* @return the offset before, not null
459
*/
460
public ZoneOffset getOffsetBefore() {
461
return offsetBefore;
462
}
463
464
/**
465
* Gets the offset after the transition.
466
*
467
* @return the offset after, not null
468
*/
469
public ZoneOffset getOffsetAfter() {
470
return offsetAfter;
471
}
472
473
//-----------------------------------------------------------------------
474
/**
475
* Creates a transition instance for the specified year.
476
* <p>
477
* Calculations are performed using the ISO-8601 chronology.
478
*
479
* @param year the year to create a transition for, not null
480
* @return the transition instance, not null
481
*/
482
public ZoneOffsetTransition createTransition(int year) {
483
LocalDate date;
484
if (dom < 0) {
485
date = LocalDate.of(year, month, month.length(IsoChronology.INSTANCE.isLeapYear(year)) + 1 + dom);
486
if (dow != null) {
487
date = date.with(previousOrSame(dow));
488
}
489
} else {
490
date = LocalDate.of(year, month, dom);
491
if (dow != null) {
492
date = date.with(nextOrSame(dow));
493
}
494
}
495
if (timeEndOfDay) {
496
date = date.plusDays(1);
497
}
498
LocalDateTime localDT = LocalDateTime.of(date, time);
499
LocalDateTime transition = timeDefinition.createDateTime(localDT, standardOffset, offsetBefore);
500
return new ZoneOffsetTransition(transition, offsetBefore, offsetAfter);
501
}
502
503
//-----------------------------------------------------------------------
504
/**
505
* Checks if this object equals another.
506
* <p>
507
* The entire state of the object is compared.
508
*
509
* @param otherRule the other object to compare to, null returns false
510
* @return true if equal
511
*/
512
@Override
513
public boolean equals(Object otherRule) {
514
if (otherRule == this) {
515
return true;
516
}
517
if (otherRule instanceof ZoneOffsetTransitionRule) {
518
ZoneOffsetTransitionRule other = (ZoneOffsetTransitionRule) otherRule;
519
return month == other.month && dom == other.dom && dow == other.dow &&
520
timeDefinition == other.timeDefinition &&
521
time.equals(other.time) &&
522
timeEndOfDay == other.timeEndOfDay &&
523
standardOffset.equals(other.standardOffset) &&
524
offsetBefore.equals(other.offsetBefore) &&
525
offsetAfter.equals(other.offsetAfter);
526
}
527
return false;
528
}
529
530
/**
531
* Returns a suitable hash code.
532
*
533
* @return the hash code
534
*/
535
@Override
536
public int hashCode() {
537
int hash = ((time.toSecondOfDay() + (timeEndOfDay ? 1 : 0)) << 15) +
538
(month.ordinal() << 11) + ((dom + 32) << 5) +
539
((dow == null ? 7 : dow.ordinal()) << 2) + (timeDefinition.ordinal());
540
return hash ^ standardOffset.hashCode() ^
541
offsetBefore.hashCode() ^ offsetAfter.hashCode();
542
}
543
544
//-----------------------------------------------------------------------
545
/**
546
* Returns a string describing this object.
547
*
548
* @return a string for debugging, not null
549
*/
550
@Override
551
public String toString() {
552
StringBuilder buf = new StringBuilder();
553
buf.append("TransitionRule[")
554
.append(offsetBefore.compareTo(offsetAfter) > 0 ? "Gap " : "Overlap ")
555
.append(offsetBefore).append(" to ").append(offsetAfter).append(", ");
556
if (dow != null) {
557
if (dom == -1) {
558
buf.append(dow.name()).append(" on or before last day of ").append(month.name());
559
} else if (dom < 0) {
560
buf.append(dow.name()).append(" on or before last day minus ").append(-dom - 1).append(" of ").append(month.name());
561
} else {
562
buf.append(dow.name()).append(" on or after ").append(month.name()).append(' ').append(dom);
563
}
564
} else {
565
buf.append(month.name()).append(' ').append(dom);
566
}
567
buf.append(" at ").append(timeEndOfDay ? "24:00" : time.toString())
568
.append(" ").append(timeDefinition)
569
.append(", standard offset ").append(standardOffset)
570
.append(']');
571
return buf.toString();
572
}
573
574
//-----------------------------------------------------------------------
575
/**
576
* A definition of the way a local time can be converted to the actual
577
* transition date-time.
578
* <p>
579
* Time zone rules are expressed in one of three ways:
580
* <ul>
581
* <li>Relative to UTC</li>
582
* <li>Relative to the standard offset in force</li>
583
* <li>Relative to the wall offset (what you would see on a clock on the wall)</li>
584
* </ul>
585
*/
586
public static enum TimeDefinition {
587
/** The local date-time is expressed in terms of the UTC offset. */
588
UTC,
589
/** The local date-time is expressed in terms of the wall offset. */
590
WALL,
591
/** The local date-time is expressed in terms of the standard offset. */
592
STANDARD;
593
594
/**
595
* Converts the specified local date-time to the local date-time actually
596
* seen on a wall clock.
597
* <p>
598
* This method converts using the type of this enum.
599
* The output is defined relative to the 'before' offset of the transition.
600
* <p>
601
* The UTC type uses the UTC offset.
602
* The STANDARD type uses the standard offset.
603
* The WALL type returns the input date-time.
604
* The result is intended for use with the wall-offset.
605
*
606
* @param dateTime the local date-time, not null
607
* @param standardOffset the standard offset, not null
608
* @param wallOffset the wall offset, not null
609
* @return the date-time relative to the wall/before offset, not null
610
*/
611
public LocalDateTime createDateTime(LocalDateTime dateTime, ZoneOffset standardOffset, ZoneOffset wallOffset) {
612
switch (this) {
613
case UTC: {
614
int difference = wallOffset.getTotalSeconds() - ZoneOffset.UTC.getTotalSeconds();
615
return dateTime.plusSeconds(difference);
616
}
617
case STANDARD: {
618
int difference = wallOffset.getTotalSeconds() - standardOffset.getTotalSeconds();
619
return dateTime.plusSeconds(difference);
620
}
621
default: // WALL
622
return dateTime;
623
}
624
}
625
}
626
627
}
628
629