All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.svws_nrw.davapi.util.icalendar.DateTimeUtil Maven / Gradle / Ivy

Go to download

Diese Bibliothek enthält die Java-Server-Definition der CalDAV und CardDAV-Schnittstelle für die Schulverwaltungssoftware in NRW

The newest version!
package de.svws_nrw.davapi.util.icalendar;

import java.sql.Timestamp;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.TimeZone;

import de.svws_nrw.db.converter.current.DatumUhrzeitConverter;
import de.svws_nrw.db.dto.current.svws.dav.DTODavRessource;
import jakarta.validation.constraints.NotNull;

/**
 * Utility-Klasse zum Parsen und Konvertieren von Datums- und Zeitangaben im
 * Kontext von iCalendar-Einträgen.
 */
public final class DateTimeUtil {

	/** Formatter für DateTime nach ISO wie es in .ics-Dateien verwendet wird */
	private static final DateTimeFormatter DAV_ISO_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss");
	/**
	 * Formatter für DateTime nach ISO mit Zeitzone wie es in .ics-Dateien verwendet
	 * wird
	 */
	private static final DateTimeFormatter DAV_ISO_FORMATTER_WITHZONE = DateTimeFormatter
			.ofPattern("yyyyMMdd'T'HHmmssX");
	/**
	 * formatter für Dates nach RFC5545 Spezifikation wie es in .ics-Dateien
	 * verwendet wird
	 */
	private static final DateTimeFormatter DAV_DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyMMdd");
	/**
	 * Die Standardzeitzone
	 */
	public static final String TIMEZONE_DEFAULT = "Europe/Berlin";

	/**
	 * Utility Klasse, privater Konstruktor
	 */
	private DateTimeUtil() {
		throw new IllegalStateException("Utility class");
	}

	/**
	 * Utility-Methode zum parsen von CalDav-Zeitangaben im Format
	 * 20221102T104500 oder 20221102T104500Z
	 *
	 * @param input der Input-String aus einem .ics File
	 * @param zone  die Zeitzone in die der String geparst werden soll
	 * @return den geparsten Zeitpunkt
	 */
	public static Instant parseCalDav(final @NotNull String input, final @NotNull String zone) {
		ZoneId zoneId = null;
		if (ZoneId.getAvailableZoneIds().contains(zone)) {
			zoneId = ZoneId.of(zone);
		} else {
			// MS Outlook nutzt andere Zeitzonen-IDs, die von JodaTime nicht erkannt werden:
			// Potenzieller Fehler: “The datetime zone id ‘W. Europe Standard Time’ is not
			// recognised
			zoneId = TimeZone.getTimeZone(zone).toZoneId();
		}
		return LocalDateTime.parse(input, DAV_ISO_FORMATTER).atZone(zoneId).toInstant();
	}

	/**
	 * Utility-Methode zum parsen von CalDav-Zeitangaben im Format
	 * 20221102T104500 oder 20221102T104500Z. Zunächst
	 * wird versucht nach dem Format 20221102T104500Z zu parsen, wenn
	 * dies fehlschlägt, wird auf {@link #parseCalDav(String, String)}
	 * zurückgegriffen und als Zeitzone {@value #TIMEZONE_DEFAULT} genutzt
	 *
	 * @param input der Input-String aus einem .ics File
	 * @return den geparsten Zeitpunkt
	 */
	public static Instant parseCalDav(final @NotNull String input) {
		try {
			return ZonedDateTime.parse(input, DAV_ISO_FORMATTER_WITHZONE).toInstant();
		} catch (final DateTimeParseException dtpe) {
			// Ausdruck konnte nicht geparst werden, daher mit default zeitzone parsen
			return parseCalDav(input, TIMEZONE_DEFAULT);
		}
	}

	/**
	 * Utility-Methode zum parsen eines Zeitpunkts aus einem Property. Ist die
	 * Zeitzone im key gegeben, wird {@link #parseCalDav(String, String)} mit der
	 * Zeitzone genutzt, ansonsten {@link #parseCalDav(String)}
	 *
	 * @param property das Property aus dem der Zeitpunkt genutzt werden soll
	 * @return den geparsten Zeitpunkt
	 */
	public static Instant parseCalDav(final @NotNull IProperty property) {
		final String[] split = property.getKey().split(";");
		String zone = null;
		boolean isDate = false;
		for (final String s : split) {
			final int idx = s.indexOf("TZID=");
			if (idx >= 0) {
				zone = s.substring(idx + 5);
			}
			if (s.equalsIgnoreCase("VALUE=DATE")) {
				isDate = true;
			}
		}
		final String value = property.getValue() + (isDate ? "T000000" : "");
		if (zone != null) {
			return parseCalDav(value, zone);
		}
		return parseCalDav(value);
	}

