001package net.filebot.web; 002 003import static net.filebot.Logging.*; 004 005import java.io.Serializable; 006import java.time.Instant; 007import java.time.LocalDate; 008import java.time.ZoneOffset; 009import java.time.format.DateTimeFormatter; 010import java.util.Locale; 011import java.util.Objects; 012import java.util.regex.Matcher; 013import java.util.regex.Pattern; 014 015public class SimpleDate implements Serializable, Comparable<Object> { 016 017 protected int year; 018 protected int month; 019 protected int day; 020 021 public SimpleDate() { 022 // used by deserializer 023 } 024 025 public SimpleDate(int year, int month, int day) { 026 this.year = year; 027 this.month = month; 028 this.day = day; 029 } 030 031 public SimpleDate(LocalDate date) { 032 this.year = date.getYear(); 033 this.month = date.getMonthValue(); 034 this.day = date.getDayOfMonth(); 035 } 036 037 public SimpleDate(int year) { 038 this(year, 1, 1); 039 } 040 041 public int getYear() { 042 return year; 043 } 044 045 public int getMonth() { 046 return month; 047 } 048 049 public int getDay() { 050 return day; 051 } 052 053 @Override 054 public boolean equals(Object obj) { 055 if (obj instanceof SimpleDate) { 056 SimpleDate other = (SimpleDate) obj; 057 return year == other.year && month == other.month && day == other.day; 058 } else if (obj instanceof CharSequence) { 059 return toString().equals(obj.toString()); 060 } 061 return super.equals(obj); 062 } 063 064 @Override 065 public int compareTo(Object other) { 066 if (other instanceof SimpleDate) { 067 return compareTo((SimpleDate) other); 068 } else if (other instanceof CharSequence) { 069 SimpleDate otherDate = parse(other.toString()); 070 if (otherDate != null) { 071 return compareTo(otherDate); 072 } 073 } 074 throw new IllegalArgumentException(String.valueOf(other)); 075 } 076 077 public int compareTo(SimpleDate other) { 078 return toInstant().compareTo(other.toInstant()); 079 } 080 081 @Override 082 public int hashCode() { 083 return Objects.hash(year, month, day); 084 } 085 086 @Override 087 public SimpleDate clone() { 088 return new SimpleDate(year, month, day); 089 } 090 091 public String format(String pattern) { 092 return format(pattern, Locale.US); 093 } 094 095 public String format(String pattern, Locale locale) { 096 return DateTimeFormatter.ofPattern(pattern, locale).format(toLocalDate()); 097 } 098 099 public LocalDate toLocalDate() { 100 try { 101 return LocalDate.of(year, month, day); 102 } catch (Exception e) { 103 throw new IllegalStateException("Bad Date: " + this, e); 104 } 105 } 106 107 public Instant toInstant() { 108 return toLocalDate().atStartOfDay(ZoneOffset.UTC).toInstant(); 109 } 110 111 public long getTimeStamp() { 112 return toInstant().toEpochMilli(); 113 } 114 115 @Override 116 public String toString() { 117 return String.format(Locale.ROOT, "%04d-%02d-%02d", year, month, day); 118 } 119 120 public static SimpleDate now() { 121 return new SimpleDate(LocalDate.now()); 122 } 123 124 public static SimpleDate from(Instant instant) { 125 return instant == null ? null : new SimpleDate(instant.atOffset(ZoneOffset.UTC).toLocalDate()); 126 } 127 128 public static SimpleDate of(int year, int month, int day) { 129 return new SimpleDate(LocalDate.of(year, month, day)); 130 } 131 132 public static SimpleDate parse(String date) { 133 if (date == null || date.isEmpty()) { 134 return null; 135 } 136 137 Matcher m = DATE_FORMAT.matcher(date); 138 if (m.matches()) { 139 int year = Integer.parseInt(m.group(1)); 140 int month = Integer.parseInt(m.group(2)); 141 int day = Integer.parseInt(m.group(3)); 142 143 try { 144 return new SimpleDate(LocalDate.of(year, month, day)); 145 } catch (Exception e) { 146 debug.finest(message("Bad Date", date)); 147 } 148 } 149 150 return null; 151 } 152 153 public static final Pattern DATE_FORMAT = Pattern.compile("(\\d{4})\\D(\\d{1,2})\\D(\\d{1,2})"); 154 155}