|
|
@@ -0,0 +1,269 @@
|
|
|
+package net.ranides.assira.time;
|
|
|
+
|
|
|
+import java.time.*;
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
+import java.time.temporal.ChronoUnit;
|
|
|
+import java.util.Locale;
|
|
|
+import java.util.Objects;
|
|
|
+import java.util.function.Function;
|
|
|
+
|
|
|
+import static java.util.Optional.ofNullable;
|
|
|
+
|
|
|
+public class DateTimeUtils {
|
|
|
+
|
|
|
+ private DateTimeUtils() {
|
|
|
+ }
|
|
|
+
|
|
|
+ public static final ZoneId ZONE_POLAND = ZoneId.of("Poland");
|
|
|
+ public static final ZoneId ZONE_0 = ZoneId.of("Etc/GMT0");
|
|
|
+
|
|
|
+ public static final ZonedDateTime MIN = ZonedDateTime.of(1900, 1, 1, 0, 0, 0, 0, ZONE_0);
|
|
|
+ public static final ZonedDateTime MAX = ZonedDateTime.of(4000, 1, 1, 0, 0, 0, 0, ZONE_0);
|
|
|
+
|
|
|
+
|
|
|
+ public static final String DATE_TIME_AT_UTC_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
|
|
|
+ public static final String DATE_TIME_ZONED_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
|
|
|
+ private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern(DATE_TIME_AT_UTC_PATTERN);
|
|
|
+ public static final DateTimeFormatter ZONED_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSX");
|
|
|
+ private static final DateTimeFormatter COMPRESS_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HHmmss");
|
|
|
+ public static final DateTimeFormatter ONLY_DATE = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
|
+ public static final DateTimeFormatter ONLY_TIME = DateTimeFormatter.ofPattern("HH:mm");
|
|
|
+ public static final DateTimeFormatter DATE_HOUR_MINUTES = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
|
|
|
+ public static final DateTimeFormatter DATE_HOUR_MINUTES_SECONDS = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
|
|
+ public static final DateTimeFormatter YEAR = DateTimeFormatter.ofPattern("yyyy");
|
|
|
+
|
|
|
+ public static final DateTimeFormatter SHORT_DAY = DateTimeFormatter.ofPattern("dd.MM EE");
|
|
|
+
|
|
|
+ private static final DateTimeFormatter TIME_FORMAT = DateTimeFormatter.ofPattern("HH:mm");
|
|
|
+
|
|
|
+ public static String convertDateTimeToCompressFormat(ZonedDateTime dateTime) {
|
|
|
+ return mapNullable(dateTime, v -> COMPRESS_FORMAT.format(v));
|
|
|
+ }
|
|
|
+
|
|
|
+ public static String convertOnlyTimeToString(ZonedDateTime date) {
|
|
|
+ return mapNullable(date, v -> ONLY_TIME.format(v));
|
|
|
+ }
|
|
|
+
|
|
|
+ public static String convertOnlyDateToString(ZonedDateTime date) {
|
|
|
+ return mapNullable(date, v -> ONLY_DATE.format(v));
|
|
|
+ }
|
|
|
+
|
|
|
+ public static String convertOnlyDateToString(ZonedDate date) {
|
|
|
+ return mapNullable(date, v -> ONLY_DATE.format(v.withMidnight()));
|
|
|
+ }
|
|
|
+
|
|
|
+ public static String formatAsDateHoursMinutes(ZonedDateTime dateTime) {
|
|
|
+ return mapNullable(dateTime, v -> DATE_HOUR_MINUTES.format(v));
|
|
|
+ }
|
|
|
+
|
|
|
+ public static String formatAsDateHoursMinutesSeconds(ZonedDateTime dateTime) {
|
|
|
+ return mapNullable(dateTime, v -> DATE_HOUR_MINUTES_SECONDS.format(v));
|
|
|
+ }
|
|
|
+
|
|
|
+ public static String convertShortDayForPolishTime(ZonedDateTime date) {
|
|
|
+ Locale locale = Locale.getDefault();
|
|
|
+ return mapNullable(polishTime(date), v -> DateTimeFormatter.ofPattern("dd.MM EE", locale).format(v));
|
|
|
+ }
|
|
|
+
|
|
|
+ public static String getFullDayNameFromDate(ZonedDateTime date) {
|
|
|
+ Locale locale = Locale.getDefault();
|
|
|
+
|
|
|
+ return mapNullable(polishTime(date), v -> DateTimeFormatter.ofPattern("EEEE", locale).format(v));
|
|
|
+ }
|
|
|
+
|
|
|
+ public static String convertDateToString(ZonedDateTime date) {
|
|
|
+ return mapNullable(date, v -> FORMATTER.format(v));
|
|
|
+ }
|
|
|
+
|
|
|
+ public static ZonedDateTime convertStringToDate(String date) {
|
|
|
+ return mapNullable(date, v -> ZonedDateTime.parse(v, FORMATTER));
|
|
|
+ }
|
|
|
+
|
|
|
+ public static ZonedDateTime truncateToDate(ZonedDateTime date) {
|
|
|
+ return mapNullable(date, v -> v.withMinute(0).withHour(0).withSecond(0).withNano(0));
|
|
|
+ }
|
|
|
+
|
|
|
+ public static ZonedDateTime utcTime(ZonedDateTime dateTime) {
|
|
|
+ return mapNullable(dateTime, v -> v.withZoneSameInstant(ZONE_0));
|
|
|
+ }
|
|
|
+
|
|
|
+ public static ZonedDateTime polishTime(ZonedDateTime dateTime) {
|
|
|
+ return mapNullable(dateTime, v -> v.withZoneSameInstant(ZONE_POLAND));
|
|
|
+ }
|
|
|
+
|
|
|
+ public static ZonedDate polishDate(ZonedDateTime dateTimeInUtc) {
|
|
|
+ return ZonedDate.from(polishTime(dateTimeInUtc));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Parses date from the given date time string and returns as ZonedDate in Polish timezone
|
|
|
+ * @param dateTime String in yyyy-MM-dd'T'HH:mm:ss.SSSX format, where X is time zone indicator
|
|
|
+ * @return Parsed date
|
|
|
+ */
|
|
|
+ public static ZonedDate parseToPolishDate(String dateTime) {
|
|
|
+ return ZonedDate.from(parseToPolishTimezone(dateTime));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Parses time from the given date time string and returns as ZonedTime in Polish timezone
|
|
|
+ *
|
|
|
+ * @param dateTime String in yyyy-MM-dd'T'HH:mm:ss.SSSX format, where X is time zone indicator
|
|
|
+ * @return Parsed time
|
|
|
+ */
|
|
|
+ public static ZonedTime parseToPolishTime(String dateTime) {
|
|
|
+ return ZonedTime.from(parseToPolishTimezone(dateTime));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Parses date and time from the given date time string and returns as ZonedDateTime in Polish timezone
|
|
|
+ * @param dateTime String in yyyy-MM-dd'T'HH:mm:ss.SSSX format, where X is time zone indicator
|
|
|
+ * @return Parsed date and time with Polish timezone set
|
|
|
+ */
|
|
|
+ public static ZonedDateTime parseToPolishTimezone(String dateTime) {
|
|
|
+ return ZonedDateTime.parse(dateTime, ZONED_FORMAT).withZoneSameInstant(ZONE_POLAND);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static ZonedDateTime min(ZonedDateTime firstDate, ZonedDateTime secondDate) {
|
|
|
+ if (firstDate == null && secondDate == null) return null;
|
|
|
+ if (firstDate == null) return secondDate;
|
|
|
+ if (secondDate == null) return firstDate;
|
|
|
+ return firstDate.isBefore(secondDate)
|
|
|
+ ? firstDate
|
|
|
+ : secondDate;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static ZonedDateTime max(ZonedDateTime firstDate, ZonedDateTime secondDate) {
|
|
|
+ if (firstDate == null && secondDate == null) return null;
|
|
|
+ if (firstDate == null) return secondDate;
|
|
|
+ if (secondDate == null) return firstDate;
|
|
|
+ return firstDate.isBefore(secondDate)
|
|
|
+ ? secondDate
|
|
|
+ : firstDate;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static boolean dateBetweenWithMinMax(ZonedDateTime testedDate, ZonedDateTime dateFrom, ZonedDateTime dateTo) {
|
|
|
+ return dateBetweenWithMinMax(testedDate, dateFrom, dateTo, false);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static boolean dateBetweenWithMinMax(ZonedDateTime testedDate, ZonedDateTime dateFrom, ZonedDateTime dateTo, boolean inclusive) {
|
|
|
+ dateFrom = valueOrMin(dateFrom);
|
|
|
+ dateTo = valueOrMax(dateTo);
|
|
|
+
|
|
|
+ if(inclusive) {
|
|
|
+ return !(testedDate.isBefore(dateFrom) || testedDate.equals(dateFrom)) && !(testedDate.isAfter(dateTo) || testedDate.equals(dateTo));
|
|
|
+ }
|
|
|
+
|
|
|
+ return !testedDate.isBefore(valueOrMin(dateFrom)) && !testedDate.isAfter(dateTo);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static ZonedDateTime valueOrMin(ZonedDateTime date) {
|
|
|
+ return ofNullable(date).orElseGet(() -> MIN);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static ZonedDateTime valueOrMax(ZonedDateTime date) {
|
|
|
+ return ofNullable(date).orElseGet(() -> MAX);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static ZonedDateTime addTimeToDate(String dateValue, String timeValue) {
|
|
|
+ if(dateValue != null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ ZonedDate zonedDate = parseToPolishDate(dateValue);
|
|
|
+ return timeValue != null ? zonedDate.withTime(parseToPolishTime(timeValue)) : zonedDate.withMidnight();
|
|
|
+ }
|
|
|
+
|
|
|
+ public static ZonedDateTime beginningOfDay(ZonedDateTime dateTime) {
|
|
|
+ return dateTime.with(LocalTime.MIDNIGHT);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static ZonedDateTime beginningOfDay(ZonedDate date) {
|
|
|
+ return date.withMax();
|
|
|
+ }
|
|
|
+
|
|
|
+ public static ZonedDateTime endOfDay(ZonedDateTime dateTime) {
|
|
|
+ return dateTime.with(LocalTime.MAX);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static boolean isSameDate(ZonedDateTime dateTime1, ZonedDateTime dateTime2) {
|
|
|
+ return dateTime1.truncatedTo(ChronoUnit.DAYS).isEqual(dateTime2.truncatedTo(ChronoUnit.DAYS));
|
|
|
+ }
|
|
|
+
|
|
|
+ public static boolean isMinTime(ZonedDateTime dateTime) {
|
|
|
+ return LocalTime.MIN.equals(dateTime.toLocalTime());
|
|
|
+ }
|
|
|
+
|
|
|
+ public static boolean isMaxTime(ZonedDateTime dateTime) {
|
|
|
+ return LocalTime.MAX.equals(dateTime.toLocalTime());
|
|
|
+ }
|
|
|
+
|
|
|
+ public static String extractTimeInPolishTimezone(ZonedDateTime dateTime) {
|
|
|
+ if (dateTime != null) {
|
|
|
+ return polishTime(dateTime).toLocalTime().format(TIME_FORMAT);
|
|
|
+ }
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+
|
|
|
+ public static ZonedDateTime lastDayOfMonth(ZonedDateTime date) {
|
|
|
+ return date
|
|
|
+ .withDayOfMonth(1)
|
|
|
+ .plusMonths(1)
|
|
|
+ .with(LocalTime.MIDNIGHT)
|
|
|
+ .minusDays(1);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static ZonedDateTime lastMinuteOfDay(ZonedDateTime date) {
|
|
|
+ return date.withHour(23).withMinute(59).withSecond(59);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static boolean isSaturday(ZonedDateTime day) {
|
|
|
+ return day.getDayOfWeek() == DayOfWeek.SATURDAY;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static boolean isSunday(ZonedDateTime day) {
|
|
|
+ return day.getDayOfWeek() == DayOfWeek.SUNDAY;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static boolean isHoliday(ZonedDateTime day) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static <T, R> R mapNullable(T value, Function<T, R> mapper) {
|
|
|
+ return Objects.isNull(value) ? null : mapper.apply(value);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static Duration timeDiff(LocalTime from, LocalTime to) {
|
|
|
+ if (from.isAfter(to)) {
|
|
|
+ return Duration.of(24, ChronoUnit.HOURS).minus(Duration.between(to, from));
|
|
|
+ }
|
|
|
+ return Duration.between(from, to);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static Duration timeDiff(ZonedDateTime from, ZonedDateTime to) {
|
|
|
+ if (from.isAfter(to)) {
|
|
|
+ return Duration.of(24, ChronoUnit.HOURS).minus(Duration.between(to, from));
|
|
|
+ }
|
|
|
+ return Duration.between(from, to);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static Duration timeDiff(ZonedTime from, ZonedTime to) {
|
|
|
+ if(!from.getZone().equals(to.getZone())) {
|
|
|
+ throw new IllegalArgumentException();
|
|
|
+ }
|
|
|
+ if (from.isAfter(to)) {
|
|
|
+ return Duration.of(24, ChronoUnit.HOURS).minus(Duration.between(to.getTimestamp(), from.getTimestamp()));
|
|
|
+ }
|
|
|
+ return Duration.between(from.getTimestamp(), to.getTimestamp());
|
|
|
+ }
|
|
|
+
|
|
|
+ public static ZonedDate literal(int y, int m, int d) {
|
|
|
+ return ZonedDate.from(literal(y, m, d, 0, 0, 0));
|
|
|
+ }
|
|
|
+
|
|
|
+ public static ZonedDateTime literal(int y, int m, int d, int H, int M) {
|
|
|
+ return literal(y, m, d, H, M, 0);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static ZonedDateTime literal(int y, int m, int d, int H, int M, int S) {
|
|
|
+ return LocalDateTime.of(y, m, d, H, M, S).atZone(ZONE_POLAND);
|
|
|
+ }
|
|
|
+}
|