	/**
	 * Konvertiert ein {@link Instant} zu einem SQL-Timestamp-String wie er am
	 * {@link DTODavRessource#KalenderStart} verwendet wird
	 *
	 * @param instant das Instant
	 * @return der String, der den Zeitpunkt repräsentiert
	 */
	public static String toSQLTimeStamp(final @NotNull Instant instant) {
		return DatumUhrzeitConverter.instance.convertToEntityAttribute(Timestamp.from(instant));
	}

	/**
	 * Konvertiert ein SQL-Timestamp String wie er an
	 * {@link DTODavRessource#KalenderStart} verwendet wird in ein {@link Instant}
* Diese Methode nutzt die Systemzeitzone zum Parsen! * * @param sql der String für den SQL-Timestamp * @return den Zeitpunkt aus dem SQLTimestamp */ public static Instant fromSqlTimeStamp(final @NotNull String sql) { return DatumUhrzeitConverter.instance.convertToDatabaseColumn(sql).toInstant(); } /** * Gibt wieder ob zwei Zeiträume überschneidend sind. Zeiträume überschneiden * sich, wenn es mindestens einen Zeitpunkt gibt, welcher in beiden Zeiträumen * enthalten ist. * * @param pRangeStart1 Startzeit des ersten Zeitraums * @param pRangeEnd1 Endzeit des ersten Zeitraums * @param pRangeStart2 Startzeit des zweiten Zeitraums * @param pRangeEnd2 Endzeit des zweiten Zeitraums * @return true, wenn die Zeiträume überlappen */ public static boolean intersect(final Instant pRangeStart1, final Instant pRangeEnd1, final Instant pRangeStart2, final Instant pRangeEnd2) { Instant rangeStart1 = pRangeStart1; Instant rangeStart2 = pRangeStart2; Instant rangeEnd1 = pRangeEnd1; Instant rangeEnd2 = pRangeEnd2; if (rangeStart1.compareTo(rangeEnd1) > 0) { final Instant buf = rangeStart1; rangeStart1 = rangeEnd1; rangeEnd1 = buf; } if (rangeStart2.compareTo(rangeEnd2) > 0) { final Instant buf = rangeStart2; rangeStart2 = rangeEnd2; rangeEnd2 = buf; } final boolean range1afterRange2 = rangeStart1.compareTo(rangeEnd2) > 0; final boolean range1beforeRange2 = rangeEnd1.compareTo(rangeStart2) < 0; return !range1afterRange2 && !range1beforeRange2; } /** * Gibt wieder, ob sich ein Zeitpunkt innerhalb eines Zeitraums befindet, * inklusive Start und Endzeitpunkt * * @param pRangeStart der Startzeitpunkt der Range * @param pRangeEnd der Endzeitpunkt der Range * @param instant der Zeitpunkt, der gegen den Zeitraum verglichen werden * soll * @return true, wenn instant gleich oder größer als der Start und gleich oder * kleiner als das Ende ist */ public static boolean between(final Instant pRangeStart, final Instant pRangeEnd, final Instant instant) { Instant rangeStart = pRangeStart; Instant rangeEnd = pRangeEnd; if (rangeStart.compareTo(rangeEnd) >= 0) { // Start und Endzeitpunkt vertauschen final Instant buf = rangeStart; rangeStart = rangeEnd; rangeEnd = buf; } return (instant.compareTo(pRangeStart) >= 0) && (instant.compareTo(pRangeEnd) <= 0); } /** * Gibt aus einem SQL-Timestamp-String die Millisekunden seit 1970 wieder, vgl. * {@link Timestamp#getTime()} * * @param time den SQL-Timestamp String wie er in * {@link DTODavRessource#KalenderStart} verwendet wird * @return die Millisekunden */ public static long getTimeInMillis(final String time) { return DatumUhrzeitConverter.instance.convertToDatabaseColumn(time).getTime(); } /** * Gibt einen CalDav String in Zulu-Timezone für den gegebenen Zeitpunkt wieder. * * @param t der gegebene Zeitpunkt * @return der CalDav String */ public static String toCalDavString(final Instant t) { return DAV_ISO_FORMATTER_WITHZONE.format(t.atZone(ZoneId.of("Z"))); } /** * Erzeugt einen CalDav String ohne Zeitzonenangabe, Zeit wird in die gegebene * Zeitzone gerechnet * * @param t der gegebene Zeitpunkt * @param tzid die Zeitzone, in die umgerechnet werden soll * @return das Datum als Zeichenkette für die Verwendung in CalDav */ public static String toCalDavString(final Instant t, final String tzid) { return DAV_ISO_FORMATTER.format(t.atZone(ZoneId.of(tzid))); } /** * Erzeugt aus einem Localdate ein .ics DateString im Format YYYYMMDD * * @param d das Datum, welches umgewandelt werden soll * @return den DateString zur Verwendung in .ics Daten */ public static String toCalDavDateString(final LocalDate d) { return DAV_DATE_FORMATTER.format(d); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy