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}