Прежде всего, имейте в виду, что смещения со временем меняются (даже стандартные), в основном из-за правительств, законов и других внешних факторов.
Вот почему API требует Instant
в качестве ссылки: чтобы узнать, какое было стандартное смещение в этот конкретный момент (независимо от того, находится ли Instant
в прошлом, настоящем или будущем). Вы не можете сказать, каково смещение, не зная, когда вы вовремя. И именно поэтому ответ @Joachim является правильным.
Но, как вы сказали в комментариях, что не хотите зависеть от Instant.now()
, я сделал код ниже - и имейте в виду, что решение не на 100% идеально по причинам, указанным выше. Это просто лучшее, что у меня есть по вашим критериям.
Вы можете сделать это, используя класс java.time.zone.ZoneRules
, который вы можете получить непосредственно из своего экземпляра ZoneId
:
// pick a timezone with DST
ZoneId zone = ZoneId.of("America/Sao_Paulo");
// get rules
ZoneRules rules = zone.getRules();
// check if offset changes over time (if it returns false, it means is not fixed, so it has DST)
System.out.println(rules.isFixedOffset()); // false
В приведенном выше коде rules.isFixedOffset()
возвращает false
, что означает, что смещение соответствующего часового пояса меняется со временем (таким образом, у него есть изменения DST).
Чтобы узнать, когда происходят эти изменения летнего времени, вы должны получить все переходы:
// get all transitions (all dates where DST starts or ends)
List<ZoneOffsetTransition> transitions = rules.getTransitions();
transitions.stream().forEach(System.out::println);
Это печатает много строк (поскольку в этом часовом поясе почти каждый год летнее время). Вот пример последних двух строк:
Переход[Перекрытие с 00:00-02:00 2039-02:00 до -03:00
Переход[Пробел с 00:00-03:00-2039-03:00 до -02:00]
Это означает, что в 20.02.2039 в полночь смещение изменится с -02:00
на -03:00
(конец летнего времени - часы переводятся на 1 час назад), а в 16.10.2039 strong> в полночь смещение изменится с -03:00
на -02:00
(переход на летнее время — часы переводятся на 1 час вперед).
Итак, если вы хотите узнать смещение, когда это не летнее время, вы просто получаете последний переход, проверяете, является ли он разрывом или перекрытием, и получаете смещение после или до:
// get the last transition
ZoneOffsetTransition last = transitions.get(transitions.size() - 1);
// find the offset without DST interference
ZoneOffset offsetWithoutDST;
// overlap means that clock moves back 1 hour (when DST ends)
if(last.isOverlap()) {
// DST ends, get the offset after it
offsetWithoutDST = last.getOffsetAfter();
} else {
// DST starts, get the offset before it
offsetWithoutDST = last.getOffsetBefore();
}
System.out.println(offsetWithoutDST);
В этом случае он печатает -03:00
, что является «нормальным» смещением для часового пояса America/Sao_Paulo
(когда не летнее время).
PS: обратите внимание, что летнее и даже стандартное смещения могут сильно меняться с течением времени.
Тот факт, что смещение сегодня одно, не означает, что оно всегда было одним и тем же: правительства могут изменить смещение в любое время, и в очень прошлые даты — например, до 1900 года — смещения были гораздо более беспорядочными, чем сегодня (в каждом городе свое время, со смещениями типа -03:06:28
и т. д.).
Приведенный выше код получает стандартное (не летнее) смещение для правил текущего часового пояса. Если вы хотите узнать, каково было смещение без перехода на летнее время 30 лет назад, вы можете использовать @Joachim answer (передав Instant
30 лет назад в качестве параметра).
person
Community
schedule
06.06.2017
getRawOffset()
близок к тому, что вы хотите, и обязательно должен возвращать отрицательные значения, где это уместно. Разница в том, что вы можете не получить из этого исторически правильные (или даже релевантные) значения. - person Joachim Sauer   schedule 06.06.2017java.time
. Для чего вам нужна эта информация? - person Joachim Sauer   schedule 06.06.2017ZoneRules.getStandardOffset(Instant)
получает стандартное смещение в определенный момент (поскольку стандарт может меняться со временем, вам всегда нуженInstant
в качестве эталона) - только потому, что сегодня он один, это не значит всегда было так в прошлом. Это также не означает, что в будущем всегда будет так: если завтра какое-то правительство решит изменить часовой пояс страны/штата/региона/чего-то еще, нам всем придется обновить наши системы с помощью этого нового правила ( иgetStandardOffset
дляInstant
в будущем вернет это новое смещение). - person   schedule 07.06.2017Instant
в качестве ссылки. - person   schedule 07.06.2017