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

com.metaeffekt.artifact.analysis.utils.TimeUtils Maven / Gradle / Ivy

There is a newer version: 0.132.0
Show newest version
/*
 * Copyright 2021-2024 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.metaeffekt.artifact.analysis.utils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

public abstract class TimeUtils {

    public static final DateTimeFormatter HUMAN_READABLE_TIMESTAMP_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd@HH'h'mm'm'ss's'");

    public static long parseHumanFormatTime(String time) {
        if (time == null) return -1;
        if (time.isEmpty() || time.equals("now")) {
            return TimeUtils.utcNow();
        }

        String[] parts = time.replace("ago", "").replace("last", "").split("(,|and)");
        long value = 0;
        boolean hadValidPart = false;

        for (String part : parts) {
            String[] split = part.trim().split(" ");
            if (split.length == 2) {
                long l = parseHumanFormatTime(split[0], split[1]);
                if (l > 0) {
                    value += l;
                    hadValidPart = true;
                }
            } else if (split.length == 1) {
                long l = parseHumanFormatTime("1", split[0]);
                if (l > 0) {
                    value += l;
                    hadValidPart = true;
                }
            }
        }

        if (!hadValidPart) {
            return -1;
        }
        return value;
    }

    private static long parseHumanFormatTime(String time, String unit) {
        time = time.replaceAll("[^0-9]", "");
        if (time.isEmpty()) {
            return -1;
        }
        int parsedTime = Integer.parseInt(time);

        if (unit.contains("year")) {
            return (long) parsedTime * 365 * 24 * 60 * 60 * 1000;
        } else if (unit.contains("month")) {
            return (long) parsedTime * 30 * 24 * 60 * 60 * 1000;
        } else if (unit.contains("week")) {
            return (long) parsedTime * 7 * 24 * 60 * 60 * 1000;
        } else if (unit.contains("day")) {
            return (long) parsedTime * 24 * 60 * 60 * 1000;
        } else if (unit.contains("hour")) {
            return (long) parsedTime * 60 * 60 * 1000;
        } else if (unit.contains("minute")) {
            return (long) parsedTime * 60 * 1000;
        } else if (unit.contains("second")) {
            return (long) parsedTime * 1000;
        }

        return -1;
    }

    public static long parseTimeFromInput(String input) {
        if (input == null) return 0;

        if (input.matches("[0-9]+")) {
            return Long.parseLong(input);
        }

        if (input.equals("now")) {
            return TimeUtils.utcNow();
        }

        long humanTime = TimeUtils.parseHumanFormatTime(input);
        if (humanTime != -1) {
            return TimeUtils.utcNow() - humanTime;
        }

        return TimeUtils.timestampFromNormalizedDate(TimeUtils.normalizeDate(input));
    }

    public static long timestampFromNormalizedDate(String date) {
        if (!date.contains("-")) {
            return 0;
        }

        final String[] dateTimeParts = date.split("[T ]");
        String datePart = dateTimeParts[0];
        final String timePart = dateTimeParts.length > 1 ? dateTimeParts[1] : "00:00:00";

        if (datePart.contains(" ")) {
            datePart = datePart.substring(0, datePart.indexOf(" "));
        }

        final String[] dateParts = datePart.split("-");
        final String[] timeParts = timePart.split(":");

        final GregorianCalendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
        calendar.set(
                Integer.parseInt(dateParts[0]),
                Integer.parseInt(dateParts[1]) - 1,
                Integer.parseInt(dateParts[2]),
                Integer.parseInt(timeParts[0]),
                Integer.parseInt(timeParts[1]),
                Integer.parseInt(timeParts[2])
        );

        calendar.set(Calendar.MILLISECOND, 0);

        return calendar.getTimeInMillis();
    }

    private final static List DATE_FORMATS = Arrays.asList(
            createUtcSimpleDateFormat("yyyy-MM-dd HH:mm:ss"),
            createUtcSimpleDateFormat("dd MMMMM yyyy", Locale.GERMAN), // cert-fr
            createUtcSimpleDateFormat("dd MMMMM yyyy", Locale.FRANCE),
            createUtcSimpleDateFormat("dd MMMMM yyyy", Locale.ENGLISH),
            createUtcSimpleDateFormat("dd MMMMM yyyy"),
            createUtcSimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ"),
            createUtcSimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy"), // java Date#toString() format

            createUtcSimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"),
            createUtcSimpleDateFormat("yyyy-MM-dd'T'HH:mm"),
            createUtcSimpleDateFormat("yyyy-MM-dd HH:mm"),

            createUtcSimpleDateFormat("dd-MM-yyyy'T'HH:mm:ss"),
            createUtcSimpleDateFormat("dd-MM-yyyy'T'HH:mm"),
            createUtcSimpleDateFormat("dd-MM-yyyy HH:mm:ss"),
            createUtcSimpleDateFormat("dd-MM-yyyy HH:mm"),

            createUtcSimpleDateFormat("MM-dd-yyyy'T'HH:mm:ss"),
            createUtcSimpleDateFormat("MM-dd-yyyy'T'HH:mm"),
            createUtcSimpleDateFormat("MM-dd-yyyy HH:mm:ss"),
            createUtcSimpleDateFormat("MM-dd-yyyy HH:mm"),

            createUtcSimpleDateFormat("MM/dd/yyyy'T'HH:mm:ss"),
            createUtcSimpleDateFormat("MM/dd/yyyy'T'HH:mm"),
            createUtcSimpleDateFormat("MM/dd/yyyy HH:mm:ss"),
            createUtcSimpleDateFormat("MM/dd/yyyy HH:mm"),

            createUtcSimpleDateFormat("dd/MM/yyyy'T'HH:mm:ss"),
            createUtcSimpleDateFormat("dd/MM/yyyy'T'HH:mm"),
            createUtcSimpleDateFormat("dd/MM/yyyy HH:mm:ss"),
            createUtcSimpleDateFormat("dd/MM/yyyy HH:mm"),

            createUtcSimpleDateFormat("yyyy/MM/dd'T'HH:mm:ss"),
            createUtcSimpleDateFormat("yyyy/MM/dd'T'HH:mm"),
            createUtcSimpleDateFormat("yyyy/MM/dd HH:mm:ss"),
            createUtcSimpleDateFormat("yyyy/MM/dd HH:mm"),

            createUtcSimpleDateFormat("yyyy-MM-dd"),
            createUtcSimpleDateFormat("yyyy-MM"),

            createUtcSimpleDateFormat("dd-MM-yyyy"),
            createUtcSimpleDateFormat("MM-dd-yyyy"),

            createUtcSimpleDateFormat("MM/dd/yyyy"),
            createUtcSimpleDateFormat("dd/MM/yyyy"),
            createUtcSimpleDateFormat("yyyy/MM/dd"),

            nonLenientUtcSimpleDateFormat("yyyy.MM.dd"),
            nonLenientUtcSimpleDateFormat("dd.MM.yyyy"),
            nonLenientUtcSimpleDateFormat("MM.dd.yyyy"),

            createUtcSimpleDateFormat("dd.MM.yyyy'T'HH:mm:ss"),
            createUtcSimpleDateFormat("dd.MM.yyyy'T'HH:mm"),
            createUtcSimpleDateFormat("dd.MM.yyyy HH:mm:ss"),
            createUtcSimpleDateFormat("dd.MM.yyyy HH:mm"),

            createUtcSimpleDateFormat("yyyy")
    );

    private static SimpleDateFormat nonLenientSimpleDateFormat(String pattern) {
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        sdf.setLenient(false);
        return sdf;
    }

    public static String normalizeDate(String string) {
        if (string == null) return "n.a.";

        Date parsedDate = tryParse(string);

        if (parsedDate != null) {
            return formatNormalizedDate(parsedDate);
        } else if (string.contains("T")) {
            return string.substring(0, string.indexOf("T"));
        }

        return string;
    }

    private final static SimpleDateFormat NORMALIZED_DATE_PATTERN = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    static {
        NORMALIZED_DATE_PATTERN.setTimeZone(TimeZone.getTimeZone("UTC"));
    }

    public static String formatNormalizedDate(Date date) {
        return NORMALIZED_DATE_PATTERN
                .format(date)
                .replace(" 00:00:00", "")
                .replaceAll(":00$", "");
    }

    public static String formatTimeDiff(long diff) {
        if (diff < 1000) {
            return diff + "ms";
        } else if (diff < 60 * 1000) {
            long s = diff / 1000;
            long ms = diff % 1000;
            return s + "s" + (ms == 0 ? "" : " " + ms + "ms");
        } else if (diff < 60 * 60 * 1000) {
            long m = diff / 1000 / 60;
            long s = diff / 1000 % 60;
            return m + "m" + (s == 0 ? "" : " " + s + "s");
        } else if (diff < 24 * 60 * 60 * 1000) {
            long h = diff / 1000 / 60 / 60;
            long m = diff / 1000 / 60 % 60;
            return h + "h" + (m == 0 ? "" : " " + m + "m");
        } else {
            long d = diff / 1000 / 60 / 60 / 24;
            long h = diff / 1000 / 60 / 60 % 24;
            return d + "d" + (h == 0 ? "" : " " + h + "h");
        }
    }

    public static Date tryParse(String dateString) {
        if (dateString == null) return null;

        if (dateString.matches("\\d+")) {
            return new Date(Long.parseLong(dateString));
        }

        synchronized (DATE_FORMATS) {
            for (SimpleDateFormat formatter : DATE_FORMATS) {
                try {
                    return formatter.parse(dateString);
                } catch (ParseException ignored) {
                }
            }
        }

        return null;
    }

    public static Date tryParse(Object date) {
        if (date instanceof Date) {
            return (Date) date;
        } else if (date instanceof Number) {
            return new Date(((Number) date).longValue());
        } else if (date instanceof String) {
            return tryParse((String) date);
        } else {
            return null;
        }
    }

    public static long utcNow() {
        return Instant.now().toEpochMilli();
    }


    public static String formatTimeUntilOrAgoDefault(long timeUntil) {
        return TimeUtils.formatTimeUntilOrAgo(timeUntil, "", "in", "ago", "", " and ", "no date provided");
    }


    public static String formatTimeNoSuffixPrefix(long timeUntil) {
        return TimeUtils.formatTimeUntilOrAgo(timeUntil, "", "", "", "", " and ", "no date provided");
    }

    public static String formatTimeUntilOrAgo(
            long timeUntil,
            String prefixBefore,
            String prefixAfter,
            String suffixBefore,
            String suffixAfter,
            String joinWord,
            String neverWord
    ) {
        String prefixUsed = timeUntil < 0 ? prefixBefore : prefixAfter;
        String suffixUsed = timeUntil < 0 ? suffixBefore : suffixAfter;

        prefixUsed = prefixUsed.isEmpty() ? "" : prefixUsed + " ";
        suffixUsed = suffixUsed.isEmpty() ? "" : " " + suffixUsed;

        final long absTime = Math.abs(timeUntil);
        if (timeUntil == Long.MAX_VALUE) {
            return neverWord;
        } else if (absTime < 1000 * 10) {
            return "now";
        }

        final String format = prefixUsed + "%d %s" + joinWord + "%d %s" + suffixUsed;
        final String formatZero = prefixUsed + "%d %s" + suffixUsed;

        final long years = absTime / (1000L * 60 * 60 * 24 * 365);
        final long months = absTime / (1000L * 60 * 60 * 24 * 30);
        final long weeks = absTime / (1000L * 60 * 60 * 24 * 7);
        final long days = absTime / (1000L * 60 * 60 * 24);
        final long hours = absTime / (1000L * 60 * 60);
        final long minutes = absTime / (1000L * 60);
        final long seconds = absTime / (1000L);

        if (years > 0) {
            return months % 12 == 0 ?
                    String.format(formatZero, years, (years > 1 ? "years" : "year")) :
                    String.format(format, years, (years > 1 ? "years" : "year"), months % 12, (months % 12 == 1 ? "month" : "months"));
        } else if (months > 0) {
            return weeks % 4 == 0 ?
                    String.format(formatZero, months, (months > 1 ? "months" : "month")) :
                    String.format(format, months, (months > 1 ? "months" : "month"), weeks % 4, (weeks % 4 == 1 ? "week" : "weeks"));
        } else if (weeks > 0) {
            return days % 7 == 0 ?
                    String.format(formatZero, weeks, (weeks > 1 ? "weeks" : "week")) :
                    String.format(format, weeks, (weeks > 1 ? "weeks" : "week"), days % 7, (days % 7 == 1 ? "day" : "days"));
        } else if (days > 0) {
            return hours % 24 == 0 ?
                    String.format(formatZero, days, (days > 1 ? "days" : "day")) :
                    String.format(format, days, (days > 1 ? "days" : "day"), hours % 24, (hours % 24 == 1 ? "hour" : "hours"));
        } else if (hours > 0) {
            return minutes % 60 == 0 ?
                    String.format(formatZero, hours, (hours > 1 ? "hours" : "hour")) :
                    String.format(format, hours, (hours > 1 ? "hours" : "hour"), minutes % 60, (minutes % 60 == 1 ? "minute" : "minutes"));
        } else if (minutes > 0) {
            return seconds % 60 == 0 ?
                    String.format(formatZero, minutes, (minutes > 1 ? "minutes" : "minute")) :
                    String.format(format, minutes, (minutes > 1 ? "minutes" : "minute"), seconds % 60, (seconds % 60 == 1 ? "second" : "seconds"));
        } else {
            return String.format(formatZero, seconds, "seconds");
        }
    }

    public static String createHumanReadableTimestamp() {
        return ZonedDateTime.now(ZoneOffset.UTC).format(HUMAN_READABLE_TIMESTAMP_FORMATTER);
    }

    private static SimpleDateFormat createUtcSimpleDateFormat(String pattern) {
        final SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
        return sdf;
    }

    private static SimpleDateFormat createUtcSimpleDateFormat(String pattern, Locale locale) {
        final SimpleDateFormat sdf = new SimpleDateFormat(pattern, locale);
        sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
        return sdf;
    }

    private static SimpleDateFormat nonLenientUtcSimpleDateFormat(String pattern) {
        final SimpleDateFormat sdf = createUtcSimpleDateFormat(pattern);
        sdf.setLenient(false);
        return sdf;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy