Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/java/time/zone/ZoneOffsetTransitionRule.java
41159 views
1
/*
2
* Copyright (c) 2012, 2020, 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 timeDefinition 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
* @throws IllegalArgumentException if {@code time.getNano()} returns non-zero value
171
*/
172
public static ZoneOffsetTransitionRule of(
173
Month month,
174
int dayOfMonthIndicator,
175
DayOfWeek dayOfWeek,
176
LocalTime time,
177
boolean timeEndOfDay,
178
TimeDefinition timeDefinition,
179
ZoneOffset standardOffset,
180
ZoneOffset offsetBefore,
181
ZoneOffset offsetAfter) {
182
Objects.requireNonNull(month, "month");
183
Objects.requireNonNull(time, "time");
184
Objects.requireNonNull(timeDefinition, "timeDefinition");
185
Objects.requireNonNull(standardOffset, "standardOffset");
186
Objects.requireNonNull(offsetBefore, "offsetBefore");
187
Objects.requireNonNull(offsetAfter, "offsetAfter");
188
if (dayOfMonthIndicator < -28 || dayOfMonthIndicator > 31 || dayOfMonthIndicator == 0) {
189
throw new IllegalArgumentException("Day of month indicator must be between -28 and 31 inclusive excluding zero");
190
}
191
if (timeEndOfDay && time.equals(LocalTime.MIDNIGHT) == false) {
192
throw new IllegalArgumentException("Time must be midnight when end of day flag is true");
193
}
194
if (time.getNano() != 0) {
195
throw new IllegalArgumentException("Time's nano-of-second must be zero");
196
}
197
return new ZoneOffsetTransitionRule(month, dayOfMonthIndicator, dayOfWeek, time, timeEndOfDay, timeDefinition, standardOffset, offsetBefore, offsetAfter);
198
}
199
200
/**
201
* Creates an instance defining the yearly rule to create transitions between two offsets.
202
*
203
* @param month the month of the month-day of the first day of the cutover week, not null
204
* @param dayOfMonthIndicator the day of the month-day of the cutover week, positive if the week is that
205
* day or later, negative if the week is that day or earlier, counting from the last day of the month,
206
* from -28 to 31 excluding 0
207
* @param dayOfWeek the required day-of-week, null if the month-day should not be changed
208
* @param time the cutover time in the 'before' offset, not null
209
* @param timeEndOfDay whether the time is midnight at the end of day
210
* @param timeDefinition how to interpret the cutover
211
* @param standardOffset the standard offset in force at the cutover, not null
212
* @param offsetBefore the offset before the cutover, not null
213
* @param offsetAfter the offset after the cutover, not null
214
* @throws IllegalArgumentException if the day of month indicator is invalid
215
* @throws IllegalArgumentException if the end of day flag is true when the time is not midnight
216
*/
217
ZoneOffsetTransitionRule(
218
Month month,
219
int dayOfMonthIndicator,
220
DayOfWeek dayOfWeek,
221
LocalTime time,
222
boolean timeEndOfDay,
223
TimeDefinition timeDefinition,
224
ZoneOffset standardOffset,
225
ZoneOffset offsetBefore,
226
ZoneOffset offsetAfter) {
227
assert time.getNano() == 0;
228
this.month = month;
229
this.dom = (byte) dayOfMonthIndicator;
230
this.dow = dayOfWeek;
231
this.time = time;
232
this.timeEndOfDay = timeEndOfDay;
233
this.timeDefinition = timeDefinition;
234
this.standardOffset = standardOffset;
235
this.offsetBefore = offsetBefore;
236
this.offsetAfter = offsetAfter;
237
}
238
239
//-----------------------------------------------------------------------
240
/**
241
* Defend against malicious streams.
242
*
243
* @param s the stream to read
244
* @throws InvalidObjectException always
245
*/
246
private void readObject(ObjectInputStream s) throws InvalidObjectException {
247
throw new InvalidObjectException("Deserialization via serialization delegate");
248
}
249
250
/**
251
* Writes the object using a
252
* <a href="{@docRoot}/serialized-form.html#java.time.zone.Ser">dedicated serialized form</a>.
253
* @serialData
254
* Refer to the serialized form of
255
* <a href="{@docRoot}/serialized-form.html#java.time.zone.ZoneRules">ZoneRules.writeReplace</a>
256
* for the encoding of epoch seconds and offsets.
257
* <pre style="font-size:1.0em">{@code
258
*
259
* out.writeByte(3); // identifies a ZoneOffsetTransitionRule
260
* final int timeSecs = (timeEndOfDay ? 86400 : time.toSecondOfDay());
261
* final int stdOffset = standardOffset.getTotalSeconds();
262
* final int beforeDiff = offsetBefore.getTotalSeconds() - stdOffset;
263
* final int afterDiff = offsetAfter.getTotalSeconds() - stdOffset;
264
* final int timeByte = (timeSecs % 3600 == 0 ? (timeEndOfDay ? 24 : time.getHour()) : 31);
265
* final int stdOffsetByte = (stdOffset % 900 == 0 ? stdOffset / 900 + 128 : 255);
266
* final int beforeByte = (beforeDiff == 0 || beforeDiff == 1800 || beforeDiff == 3600 ? beforeDiff / 1800 : 3);
267
* final int afterByte = (afterDiff == 0 || afterDiff == 1800 || afterDiff == 3600 ? afterDiff / 1800 : 3);
268
* final int dowByte = (dow == null ? 0 : dow.getValue());
269
* int b = (month.getValue() << 28) + // 4 bits
270
* ((dom + 32) << 22) + // 6 bits
271
* (dowByte << 19) + // 3 bits
272
* (timeByte << 14) + // 5 bits
273
* (timeDefinition.ordinal() << 12) + // 2 bits
274
* (stdOffsetByte << 4) + // 8 bits
275
* (beforeByte << 2) + // 2 bits
276
* afterByte; // 2 bits
277
* out.writeInt(b);
278
* if (timeByte == 31) {
279
* out.writeInt(timeSecs);
280
* }
281
* if (stdOffsetByte == 255) {
282
* out.writeInt(stdOffset);
283
* }
284
* if (beforeByte == 3) {
285
* out.writeInt(offsetBefore.getTotalSeconds());
286
* }
287
* if (afterByte == 3) {
288
* out.writeInt(offsetAfter.getTotalSeconds());
289
* }
290
* }
291
* </pre>
292
*
293
* @return the replacing object, not null
294
*/
295
private Object writeReplace() {
296
return new Ser(Ser.ZOTRULE, this);
297
}
298
299
/**
300
* Writes the state to the stream.
301
*
302
* @param out the output stream, not null
303
* @throws IOException if an error occurs
304
*/
305
void writeExternal(DataOutput out) throws IOException {
306
final int timeSecs = (timeEndOfDay ? 86400 : time.toSecondOfDay());
307
final int stdOffset = standardOffset.getTotalSeconds();
308
final int beforeDiff = offsetBefore.getTotalSeconds() - stdOffset;
309
final int afterDiff = offsetAfter.getTotalSeconds() - stdOffset;
310
final int timeByte = (timeSecs % 3600 == 0 ? (timeEndOfDay ? 24 : time.getHour()) : 31);
311
final int stdOffsetByte = (stdOffset % 900 == 0 ? stdOffset / 900 + 128 : 255);
312
final int beforeByte = (beforeDiff == 0 || beforeDiff == 1800 || beforeDiff == 3600 ? beforeDiff / 1800 : 3);
313
final int afterByte = (afterDiff == 0 || afterDiff == 1800 || afterDiff == 3600 ? afterDiff / 1800 : 3);
314
final int dowByte = (dow == null ? 0 : dow.getValue());
315
int b = (month.getValue() << 28) + // 4 bits
316
((dom + 32) << 22) + // 6 bits
317
(dowByte << 19) + // 3 bits
318
(timeByte << 14) + // 5 bits
319
(timeDefinition.ordinal() << 12) + // 2 bits
320
(stdOffsetByte << 4) + // 8 bits
321
(beforeByte << 2) + // 2 bits
322
afterByte; // 2 bits
323
out.writeInt(b);
324
if (timeByte == 31) {
325
out.writeInt(timeSecs);
326
}
327
if (stdOffsetByte == 255) {
328
out.writeInt(stdOffset);
329
}
330
if (beforeByte == 3) {
331
out.writeInt(offsetBefore.getTotalSeconds());
332
}
333
if (afterByte == 3) {
334
out.writeInt(offsetAfter.getTotalSeconds());
335
}
336
}
337
338
/**
339
* Reads the state from the stream.
340
*
341
* @param in the input stream, not null
342
* @return the created object, not null
343
* @throws IOException if an error occurs
344
*/
345
static ZoneOffsetTransitionRule readExternal(DataInput in) throws IOException {
346
int data = in.readInt();
347
Month month = Month.of(data >>> 28);
348
int dom = ((data & (63 << 22)) >>> 22) - 32;
349
int dowByte = (data & (7 << 19)) >>> 19;
350
DayOfWeek dow = dowByte == 0 ? null : DayOfWeek.of(dowByte);
351
int timeByte = (data & (31 << 14)) >>> 14;
352
TimeDefinition defn = TimeDefinition.values()[(data & (3 << 12)) >>> 12];
353
int stdByte = (data & (255 << 4)) >>> 4;
354
int beforeByte = (data & (3 << 2)) >>> 2;
355
int afterByte = (data & 3);
356
LocalTime time = (timeByte == 31 ? LocalTime.ofSecondOfDay(in.readInt()) : LocalTime.of(timeByte % 24, 0));
357
ZoneOffset std = (stdByte == 255 ? ZoneOffset.ofTotalSeconds(in.readInt()) : ZoneOffset.ofTotalSeconds((stdByte - 128) * 900));
358
ZoneOffset before = (beforeByte == 3 ? ZoneOffset.ofTotalSeconds(in.readInt()) : ZoneOffset.ofTotalSeconds(std.getTotalSeconds() + beforeByte * 1800));
359
ZoneOffset after = (afterByte == 3 ? ZoneOffset.ofTotalSeconds(in.readInt()) : ZoneOffset.ofTotalSeconds(std.getTotalSeconds() + afterByte * 1800));
360
return ZoneOffsetTransitionRule.of(month, dom, dow, time, timeByte == 24, defn, std, before, after);
361
}
362
363
//-----------------------------------------------------------------------
364
/**
365
* Gets the month of the transition.
366
* <p>
367
* If the rule defines an exact date then the month is the month of that date.
368
* <p>
369
* If the rule defines a week where the transition might occur, then the month
370
* if the month of either the earliest or latest possible date of the cutover.
371
*
372
* @return the month of the transition, not null
373
*/
374
public Month getMonth() {
375
return month;
376
}
377
378
/**
379
* Gets the indicator of the day-of-month of the transition.
380
* <p>
381
* If the rule defines an exact date then the day is the month of that date.
382
* <p>
383
* If the rule defines a week where the transition might occur, then the day
384
* defines either the start of the end of the transition week.
385
* <p>
386
* If the value is positive, then it represents a normal day-of-month, and is the
387
* earliest possible date that the transition can be.
388
* The date may refer to 29th February which should be treated as 1st March in non-leap years.
389
* <p>
390
* If the value is negative, then it represents the number of days back from the
391
* end of the month where {@code -1} is the last day of the month.
392
* In this case, the day identified is the latest possible date that the transition can be.
393
*
394
* @return the day-of-month indicator, from -28 to 31 excluding 0
395
*/
396
public int getDayOfMonthIndicator() {
397
return dom;
398
}
399
400
/**
401
* Gets the day-of-week of the transition.
402
* <p>
403
* If the rule defines an exact date then this returns null.
404
* <p>
405
* If the rule defines a week where the cutover might occur, then this method
406
* returns the day-of-week that the month-day will be adjusted to.
407
* If the day is positive then the adjustment is later.
408
* If the day is negative then the adjustment is earlier.
409
*
410
* @return the day-of-week that the transition occurs, null if the rule defines an exact date
411
*/
412
public DayOfWeek getDayOfWeek() {
413
return dow;
414
}
415
416
/**
417
* Gets the local time of day of the transition which must be checked with
418
* {@link #isMidnightEndOfDay()}.
419
* <p>
420
* The time is converted into an instant using the time definition.
421
*
422
* @return the local time of day of the transition, not null
423
*/
424
public LocalTime getLocalTime() {
425
return time;
426
}
427
428
/**
429
* Is the transition local time midnight at the end of day.
430
* <p>
431
* The transition may be represented as occurring at 24:00.
432
*
433
* @return whether a local time of midnight is at the start or end of the day
434
*/
435
public boolean isMidnightEndOfDay() {
436
return timeEndOfDay;
437
}
438
439
/**
440
* Gets the time definition, specifying how to convert the time to an instant.
441
* <p>
442
* The local time can be converted to an instant using the standard offset,
443
* the wall offset or UTC.
444
*
445
* @return the time definition, not null
446
*/
447
public TimeDefinition getTimeDefinition() {
448
return timeDefinition;
449
}
450
451
/**
452
* Gets the standard offset in force at the transition.
453
*
454
* @return the standard offset, not null
455
*/
456
public ZoneOffset getStandardOffset() {
457
return standardOffset;
458
}
459
460
/**
461
* Gets the offset before the transition.
462
*
463
* @return the offset before, not null
464
*/
465
public ZoneOffset getOffsetBefore() {
466
return offsetBefore;
467
}
468
469
/**
470
* Gets the offset after the transition.
471
*
472
* @return the offset after, not null
473
*/
474
public ZoneOffset getOffsetAfter() {
475
return offsetAfter;
476
}
477
478
//-----------------------------------------------------------------------
479
/**
480
* Creates a transition instance for the specified year.
481
* <p>
482
* Calculations are performed using the ISO-8601 chronology.
483
*
484
* @param year the year to create a transition for, not null
485
* @return the transition instance, not null
486
*/
487
public ZoneOffsetTransition createTransition(int year) {
488
LocalDate date;
489
if (dom < 0) {
490
date = LocalDate.of(year, month, month.length(IsoChronology.INSTANCE.isLeapYear(year)) + 1 + dom);
491
if (dow != null) {
492
date = date.with(previousOrSame(dow));
493
}
494
} else {
495
date = LocalDate.of(year, month, dom);
496
if (dow != null) {
497
date = date.with(nextOrSame(dow));
498
}
499
}
500
if (timeEndOfDay) {
501
date = date.plusDays(1);
502
}
503
LocalDateTime localDT = LocalDateTime.of(date, time);
504
LocalDateTime transition = timeDefinition.createDateTime(localDT, standardOffset, offsetBefore);
505
return new ZoneOffsetTransition(transition, offsetBefore, offsetAfter);
506
}
507
508
//-----------------------------------------------------------------------
509
/**
510
* Checks if this object equals another.
511
* <p>
512
* The entire state of the object is compared.
513
*
514
* @param otherRule the other object to compare to, null returns false
515
* @return true if equal
516
*/
517
@Override
518
public boolean equals(Object otherRule) {
519
if (otherRule == this) {
520
return true;
521
}
522
return (otherRule instanceof ZoneOffsetTransitionRule other)
523
&& month == other.month
524
&& dom == other.dom
525
&& dow == other.dow
526
&& timeDefinition == other.timeDefinition
527
&& timeEndOfDay == other.timeEndOfDay
528
&& time.equals(other.time)
529
&& standardOffset.equals(other.standardOffset)
530
&& offsetBefore.equals(other.offsetBefore)
531
&& offsetAfter.equals(other.offsetAfter);
532
}
533
534
/**
535
* Returns a suitable hash code.
536
*
537
* @return the hash code
538
*/
539
@Override
540
public int hashCode() {
541
int hash = ((time.toSecondOfDay() + (timeEndOfDay ? 1 : 0)) << 15) +
542
(month.ordinal() << 11) + ((dom + 32) << 5) +
543
((dow == null ? 7 : dow.ordinal()) << 2) + (timeDefinition.ordinal());
544
return hash ^ standardOffset.hashCode() ^
545
offsetBefore.hashCode() ^ offsetAfter.hashCode();
546
}
547
548
//-----------------------------------------------------------------------
549
/**
550
* Returns a string describing this object.
551
*
552
* @return a string for debugging, not null
553
*/
554
@Override
555
public String toString() {
556
StringBuilder buf = new StringBuilder();
557
buf.append("TransitionRule[")
558
.append(offsetBefore.compareTo(offsetAfter) > 0 ? "Gap " : "Overlap ")
559
.append(offsetBefore).append(" to ").append(offsetAfter).append(", ");
560
if (dow != null) {
561
if (dom == -1) {
562
buf.append(dow.name()).append(" on or before last day of ").append(month.name());
563
} else if (dom < 0) {
564
buf.append(dow.name()).append(" on or before last day minus ").append(-dom - 1).append(" of ").append(month.name());
565
} else {
566
buf.append(dow.name()).append(" on or after ").append(month.name()).append(' ').append(dom);
567
}
568
} else {
569
buf.append(month.name()).append(' ').append(dom);
570
}
571
buf.append(" at ").append(timeEndOfDay ? "24:00" : time.toString())
572
.append(" ").append(timeDefinition)
573
.append(", standard offset ").append(standardOffset)
574
.append(']');
575
return buf.toString();
576
}
577
578
//-----------------------------------------------------------------------
579
/**
580
* A definition of the way a local time can be converted to the actual
581
* transition date-time.
582
* <p>
583
* Time zone rules are expressed in one of three ways:
584
* <ul>
585
* <li>Relative to UTC</li>
586
* <li>Relative to the standard offset in force</li>
587
* <li>Relative to the wall offset (what you would see on a clock on the wall)</li>
588
* </ul>
589
*/
590
public static enum TimeDefinition {
591
/** The local date-time is expressed in terms of the UTC offset. */
592
UTC,
593
/** The local date-time is expressed in terms of the wall offset. */
594
WALL,
595
/** The local date-time is expressed in terms of the standard offset. */
596
STANDARD;
597
598
/**
599
* Converts the specified local date-time to the local date-time actually
600
* seen on a wall clock.
601
* <p>
602
* This method converts using the type of this enum.
603
* The output is defined relative to the 'before' offset of the transition.
604
* <p>
605
* The UTC type uses the UTC offset.
606
* The STANDARD type uses the standard offset.
607
* The WALL type returns the input date-time.
608
* The result is intended for use with the wall-offset.
609
*
610
* @param dateTime the local date-time, not null
611
* @param standardOffset the standard offset, not null
612
* @param wallOffset the wall offset, not null
613
* @return the date-time relative to the wall/before offset, not null
614
*/
615
public LocalDateTime createDateTime(LocalDateTime dateTime, ZoneOffset standardOffset, ZoneOffset wallOffset) {
616
switch (this) {
617
case UTC: {
618
int difference = wallOffset.getTotalSeconds() - ZoneOffset.UTC.getTotalSeconds();
619
return dateTime.plusSeconds(difference);
620
}
621
case STANDARD: {
622
int difference = wallOffset.getTotalSeconds() - standardOffset.getTotalSeconds();
623
return dateTime.plusSeconds(difference);
624
}
625
default: // WALL
626
return dateTime;
627
}
628
}
629
}
630
631
}
632
633