package org.joda.time.tz;
DateTimeZoneBuilder allows complex DateTimeZones to be constructed. Since
creating a new DateTimeZone this way is a relatively expensive operation,
built zones can be written to a file. Reading back the encoded data is a
quick operation.
DateTimeZoneBuilder itself is mutable and not thread-safe, but the
DateTimeZone objects that it builds are thread-safe and immutable.
It is intended that ZoneInfoCompiler
be used to read time zone data
files, indirectly calling DateTimeZoneBuilder. The following complex
example defines the America/Los_Angeles time zone, with all historical
transitions:
DateTimeZone America_Los_Angeles = new DateTimeZoneBuilder()
.addCutover(-2147483648, 'w', 1, 1, 0, false, 0)
.setStandardOffset(-28378000)
.setFixedSavings("LMT", 0)
.addCutover(1883, 'w', 11, 18, 0, false, 43200000)
.setStandardOffset(-28800000)
.addRecurringSavings("PDT", 3600000, 1918, 1919, 'w', 3, -1, 7, false, 7200000)
.addRecurringSavings("PST", 0, 1918, 1919, 'w', 10, -1, 7, false, 7200000)
.addRecurringSavings("PWT", 3600000, 1942, 1942, 'w', 2, 9, 0, false, 7200000)
.addRecurringSavings("PPT", 3600000, 1945, 1945, 'u', 8, 14, 0, false, 82800000)
.addRecurringSavings("PST", 0, 1945, 1945, 'w', 9, 30, 0, false, 7200000)
.addRecurringSavings("PDT", 3600000, 1948, 1948, 'w', 3, 14, 0, false, 7200000)
.addRecurringSavings("PST", 0, 1949, 1949, 'w', 1, 1, 0, false, 7200000)
.addRecurringSavings("PDT", 3600000, 1950, 1966, 'w', 4, -1, 7, false, 7200000)
.addRecurringSavings("PST", 0, 1950, 1961, 'w', 9, -1, 7, false, 7200000)
.addRecurringSavings("PST", 0, 1962, 1966, 'w', 10, -1, 7, false, 7200000)
.addRecurringSavings("PST", 0, 1967, 2147483647, 'w', 10, -1, 7, false, 7200000)
.addRecurringSavings("PDT", 3600000, 1967, 1973, 'w', 4, -1, 7, false, 7200000)
.addRecurringSavings("PDT", 3600000, 1974, 1974, 'w', 1, 6, 0, false, 7200000)
.addRecurringSavings("PDT", 3600000, 1975, 1975, 'w', 2, 23, 0, false, 7200000)
.addRecurringSavings("PDT", 3600000, 1976, 1986, 'w', 4, -1, 7, false, 7200000)
.addRecurringSavings("PDT", 3600000, 1987, 2147483647, 'w', 4, 1, 7, true, 7200000)
.toDateTimeZone("America/Los_Angeles", true);
Decodes a built DateTimeZone from the given stream, as encoded by
writeTo.
- Parameters:
in
input stream to read encoded DateTimeZone from.id
time zone id to assign
Decodes a built DateTimeZone from the given stream, as encoded by
writeTo.
- Parameters:
in
input stream to read encoded DateTimeZone from.id
time zone id to assign
return PrecalculatedZone.readFrom(in, id);
Millisecond encoding formats:
upper two bits units field length approximate range
---------------------------------------------------------------
00 30 minutes 1 byte +/- 16 hours
01 minutes 4 bytes +/- 1020 years
10 seconds 5 bytes +/- 4355 years
11 millis 9 bytes +/- 292,000,000 years
Remaining bits in field form signed offset from 1970-01-01T00:00:00Z.
if (millis % (30 * 60000L) == 0) {
long units = millis / (30 * 60000L);
if (((units << (64 - 6)) >> (64 - 6)) == units) {
if (millis % 60000L == 0) {
long minutes = millis / 60000L;
if (((minutes << (64 - 30)) >> (64 - 30)) == minutes) {
out.writeInt(0x40000000 | (int)(minutes & 0x3fffffff));
if (millis % 1000L == 0) {
long seconds = millis / 1000L;
if (((seconds << (64 - 38)) >> (64 - 38)) == seconds) {
out.writeByte(0x80 | (int)((seconds >> 32) & 0x3f));
out.writeInt((int)(seconds & 0xffffffff));
Reads encoding generated by writeMillis.
v = (v << (32 - 6)) >> (32 - 6);
return v * (30 * 60000L);
v = (v << (32 - 6)) >> (32 - 30);
long w = (((long)v) << (64 - 6)) >> (64 - 38);
int wallOffset, int standardOffset) {
wallOffset == 0 && standardOffset == 0) {
Adds a cutover for added rules. The standard offset at the cutover
defaults to 0. Call setStandardOffset afterwards to change it.
- Parameters:
year
the year of cutovermode
'u' - cutover is measured against UTC, 'w' - against wall
offset, 's' - against standard offsetmonthOfYear
the month from 1 (January) to 12 (December)dayOfMonth
if negative, set to ((last day of month) - ~dayOfMonth).
For example, if -1, set to last day of monthdayOfWeek
from 1 (Monday) to 7 (Sunday), if 0 then ignoreadvanceDayOfWeek
if dayOfMonth does not fall on dayOfWeek, advance to
dayOfWeek when true, retreat when false.millisOfDay
additional precision for specifying time of day of cutover
boolean advanceDayOfWeek,
(mode, monthOfYear, dayOfMonth, dayOfWeek, advanceDayOfWeek, millisOfDay);
Sets the standard offset to use for newly added rules until the next
cutover is added.
- Parameters:
standardOffset
the standard offset in millis
Set a fixed savings rule at the cutover.
Add a recurring daylight saving time rule.
- Parameters:
nameKey
the name key of new rulesaveMillis
the milliseconds to add to standard offsetfromYear
the first year that rule is in effect, MIN_VALUE indicates
beginning of timetoYear
the last year (inclusive) that rule is in effect, MAX_VALUE
indicates end of timemode
'u' - transitions are calculated against UTC, 'w' -
transitions are calculated against wall offset, 's' - transitions are
calculated against standard offsetmonthOfYear
the month from 1 (January) to 12 (December)dayOfMonth
if negative, set to ((last day of month) - ~dayOfMonth).
For example, if -1, set to last day of monthdayOfWeek
from 1 (Monday) to 7 (Sunday), if 0 then ignoreadvanceDayOfWeek
if dayOfMonth does not fall on dayOfWeek, advance to
dayOfWeek when true, retreat when false.millisOfDay
additional precision for specifying time of day of transitions
int fromYear, int toYear,
boolean advanceDayOfWeek,
if (fromYear <= toYear) {
(mode, monthOfYear, dayOfMonth, dayOfWeek, advanceDayOfWeek, millisOfDay);
Rule rule = new Rule(recurrence, fromYear, toYear);
Processes all the rules and builds a DateTimeZone.
- Parameters:
id
time zone id to assignoutputID
true if the zone id should be output
for (int i=0; i<ruleSetCount; i++) {
if (tailZone == null && i == ruleSetCount - 1) {
if (transitions.size() == 0) {
if (transitions.size() == 1 && tailZone == null) {
return CachedDateTimeZone.forZone(zone);
int size = transitions.size();
long lastLocal = last.getMillis() + offsetForLast;
long newLocal = tr.getMillis() + offsetForNew;
if (newLocal != lastLocal) {
Encodes a built DateTimeZone to the given stream. Call readFrom to
decode the data into a DateTimeZone object.
- Parameters:
out
the output stream to receive the encoded DateTimeZone- Since:
- 1.5 (parameter added)
Encodes a built DateTimeZone to the given stream. Call readFrom to
decode the data into a DateTimeZone object.
- Parameters:
out
the output stream to receive the encoded DateTimeZone- Since:
- 1.5 (parameter added)
Supports setting fields of year and moving between transitions.
private static final class OfYear {
int dayOfWeek, boolean advanceDayOfWeek,
if (mode != 'u' && mode != 'w' && mode != 's') {
- Parameters:
standardOffset
standard offset just before instant
public long setInstant(int year, int standardOffset, int saveMillis) {
offset = standardOffset + saveMillis;
} else if (iMode == 's') {
long millis = chrono.year().set(0, year);
- Parameters:
standardOffset
standard offset just before next recurrence
public long next(long instant, int standardOffset, int saveMillis) {
offset = standardOffset + saveMillis;
} else if (iMode == 's') {
- Parameters:
standardOffset
standard offset just before previous recurrence
public long previous(long instant, int standardOffset, int saveMillis) {
offset = standardOffset + saveMillis;
} else if (iMode == 's') {
prev = chrono.year().add(prev, -1);
prev = chrono.year().add(prev, -1);
If month-day is 02-29 and year isn't leap, advances to next leap year.
If month-day is 02-29 and year isn't leap, retreats to previous leap year.
prev = chrono.year().add(prev, -1);
Extends OfYear with a nameKey and savings.
- Parameters:
standardOffset
standard offset just before next recurrence
public long next(long instant, int standardOffset, int saveMillis) {
return iOfYear.next(instant, standardOffset, saveMillis);
- Parameters:
standardOffset
standard offset just before previous recurrence
public long previous(long instant, int standardOffset, int saveMillis) {
Extends Recurrence with inclusive year limits.
private static final class Rule {
public long next(final long instant, int standardOffset, int saveMillis) {
final int wallOffset = standardOffset + saveMillis;
long testInstant = instant;
year = chrono.year().get(instant + wallOffset);
year = chrono.year().get(next + wallOffset);
int wallOffset, int standardOffset) {
There must be a change in the millis, wall offsets or name keys.
private static final class RuleSet {
Returns a transition at firstMillis with the first name key and
offsets for this rule set. This method may return null.
- Parameters:
firstMillis
millis of first transition
if (millis == firstMillis) {
if (millis > firstMillis) {
Returns null if RuleSet is exhausted or upper limit reached. Calling
this method will throw away rules as they each become
exhausted. Copy the RuleSet before using it to compute transitions.
Returned transition may be a duplicate from previous
transition. Caller must call isTransitionFrom to filter out
duplicates.
- Parameters:
saveMillis
savings before next transition
if (next <= nextMillis) {
if (nextMillis >= upperMillis) {
- Parameters:
saveMillis
savings before upper limit
Returns null if none can be built.
startRule.iRecurrence, endRule.iRecurrence);