У меня есть диапазон дат (начальная и конечная дата), и мне нужно знать, подпадает ли он под переход на летнее время.
Есть ли какой-нибудь Java API для проверки этого или какой-либо Java-код для этого?
У меня есть диапазон дат (начальная и конечная дата), и мне нужно знать, подпадает ли он под переход на летнее время.
Есть ли какой-нибудь Java API для проверки этого или какой-либо Java-код для этого?
Переход на летнее время происходит в разные даты в каждой стране / регионе, поэтому первое, что нужно знать, - это название проверяемого часового пояса.
Я пишу этот ответ, используя как Joda-Time, так и новый Java Date / Time API, и оба используют IANA. список названий часовых поясов (в формате Continent/City). Оба API также избегают использования трехбуквенных имен, поскольку они неоднозначно и нестандартно.
В приведенном ниже коде я буду использовать America/Sao_Paulo (часовой пояс, в котором я живу, в котором каждый год меняется летнее время), но вы можете заменить его на нужный часовой пояс.
В приведенном ниже коде показано, как проверить, находится ли дата в DST, и найти следующую дату, когда произойдет изменение DST. Итак, если у вас есть даты начала и окончания и вы хотите знать, находятся ли оба в пределах изменения DST, вы можете проверить, находятся ли оба в DST или нет, а также найти следующее и предыдущее изменения DST (и проверить, находятся ли даты между эти изменения - мне непонятно, как должна проводиться ваша проверка).
Также имейте в виду, что Joda-Time находится в режиме обслуживания и заменяется новыми API, поэтому я не рекомендую начинать с ним новый проект. Даже на веб-сайте joda написано: Обратите внимание, что Joda-Time считается во многом «законченный» проект. Никаких серьезных улучшений не планируется. Если вы используете Java SE 8, перейдите на java.time (JSR-310).
Вы можете использовать класс org.joda.time.DateTimeZone. Чтобы узнать все доступные часовые пояса, позвоните DateTimeZone.getAvailableIDs().
Приведенный ниже код проверяет, находится ли дата в DST, а также находит следующую дату, когда произойдет изменение DST:
// create timezone object
DateTimeZone zone = DateTimeZone.forID("America/Sao_Paulo");
// check if a date is in DST
DateTime inDst = new DateTime(2017, 1, 1, 10, 0, zone);
// isStandardOffset returns false (it's in DST)
System.out.println(zone.isStandardOffset(inDst.getMillis()));
// check when it'll be the next DST change
DateTime nextDstChange = new DateTime(zone.nextTransition(inDst.getMillis()), zone);
System.out.println(nextDstChange); // 2017-02-18T23:00:00.000-03:00
// check if a date is in DST
DateTime noDst = new DateTime(2017, 6, 18, 10, 0, zone);
// isStandardOffset returns true (it's not in DST)
System.out.println(zone.isStandardOffset(noDst.getMillis()));
// check when it'll be the next DST change
nextDstChange = new DateTime(zone.nextTransition(noDst.getMillis()), zone);
System.out.println(nextDstChange); // 2017-10-15T01:00:00.000-02:00
Если вы хотите найти предыдущее изменение летнего времени (вместо следующего), вызовите previousTransition() вместо nextTransition().
Если вы используете Java 8, новый API java.time уже идет изначально.
Если вы используете Java ‹= 7, вы можете использовать ThreeTen Backport, отличный backport для новых классов даты / времени Java 8. А для Android есть ThreeTenABP (подробнее о том, как его использовать здесь).
Приведенный ниже код работает для обоих. Единственное отличие состоит в именах пакетов (в Java 8 это java.time, а в ThreeTen Backport (или в Android ThreeTenABP) org.threeten.bp), но имена классов и методов одинаковы.
Код очень похож на версию Joda-Time. Основные отличия:
isStandardOffset(), чтобы проверить, является ли дата не в DST, в новом API есть isDaylightSavings(), чтобы проверить, находится ли дата в DST.DateTimeZone, но новый API имеет специальный класс для правил DST (java.time.zone.ZoneRules).java.time.zone.ZoneOffsetTransition вместо прямого возврата даты (этот объект предоставляет дополнительную информацию об изменении летнего времени, как показано ниже).Несмотря на все эти различия, идея очень похожа:
// create timezone object
ZoneId zone = ZoneId.of("America/Sao_Paulo");
// get the timezone's rules
ZoneRules rules = zone.getRules();
// check if a date is in DST
ZonedDateTime inDST = ZonedDateTime.of(2017, 1, 1, 10, 0, 0, 0, zone);
// isDaylightSavings returns true (it's in DST)
System.out.println(rules.isDaylightSavings(inDST.toInstant()));
// check when it'll be the next DST change
ZoneOffsetTransition nextTransition = rules.nextTransition(inDST.toInstant());
// getInstant() returns the UTC instant; atZone converts to the specified timezone
System.out.println(nextTransition.getInstant().atZone(zone)); // 2017-02-18T23:00-03:00[America/Sao_Paulo]
// you can also check the date/time and offset before and after the DST change
// in this case, at 19/02/2017, the clock is moved 1 hour back (from midnight to 11 PM)
ZonedDateTime beforeDST = ZonedDateTime.of(nextTransition.getDateTimeBefore(), nextTransition.getOffsetBefore());
System.out.println(beforeDST); // 2017-02-19T00:00-02:00
ZonedDateTime afterDST = ZonedDateTime.of(nextTransition.getDateTimeAfter(), nextTransition.getOffsetAfter());
System.out.println(afterDST); // 2017-02-18T23:00-03:00
// check if a date is in DST
ZonedDateTime noDST = ZonedDateTime.of(2017, 6, 1, 10, 0, 0, 0, zone);
// isDaylightSavings returns false (it's not in DST)
System.out.println(rules.isDaylightSavings(noDST.toInstant()));
// check when it'll be the next DST change
nextTransition = rules.nextTransition(noDST.toInstant());
// getInstant() returns the UTC instant; atZone converts to the specified timezone
System.out.println(nextTransition.getInstant().atZone(zone)); // 2017-10-15T01:00-02:00[America/Sao_Paulo]
// you can also check the date/time and offset before and after the DST change
// in this case, at 15/10/2017, the clock is moved 1 hour forward (from midnight to 1 AM)
beforeDST = ZonedDateTime.of(nextTransition.getDateTimeBefore(), nextTransition.getOffsetBefore());
System.out.println(beforeDST); // 2017-10-15T00:00-03:00
afterDST = ZonedDateTime.of(nextTransition.getDateTimeAfter(), nextTransition.getOffsetAfter());
System.out.println(afterDST); // 2017-10-15T01:00-02:00
Если вы хотите найти предыдущее изменение летнего времени вместо следующего, вы можете вызвать rules.previousTransition() вместо rules.nextTransition().
Конечно, есть. Их также несколько. Стандартный API для использования - java.time.
Совершенно очевидно, что сначала вам нужно выбрать часовой пояс, для которого вы хотите это сделать.
Вы отметили свой вопрос gmt, и это легко: в GMT нет перехода на летнее время (летнее время), поэтому в вашем диапазоне никогда не будет перехода. Если это то, что вы имели в виду, вам не нужно читать дальше.
Даты перехода на летнее время не совпадают в Северной Америке и ЕС, а в южном полушарии они еще полностью разные. Также во многих часовых поясах DST вообще не применяется. Поэтому получите желаемый часовой пояс из ZoneId.of(), указав строку в форме continent/city, например Europe/Stockholm. Он принимает несколько городов, я думаю, что есть хотя бы один в каждом часовом поясе и по одному в каждой стране. Используйте ZoneId.getRules(), чтобы получить объект ZoneRules. Пожалуйста, проверьте документацию для всех что вы можете делать с этим объектом. Думаю, я бы попробовал nextTransistion() передать дату начала. Если я получаю обратно null, переключение диапазона невозможно (вероятно, зона не применяет летнее время). Если я получу обратно ZoneOffsetTransition, используйте его getInstant() и проверьте, не лежит ли Instant до вашей даты окончания.
java.time был описан в JSR-310. Он встроен в Java 8 и новее. Если вы еще не используете Java 8, воспользуйтесь ThreeTen Backport.
Вы отметили свой вопрос jodatime, и да, Joda-Time тоже должен быть вариантом.
Обратите внимание, что Joda-Time считается в значительной степени «законченным» проектом. Никаких серьезных улучшений не планируется. Если вы используете Java SE 8, перейдите на
java.time(JSR-310).
Цитируется с домашней страницы Joda-Time.