001package org.gbif.api.vocabulary; 002 003import java.util.Optional; 004import java.util.regex.Matcher; 005import java.util.regex.Pattern; 006import lombok.AllArgsConstructor; 007import lombok.EqualsAndHashCode; 008import lombok.Getter; 009 010@Getter 011public enum DurationUnit { 012 SECONDS(0.0166667, "seconds", "second", "s", "sec", "secs"), 013 MINUTES(1, "minutes", "minute", "m", "min", "mins"), 014 HOURS(60, "hours", "hour", "h", "hr", "hrs"), 015 DAYS(1440, "days", "day", "d"), 016 WEEKS(10080, "weeks", "week", "wk", "wks"), 017 MONTHS(43800, "months", "month", "mo", "mos"), 018 YEARS(525600, "years", "year", "yr", "yrs", "y"); 019 020 public static final DurationUnit DEFAULT = MINUTES; 021 022 private final double durationInMinutes; 023 private final String[] names; 024 025 DurationUnit(double durationInMinutes, String... names) { 026 this.durationInMinutes = durationInMinutes; 027 this.names = names; 028 } 029 030 public static Optional<DurationUnit> parseDurationUnit(String duration) { 031 if (duration != null && !duration.isEmpty()) { 032 String normalizedDuration = duration.trim().toLowerCase(); 033 for (DurationUnit unit : DurationUnit.values()) { 034 for (String name : unit.getNames()) { 035 if (normalizedDuration.equals(name)) { 036 return Optional.of(unit); 037 } 038 } 039 } 040 } 041 return Optional.empty(); 042 } 043 044 @AllArgsConstructor 045 @Getter 046 @EqualsAndHashCode 047 public static class Duration { 048 049 private static final Pattern DURATION_PATTERN = 050 Pattern.compile("(\\d*\\.?\\d+)\\s*([a-zA-Z]*)"); 051 052 private final double value; 053 private final DurationUnit unit; 054 055 public static Optional<Duration> parse(String duration) { 056 if (duration != null && !duration.isEmpty()) { 057 Matcher matcher = DURATION_PATTERN.matcher(duration); 058 if (matcher.matches()) { 059 String rawUnit = matcher.group(2); 060 if (rawUnit != null && !rawUnit.isEmpty()) { 061 DurationUnit unit = DurationUnit.parseDurationUnit(matcher.group(2)).orElse(null); 062 063 if (unit == null) { 064 return Optional.empty(); 065 } 066 067 return Optional.of(new Duration(Double.parseDouble(matcher.group(1)), unit)); 068 } else { 069 return Optional.of(new Duration(Double.parseDouble(duration), DEFAULT)); 070 } 071 } 072 } 073 return Optional.empty(); 074 } 075 076 public double toMinutes() { 077 return value * unit.getDurationInMinutes(); 078 } 079 } 080}