< prev index next >

make/jdk/src/classes/build/tools/tzdb/TzdbZoneRulesProvider.java

Print this page
rev 55794 : [mq]: 8212970

*** 1,7 **** /* ! * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this --- 1,7 ---- /* ! * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this
*** 29,56 **** import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; ! import java.util.ArrayList; ! import java.util.Collections; ! import java.util.List; ! import java.util.Map; import java.util.Map.Entry; - import java.util.NavigableMap; - import java.util.Objects; - import java.util.Set; - import java.util.TreeMap; - import java.util.TreeSet; import java.util.concurrent.ConcurrentSkipListMap; import java.time.*; import java.time.Year; import java.time.chrono.IsoChronology; import java.time.temporal.TemporalAdjusters; ! import java.time.zone.ZoneOffsetTransition; ! import java.time.zone.ZoneOffsetTransitionRule; ! import java.time.zone.ZoneOffsetTransitionRule.TimeDefinition; import java.time.zone.ZoneRulesException; /** * Compile and build time-zone rules from IANA timezone data * --- 29,46 ---- import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; ! import java.util.*; import java.util.Map.Entry; import java.util.concurrent.ConcurrentSkipListMap; import java.time.*; import java.time.Year; import java.time.chrono.IsoChronology; import java.time.temporal.TemporalAdjusters; ! import build.tools.tzdb.ZoneOffsetTransitionRule.TimeDefinition; import java.time.zone.ZoneRulesException; /** * Compile and build time-zone rules from IANA timezone data *
*** 270,281 **** /** The time of the cutover, in second of day */ int secsOfDay = 0; /** Whether this is midnight end of day. */ boolean endOfDay; - /** The time of the cutover. */ TimeDefinition timeDefinition = TimeDefinition.WALL; void adjustToForwards(int year) { if (adjustForwards == false && dayOfMonth > 0) { // weekDay<=monthDay case, don't have it in tzdb data for now --- 260,271 ---- /** The time of the cutover, in second of day */ int secsOfDay = 0; /** Whether this is midnight end of day. */ boolean endOfDay; + /** The time definition of the cutover. */ TimeDefinition timeDefinition = TimeDefinition.WALL; void adjustToForwards(int year) { if (adjustForwards == false && dayOfMonth > 0) { // weekDay<=monthDay case, don't have it in tzdb data for now
*** 341,350 **** --- 331,354 ---- secsOfDay = parseSecs(timeStr); if (secsOfDay == 86400) { // time must be midnight when end of day flag is true endOfDay = true; secsOfDay = 0; + } else if (secsOfDay < 0 || secsOfDay > 86400) { + // beyond 0:00-24:00 range. Adjust the cutover date. + int beyondDays = secsOfDay / 86400; + secsOfDay %= 86400; + if (secsOfDay < 0) { + secsOfDay = 86400 + secsOfDay; + beyondDays -= 1; + } + LocalDate date = LocalDate.of(2004, month, dayOfMonth).plusDays(beyondDays); // leap-year + month = date.getMonth(); + dayOfMonth = date.getDayOfMonth(); + if (dayOfWeek != null) { + dayOfWeek = dayOfWeek.plus(beyondDays); + } } timeDefinition = parseTimeDefinition(timeStr.charAt(timeStr.length() - 1)); } } }
*** 495,507 **** /** * Converts this to a transition rule. * * @param standardOffset the active standard offset, not null * @param savingsBeforeSecs the active savings before the transition in seconds * @return the transition, not null */ ! ZoneOffsetTransitionRule toTransitionRule(ZoneOffset stdOffset, int savingsBefore) { // rule shared by different zones, so don't change it Month month = this.month; int dayOfMonth = this.dayOfMonth; DayOfWeek dayOfWeek = this.dayOfWeek; boolean endOfDay = this.endOfDay; --- 499,513 ---- /** * Converts this to a transition rule. * * @param standardOffset the active standard offset, not null * @param savingsBeforeSecs the active savings before the transition in seconds + * @param negativeSavings minimum savings in the rule, usually zero, but negative if negative DST is + * in effect. * @return the transition, not null */ ! ZoneOffsetTransitionRule toTransitionRule(ZoneOffset stdOffset, int savingsBefore, int negativeSavings) { // rule shared by different zones, so don't change it Month month = this.month; int dayOfMonth = this.dayOfMonth; DayOfWeek dayOfWeek = this.dayOfWeek; boolean endOfDay = this.endOfDay;
*** 520,537 **** if (dayOfWeek != null) { dayOfWeek = dayOfWeek.plus(1); } endOfDay = false; } // build rule return ZoneOffsetTransitionRule.of( //month, dayOfMonth, dayOfWeek, time, endOfDay, timeDefinition, month, dayOfMonth, dayOfWeek, LocalTime.ofSecondOfDay(secsOfDay), endOfDay, timeDefinition, stdOffset, ZoneOffset.ofTotalSeconds(stdOffset.getTotalSeconds() + savingsBefore), ! ZoneOffset.ofTotalSeconds(stdOffset.getTotalSeconds() + savingsAmount)); } RuleLine parse(String[] tokens) { startYear = parseYear(tokens[2], 0); endYear = parseYear(tokens[3], startYear); --- 526,544 ---- if (dayOfWeek != null) { dayOfWeek = dayOfWeek.plus(1); } endOfDay = false; } + // build rule return ZoneOffsetTransitionRule.of( //month, dayOfMonth, dayOfWeek, time, endOfDay, timeDefinition, month, dayOfMonth, dayOfWeek, LocalTime.ofSecondOfDay(secsOfDay), endOfDay, timeDefinition, stdOffset, ZoneOffset.ofTotalSeconds(stdOffset.getTotalSeconds() + savingsBefore), ! ZoneOffset.ofTotalSeconds(stdOffset.getTotalSeconds() + savingsAmount - negativeSavings)); } RuleLine parse(String[] tokens) { startYear = parseYear(tokens[2], 0); endYear = parseYear(tokens[3], startYear);
*** 641,656 **** this.rule = rule; this.ldt = rule.toDateTime(year); this.ldtSecs = ldt.toEpochSecond(ZoneOffset.UTC); } ! ZoneOffsetTransition toTransition(ZoneOffset standardOffset, int savingsBeforeSecs) { // copy of code in ZoneOffsetTransitionRule to avoid infinite loop ZoneOffset wallOffset = ZoneOffset.ofTotalSeconds( standardOffset.getTotalSeconds() + savingsBeforeSecs); ZoneOffset offsetAfter = ZoneOffset.ofTotalSeconds( ! standardOffset.getTotalSeconds() + rule.savingsAmount); LocalDateTime dt = rule.timeDefinition .createDateTime(ldt, standardOffset, wallOffset); return ZoneOffsetTransition.of(dt, wallOffset, offsetAfter); } --- 648,663 ---- this.rule = rule; this.ldt = rule.toDateTime(year); this.ldtSecs = ldt.toEpochSecond(ZoneOffset.UTC); } ! ZoneOffsetTransition toTransition(ZoneOffset standardOffset, int savingsBeforeSecs, int negativeSavings) { // copy of code in ZoneOffsetTransitionRule to avoid infinite loop ZoneOffset wallOffset = ZoneOffset.ofTotalSeconds( standardOffset.getTotalSeconds() + savingsBeforeSecs); ZoneOffset offsetAfter = ZoneOffset.ofTotalSeconds( ! standardOffset.getTotalSeconds() + rule.savingsAmount - negativeSavings); LocalDateTime dt = rule.timeDefinition .createDateTime(ldt, standardOffset, wallOffset); return ZoneOffsetTransition.of(dt, wallOffset, offsetAfter); }
*** 664,677 **** /** * Tests if this a real transition with the active savings in seconds * * @param savingsBefore the active savings in seconds * @return true, if savings changes */ ! boolean isTransition(int savingsBefore) { ! return rule.savingsAmount != savingsBefore; } public int compareTo(TransRule other) { return (ldtSecs < other.ldtSecs)? -1 : ((ldtSecs == other.ldtSecs) ? 0 : 1); } --- 671,686 ---- /** * Tests if this a real transition with the active savings in seconds * * @param savingsBefore the active savings in seconds + * @param negativeSavings minimum savings in the rule, usually zero, but negative if negative DST is + * in effect. * @return true, if savings changes */ ! boolean isTransition(int savingsBefore, int negativeSavings) { ! return rule.savingsAmount - negativeSavings != savingsBefore; } public int compareTo(TransRule other) { return (ldtSecs < other.ldtSecs)? -1 : ((ldtSecs == other.ldtSecs) ? 0 : 1); }
*** 695,710 **** ZoneOffset wallOffset = ZoneOffset.ofTotalSeconds(stdOffset.getTotalSeconds() + savings); // start ldt of each zone window LocalDateTime zoneStart = LocalDateTime.MIN; ! // first stanard offset ZoneOffset firstStdOffset = stdOffset; // first wall offset ZoneOffset firstWallOffset = wallOffset; for (ZoneLine zone : zones) { // check if standard offset changed, update it if yes ZoneOffset stdOffsetPrev = stdOffset; // for effectiveSavings check if (zone.stdOffsetSecs != stdOffset.getTotalSeconds()) { ZoneOffset stdOffsetNew = ZoneOffset.ofTotalSeconds(zone.stdOffsetSecs); standardTransitionList.add( --- 704,729 ---- ZoneOffset wallOffset = ZoneOffset.ofTotalSeconds(stdOffset.getTotalSeconds() + savings); // start ldt of each zone window LocalDateTime zoneStart = LocalDateTime.MIN; ! // first standard offset ZoneOffset firstStdOffset = stdOffset; // first wall offset ZoneOffset firstWallOffset = wallOffset; for (ZoneLine zone : zones) { + // Adjust stdOffset, if negative DST is observed. It should be either + // fixed amount, or expressed in the named Rules. + int negativeSavings = Math.min(zone.fixedSavingsSecs, findNegativeSavings(zoneStart, zone)); + if (negativeSavings < 0) { + zone.stdOffsetSecs += negativeSavings; + if (zone.fixedSavingsSecs < 0) { + zone.fixedSavingsSecs = 0; + } + } + // check if standard offset changed, update it if yes ZoneOffset stdOffsetPrev = stdOffset; // for effectiveSavings check if (zone.stdOffsetSecs != stdOffset.getTotalSeconds()) { ZoneOffset stdOffsetNew = ZoneOffset.ofTotalSeconds(zone.stdOffsetSecs); standardTransitionList.add(
*** 789,808 **** Collections.sort(lastRules); } // sort the merged rules Collections.sort(trules); ! effectiveSavings = 0; for (TransRule rule : trules) { if (rule.toEpochSecond(stdOffsetPrev, savings) > zoneStart.toEpochSecond(wallOffset)) { // previous savings amount found, which could be the // savings amount at the instant that the window starts // (hence isAfter) break; } ! effectiveSavings = rule.rule.savingsAmount; } } // check if the start of the window represents a transition ZoneOffset effectiveWallOffset = ZoneOffset.ofTotalSeconds(stdOffset.getTotalSeconds() + effectiveSavings); --- 808,827 ---- Collections.sort(lastRules); } // sort the merged rules Collections.sort(trules); ! effectiveSavings = -negativeSavings; for (TransRule rule : trules) { if (rule.toEpochSecond(stdOffsetPrev, savings) > zoneStart.toEpochSecond(wallOffset)) { // previous savings amount found, which could be the // savings amount at the instant that the window starts // (hence isAfter) break; } ! effectiveSavings = rule.rule.savingsAmount - negativeSavings; } } // check if the start of the window represents a transition ZoneOffset effectiveWallOffset = ZoneOffset.ofTotalSeconds(stdOffset.getTotalSeconds() + effectiveSavings);
*** 815,839 **** savings = effectiveSavings; // apply rules within the window if (trules != null) { long zoneStartEpochSecs = zoneStart.toEpochSecond(wallOffset); for (TransRule trule : trules) { ! if (trule.isTransition(savings)) { long epochSecs = trule.toEpochSecond(stdOffset, savings); if (epochSecs < zoneStartEpochSecs || epochSecs >= zone.toDateTimeEpochSecond(savings)) { continue; } ! transitionList.add(trule.toTransition(stdOffset, savings)); ! savings = trule.rule.savingsAmount; } } } if (lastRules != null) { for (TransRule trule : lastRules) { ! lastTransitionRuleList.add(trule.rule.toTransitionRule(stdOffset, savings)); ! savings = trule.rule.savingsAmount; } } // finally we can calculate the true end of the window, passing it to the next window wallOffset = ZoneOffset.ofTotalSeconds(stdOffset.getTotalSeconds() + savings); --- 834,858 ---- savings = effectiveSavings; // apply rules within the window if (trules != null) { long zoneStartEpochSecs = zoneStart.toEpochSecond(wallOffset); for (TransRule trule : trules) { ! if (trule.isTransition(savings, negativeSavings)) { long epochSecs = trule.toEpochSecond(stdOffset, savings); if (epochSecs < zoneStartEpochSecs || epochSecs >= zone.toDateTimeEpochSecond(savings)) { continue; } ! transitionList.add(trule.toTransition(stdOffset, savings, negativeSavings)); ! savings = trule.rule.savingsAmount - negativeSavings; } } } if (lastRules != null) { for (TransRule trule : lastRules) { ! lastTransitionRuleList.add(trule.rule.toTransitionRule(stdOffset, savings, negativeSavings)); ! savings = trule.rule.savingsAmount - negativeSavings; } } // finally we can calculate the true end of the window, passing it to the next window wallOffset = ZoneOffset.ofTotalSeconds(stdOffset.getTotalSeconds() + savings);
*** 846,851 **** --- 865,904 ---- standardTransitionList, transitionList, lastTransitionRuleList); } + /** + * Find the minimum negative savings in named Rules for a Zone. Savings are only + * looked at for the period of the subject Zone. + * + * @param zoneStart start LDT of the zone + * @param zl ZoneLine to look at + */ + private int findNegativeSavings(LocalDateTime zoneStart, ZoneLine zl) { + int negativeSavings = 0; + LocalDateTime zoneEnd = zl.toDateTime(); + + if (zl.savingsRule != null) { + List<RuleLine> rlines = rules.get(zl.savingsRule); + if (rlines == null) { + throw new IllegalArgumentException("<Rule> not found: " + + zl.savingsRule); + } + + negativeSavings = Math.min(0, rlines.stream() + .filter(l -> windowOverlap(l, zoneStart.getYear(), zoneEnd.getYear())) + .map(l -> l.savingsAmount) + .min(Comparator.naturalOrder()) + .orElse(0)); + } + + return negativeSavings; + } + + private boolean windowOverlap(RuleLine ruleLine, int zoneStartYear, int zoneEndYear) { + boolean overlap = zoneStartYear <= ruleLine.startYear && zoneEndYear >= ruleLine.startYear || + zoneStartYear <= ruleLine.endYear && zoneEndYear >= ruleLine.endYear; + + return overlap; + } }
< prev index next >