DaylightSavingUtils.java
- /*
- * GovWay - A customizable API Gateway
- * https://govway.org
- *
- * Copyright (c) 2005-2025 Link.it srl (https://link.it).
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3, as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
- package org.openspcoop2.utils.date;
- import java.time.*;
- import java.time.format.DateTimeFormatter;
- import java.time.zone.ZoneOffsetTransition;
- import java.time.zone.ZoneRules;
- /**
- * DaylightSavingUtils
- *
- * @author Poli Andrea (poli@link.it)
- * @author $Author$
- * @version $Rev$, $Date$
- */
- public class DaylightSavingUtils {
-
- /**
- * Ora Solare (CET - Central European Time): L'ora solare è il tempo standard utilizzato durante l'inverno. In Europa, è UTC+1, il che significa che è un'ora avanti rispetto al Coordinated Universal Time (UTC). L'ora solare è usata dal tardo autunno all'inizio della primavera, solitamente da fine ottobre a fine marzo.
- Ora Legale (CEST - Central European Summer Time): L'ora legale viene utilizzata durante l'estate per risparmiare energia, spostando le lancette avanti di un'ora. In Europa, è UTC+2, ovvero due ore avanti rispetto a UTC. L'ora legale è in vigore da fine marzo a fine ottobre.
- Passaggio da Ora Legale a Ora Solare: In autunno (solitamente l'ultima domenica di ottobre), l'orologio viene spostato indietro di un'ora alle 03:00 AM CEST, tornando alle 02:00 AM CET (ora solare).
- Passaggio da Ora Solare a Ora Legale: In primavera (solitamente l'ultima domenica di marzo), l'orologio viene spostato avanti di un'ora alle 02:00 AM CET, diventando le 03:00 AM CEST (ora legale).
- */
-
- private DaylightSavingUtils() {}
- // Formato per il parsing delle date con offset
- private static final String OFFSET_FORMAT = "yyyy-MM-dd HH:mm:ssXXX";
- public static String getOffsetFormat() {
- return OFFSET_FORMAT;
- }
- private static final DateTimeFormatter OFFSET_FORMATTER = DateTimeFormatter.ofPattern(OFFSET_FORMAT);
- public static DateTimeFormatter getOffsetFormatter() {
- return OFFSET_FORMATTER;
- }
- // Formato per il parsing delle date senza offset
- private static final String BASIC_FORMAT = "yyyy-MM-dd HH:mm:ss";
- public static String getBasicFormat() {
- return BASIC_FORMAT;
- }
- private static final DateTimeFormatter BASIC_FORMATTER = DateTimeFormatter.ofPattern(BASIC_FORMAT);
- public static DateTimeFormatter getBasicFormatter() {
- return BASIC_FORMATTER;
- }
- // Zona di riferimento, ad esempio Europe/Rome
- /**private static final ZoneId ZONE_ID = ZoneId.of("Europe/Rome");*/
- private static final ZoneId ZONE_ID_DEFAULT = ZoneId.systemDefault();
- public static ZoneId getZoneIdDefault() {
- return ZONE_ID_DEFAULT;
- }
-
- /**
- * Calcola quanti minuti mancano al prossimo cambio di ora legale o solare
- * per una data con offset di fuso orario.
- *
- * @param inputDate La data in formato "yyyy-MM-dd HH:mm:ss+01"
- * @return Minuti mancanti al cambio di ora
- */
- public static long minutesUntilNextTransition(String inputDate) {
- return minutesUntilNextTransition(inputDate, ZONE_ID_DEFAULT);
- }
- public static long minutesUntilNextTransition(String inputDate, ZoneId zoneId) {
- return minutesUntilNextTransition(inputDate, zoneId, null, null);
- }
- public static long minutesUntilNextTransition(String inputDate, String format) {
- return minutesUntilNextTransition(inputDate, ZONE_ID_DEFAULT, format);
- }
- public static long minutesUntilNextTransition(String inputDate, ZoneId zoneId, String format) {
- return minutesUntilNextTransition(inputDate, zoneId, format, null);
- }
- public static long minutesUntilNextTransition(String inputDate, DateTimeFormatter formatter) {
- return minutesUntilNextTransition(inputDate, ZONE_ID_DEFAULT, formatter);
- }
- public static long minutesUntilNextTransition(String inputDate, ZoneId zoneId, DateTimeFormatter formatter) {
- return minutesUntilNextTransition(inputDate, zoneId, null, formatter);
- }
- private static long minutesUntilNextTransition(String inputDate, ZoneId zoneId, String format, DateTimeFormatter formatter) {
- OffsetDateTime offsetDateTime = formatter!=null ? parseOffsetDateTime(inputDate, formatter) : parseOffsetDateTime(inputDate, format);
- ZonedDateTime zonedDateTime = offsetDateTime.atZoneSameInstant(zoneId);
- ZoneRules zoneRules = zoneId.getRules();
- ZoneOffsetTransition nextTransition = zoneRules.nextTransition(zonedDateTime.toInstant());
- if (nextTransition != null) {
- ZonedDateTime transitionDateTime = ZonedDateTime.ofInstant(nextTransition.getDateTimeBefore(), nextTransition.getOffsetBefore(), zoneId);
- return Duration.between(zonedDateTime, transitionDateTime).toMinutes();
- }
- return -1; // Nessuna transizione trovata
- }
- /**
- * Calcola quanti minuti mancano al prossimo cambio di ora legale o solare
- * per una data senza offset di fuso orario.
- *
- * @param inputDate La data in formato "yyyy-MM-dd HH:mm:ss"
- * @return Minuti mancanti al cambio di ora
- */
- public static long minutesUntilNextTransitionWithoutOffset(String inputDate) {
- return minutesUntilNextTransitionWithoutOffset(inputDate, ZONE_ID_DEFAULT);
- }
- public static long minutesUntilNextTransitionWithoutOffset(String inputDate, ZoneId zoneId) {
- return minutesUntilNextTransitionWithoutOffset(inputDate, zoneId, null, null);
- }
- public static long minutesUntilNextTransitionWithoutOffset(String inputDate, String format) {
- return minutesUntilNextTransitionWithoutOffset(inputDate, ZONE_ID_DEFAULT, format);
- }
- public static long minutesUntilNextTransitionWithoutOffset(String inputDate, ZoneId zoneId, String format) {
- return minutesUntilNextTransitionWithoutOffset(inputDate, zoneId, format, null);
- }
- public static long minutesUntilNextTransitionWithoutOffset(String inputDate, DateTimeFormatter formatter) {
- return minutesUntilNextTransitionWithoutOffset(inputDate, ZONE_ID_DEFAULT, formatter);
- }
- public static long minutesUntilNextTransitionWithoutOffset(String inputDate, ZoneId zoneId, DateTimeFormatter formatter) {
- return minutesUntilNextTransitionWithoutOffset(inputDate, zoneId, null, formatter);
- }
- private static long minutesUntilNextTransitionWithoutOffset(String inputDate, ZoneId zoneId, String format, DateTimeFormatter formatter) {
- LocalDateTime localDateTime = formatter!=null ? parseLocalDateTime(inputDate, formatter) : parseLocalDateTime(inputDate, format);
- ZonedDateTime zonedDateTime = localDateTime.atZone(zoneId);
- ZoneRules zoneRules = zoneId.getRules();
- ZoneOffsetTransition nextTransition = zoneRules.nextTransition(zonedDateTime.toInstant());
- if (nextTransition != null) {
- ZonedDateTime transitionDateTime = ZonedDateTime.ofInstant(nextTransition.getDateTimeBefore(), nextTransition.getOffsetBefore(), zoneId);
- return Duration.between(zonedDateTime, transitionDateTime).toMinutes();
- }
- return -1; // Nessuna transizione trovata
- }
-
-
- /**
- * Determina se una certa data si trova in ora legale o ora solare.
- *
- * @param inputDate La data in formato "yyyy-MM-dd HH:mm:ss+01"
- * @return "ora legale" o "ora solare" a seconda della data
- */
- public static TimeType getTimeType(String inputDate) {
- return getTimeType(inputDate, ZONE_ID_DEFAULT);
- }
- public static TimeType getTimeType(String inputDate, ZoneId zoneId) {
- return getTimeType(inputDate, zoneId, null, null);
- }
- public static TimeType getTimeType(String inputDate, String format) {
- return getTimeType(inputDate, ZONE_ID_DEFAULT, format);
- }
- public static TimeType getTimeType(String inputDate, ZoneId zoneId, String format) {
- return getTimeType(inputDate, zoneId, format, null);
- }
- public static TimeType getTimeType(String inputDate, DateTimeFormatter formatter) {
- return getTimeType(inputDate, ZONE_ID_DEFAULT, formatter);
- }
- public static TimeType getTimeType(String inputDate, ZoneId zoneId, DateTimeFormatter formatter) {
- return getTimeType(inputDate, zoneId, null, formatter);
- }
- private static TimeType getTimeType(String inputDate, ZoneId zoneId, String format, DateTimeFormatter formatter) {
- OffsetDateTime offsetDateTime = formatter!=null ? parseOffsetDateTime(inputDate, formatter) : parseOffsetDateTime(inputDate, format);
- ZonedDateTime zonedDateTime = offsetDateTime.atZoneSameInstant(zoneId);
- boolean isDaylightSavings = zonedDateTime.getZone().getRules().isDaylightSavings(zonedDateTime.toInstant());
- return isDaylightSavings ? TimeType.DAYLIGHT_SAVING_TIME : TimeType.STANDARD_TIME;
- }
- /**
- * Converte una data in formato "yyyy-MM-dd HH:mm:ss+01" in un ZonedDateTime
- * per il fuso orario specificato (es. Europe/Rome).
- *
- * @param inputDate La data in formato "yyyy-MM-dd HH:mm:ss+01"
- * @return ZonedDateTime corrispondente
- */
- public static ZonedDateTime convertToZonedDateTime(String inputDate) {
- return convertToZonedDateTime(inputDate, ZONE_ID_DEFAULT);
- }
- public static ZonedDateTime convertToZonedDateTime(String inputDate, ZoneId zoneId) {
- return convertToZonedDateTime(inputDate, zoneId, null, null);
- }
- public static ZonedDateTime convertToZonedDateTime(String inputDate, String format) {
- return convertToZonedDateTime(inputDate, ZONE_ID_DEFAULT, format);
- }
- public static ZonedDateTime convertToZonedDateTime(String inputDate, ZoneId zoneId, String format) {
- return convertToZonedDateTime(inputDate, zoneId, format, null);
- }
- public static ZonedDateTime convertToZonedDateTime(String inputDate, DateTimeFormatter formatter) {
- return convertToZonedDateTime(inputDate, ZONE_ID_DEFAULT, formatter);
- }
- public static ZonedDateTime convertToZonedDateTime(String inputDate, ZoneId zoneId, DateTimeFormatter formatter) {
- return convertToZonedDateTime(inputDate, zoneId, null, formatter);
- }
- private static ZonedDateTime convertToZonedDateTime(String inputDate, ZoneId zoneId, String format, DateTimeFormatter formatter) {
- OffsetDateTime offsetDateTime = formatter!=null ? parseOffsetDateTime(inputDate, formatter) : parseOffsetDateTime(inputDate, format);
- return offsetDateTime.atZoneSameInstant(zoneId);
- }
-
- /**
- * Determina se una data è nel giorno in cui avviene il cambio tra ora legale e ora solare (o viceversa).
- *
- * @param inputDate La data in formato "yyyy-MM-dd HH:mm:ss+01:00"
- * @return true se la data è nel giorno del cambio di ora, false altrimenti
- */
- public static TimeTransitionType getTimeChangePendingToday(String inputDate) {
- return getTimeChangePendingToday(inputDate, ZONE_ID_DEFAULT);
- }
- public static TimeTransitionType getTimeChangePendingToday(String inputDate, ZoneId zoneId) {
- return getTimeChangePendingToday(inputDate, zoneId, null, null);
- }
- public static TimeTransitionType getTimeChangePendingToday(String inputDate, String format) {
- return getTimeChangePendingToday(inputDate, ZONE_ID_DEFAULT, format);
- }
- public static TimeTransitionType getTimeChangePendingToday(String inputDate, ZoneId zoneId, String format) {
- return getTimeChangePendingToday(inputDate, zoneId, format, null);
- }
- public static TimeTransitionType getTimeChangePendingToday(String inputDate, DateTimeFormatter formatter) {
- return getTimeChangePendingToday(inputDate, ZONE_ID_DEFAULT, formatter);
- }
- public static TimeTransitionType getTimeChangePendingToday(String inputDate, ZoneId zoneId, DateTimeFormatter formatter) {
- return getTimeChangePendingToday(inputDate, zoneId, null, formatter);
- }
- private static TimeTransitionType getTimeChangePendingToday(String inputDate, ZoneId zoneId, String format, DateTimeFormatter formatter) {
- // Parse della stringa in OffsetDateTime
- OffsetDateTime dateTime = formatter!=null ? parseOffsetDateTime(inputDate, formatter) : parseOffsetDateTime(inputDate, format);
- // Ottieni il fuso orario dell'ambiente (ad esempio Europe/Rome)
- ZoneRules zoneRules = zoneId.getRules();
- // Ottieni la transizione successiva
- ZoneOffsetTransition nextTransition = zoneRules.nextTransition(dateTime.toInstant());
- if (nextTransition != null) {
- // Ottieni la data e l'ora del giorno della transizione
- LocalDate transitionDate = nextTransition.getDateTimeBefore().toLocalDate();
- // Verifica se la data fornita è nello stesso giorno della transizione
- if( dateTime.toLocalDate().equals(transitionDate) ) {
- // Ottieni gli offset prima e dopo la transizione
- ZoneOffset offsetBefore = nextTransition.getOffsetBefore();
- ZoneOffset offsetAfter = nextTransition.getOffsetAfter();
- // Determina il tipo di transizione
- if (offsetBefore.getTotalSeconds() > offsetAfter.getTotalSeconds()) {
- return TimeTransitionType.FROM_DAYLIGHT_SAVING_TO_STANDARD_TIME; // Ora legale a ora solare
- } else {
- return TimeTransitionType.FROM_STANDARD_TO_DAYLIGHT_SAVING_TIME; // Ora solare a ora legale
- }
- }
- }
-
- return null; // Nessuna transizione trovata
- }
-
-
- /**
- * Determina se una data è nel giorno in cui avviene il cambio tra ora legale e ora solare (o viceversa) per una data senza offset di fuso orario.
- *
- * @param inputDate La data in formato "yyyy-MM-dd HH:mm:ss"
- * @return true se la data è nel giorno del cambio di ora, false altrimenti
- */
- public static TimeTransitionType getTimeChangePendingTodayWithoutOffset(String inputDate) {
- return getTimeChangePendingTodayWithoutOffset(inputDate, ZONE_ID_DEFAULT);
- }
- public static TimeTransitionType getTimeChangePendingTodayWithoutOffset(String inputDate, ZoneId zoneId) {
- return getTimeChangePendingTodayWithoutOffset(inputDate, zoneId, null, null);
- }
- public static TimeTransitionType getTimeChangePendingTodayWithoutOffset(String inputDate, String format) {
- return getTimeChangePendingTodayWithoutOffset(inputDate, ZONE_ID_DEFAULT, format);
- }
- public static TimeTransitionType getTimeChangePendingTodayWithoutOffset(String inputDate, ZoneId zoneId, String format) {
- return getTimeChangePendingTodayWithoutOffset(inputDate, zoneId, format, null);
- }
- public static TimeTransitionType getTimeChangePendingTodayWithoutOffset(String inputDate, DateTimeFormatter formatter) {
- return getTimeChangePendingTodayWithoutOffset(inputDate, ZONE_ID_DEFAULT, formatter);
- }
- public static TimeTransitionType getTimeChangePendingTodayWithoutOffset(String inputDate, ZoneId zoneId, DateTimeFormatter formatter) {
- return getTimeChangePendingTodayWithoutOffset(inputDate, zoneId, null, formatter);
- }
- private static TimeTransitionType getTimeChangePendingTodayWithoutOffset(String inputDate, ZoneId zoneId, String format, DateTimeFormatter formatter) {
-
- LocalDateTime localDateTime = formatter!=null ? parseLocalDateTime(inputDate, formatter) : parseLocalDateTime(inputDate, format);
- ZonedDateTime zonedDateTime = localDateTime.atZone(zoneId);
- ZoneRules zoneRules = zoneId.getRules();
- ZoneOffsetTransition nextTransition = zoneRules.nextTransition(zonedDateTime.toInstant());
- if (nextTransition != null) {
- ZonedDateTime transitionDateTime = ZonedDateTime.ofInstant(nextTransition.getDateTimeBefore(), nextTransition.getOffsetBefore(), zoneId);
-
- // Verifica se la data fornita è nello stesso giorno della transizione
- if( localDateTime.toLocalDate().equals(transitionDateTime.toLocalDate()) ) {
- // Ottieni gli offset prima e dopo la transizione
- ZoneOffset offsetBefore = nextTransition.getOffsetBefore();
- ZoneOffset offsetAfter = nextTransition.getOffsetAfter();
- // Determina il tipo di transizione
- if (offsetBefore.getTotalSeconds() > offsetAfter.getTotalSeconds()) {
- return TimeTransitionType.FROM_DAYLIGHT_SAVING_TO_STANDARD_TIME; // Ora legale a ora solare
- } else {
- return TimeTransitionType.FROM_STANDARD_TO_DAYLIGHT_SAVING_TIME; // Ora solare a ora legale
- }
- }
- }
-
- return null; // Nessuna transizione trovata
- }
-
-
-
- /** Parser */
-
- public static LocalDateTime parseLocalDateTime(String inputDate) {
- return parseLocalDateTime(inputDate, BASIC_FORMATTER);
- }
- public static LocalDateTime parseLocalDateTime(String inputDate, String format) {
- if(format==null) {
- return parseLocalDateTime(inputDate);
- }
- return parseLocalDateTime(inputDate, DateTimeFormatter.ofPattern(format));
- }
- public static LocalDateTime parseLocalDateTime(String inputDate, DateTimeFormatter formatter) {
- if(formatter==null) {
- return parseLocalDateTime(inputDate);
- }
- return LocalDateTime.parse(inputDate, formatter);
- }
-
- public static OffsetDateTime parseOffsetDateTime(String inputDate) {
- return parseOffsetDateTime(inputDate, OFFSET_FORMATTER);
- }
- public static OffsetDateTime parseOffsetDateTime(String inputDate, String format) {
- if(format==null) {
- return parseOffsetDateTime(inputDate);
- }
- return parseOffsetDateTime(inputDate, DateTimeFormatter.ofPattern(format));
- }
- public static OffsetDateTime parseOffsetDateTime(String inputDate, DateTimeFormatter formatter) {
- if(formatter==null) {
- return parseOffsetDateTime(inputDate);
- }
- if (inputDate.matches(".*[+-]\\d{2}$")) {
- inputDate += ":00";
- }
- return OffsetDateTime.parse(inputDate, formatter);
- }
- }