package com.andegna.chrono; import java.io.Serializable; import java.time.DateTimeException; import java.time.LocalDate; import java.time.Period; import java.time.chrono.ChronoLocalDate; import java.time.chrono.ChronoPeriod; import java.time.temporal.ChronoField; import static java.time.temporal.ChronoField.DAY_OF_MONTH; import static java.time.temporal.ChronoField.ERA; import static java.time.temporal.ChronoField.MONTH_OF_YEAR; import static java.time.temporal.ChronoField.PROLEPTIC_MONTH; import java.time.temporal.Temporal; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalAmount; import java.time.temporal.TemporalField; import java.time.temporal.TemporalUnit; /** * * @author Sam As End */ public class EthiopianDate implements ChronoLocalDate, Serializable { private static final long serialVersionUID = 1L; /** * <b>NOW</b> * * @return */ public static EthiopianDate now() { return EthiopianChronology.INSTANCE.date(LocalDate.now()); } public static EthiopianDate from(TemporalAccessor temporal) { return EthiopianChronology.INSTANCE.date(temporal); } public static EthiopianDate of(int prolepticYear, int month, int dayOfMonthyear) { return EthiopianChronology.INSTANCE.date(prolepticYear, month, dayOfMonthyear); } public static EthiopianDate ofEpochDay(long epochDay) { return EthiopianChronology.INSTANCE.dateEpochDay(epochDay); } public static EthiopianDate ofYearDay(int prolepticYear, int dayOfYear) { return EthiopianChronology.INSTANCE.dateYearDay(prolepticYear, dayOfYear); } private final EthiopianEra era; private final int year; private final int month; private final int day; public EthiopianDate(EthiopianEra era, int year, int month, int day) { validate(year, month, day); this.era = era; this.year = year; this.month = month; this.day = day; } @Override public EthiopianChronology getChronology() { return EthiopianChronology.INSTANCE; } @Override public int lengthOfMonth() { if (month == 13) { if (this.isLeapYear()) { return 6; } else { return 5; } } return 30; } @Override public ChronoPeriod until(ChronoLocalDate endDateExclusive) { Period period = LocalDate.ofEpochDay(toEpochDay()).until(endDateExclusive); return getChronology().period(period.getYears(), period.getMonths(), period.getDays()); } @Override public long getLong(TemporalField field) { if (field instanceof ChronoField) { switch ((ChronoField) field) { case DAY_OF_MONTH: return day; case MONTH_OF_YEAR: return month; case YEAR_OF_ERA: return year; case YEAR: return era.equals(EthiopianEra.AMETE_ALEM) ? -1 * year : year; case ERA: return era.getValue(); case EPOCH_DAY: return getChronology().toGregorian(this).toEpochDay(); case DAY_OF_YEAR: return (month - 1) * 30 + day; case PROLEPTIC_MONTH: return year * 13 + month - 1; } return getChronology().toGregorian(this).getLong(field); } return field.getFrom(this); } @Override public int get(TemporalField field) { return (int) getLong(field); } @Override public long until(Temporal endExclusive, TemporalUnit unit) { return getChronology().toGregorian(this).until(endExclusive, unit); } @Override public EthiopianDate plus(TemporalAmount amount) { return getChronology().date( getChronology().toGregorian(this).plus(amount)); } @Override public EthiopianDate plus(long amountToAdd, TemporalUnit unit) { return getChronology().date( getChronology().toGregorian(this).plus(amountToAdd, unit)); } @Override public EthiopianDate minus(TemporalAmount amount) { return getChronology().date( getChronology().toGregorian(this).minus(amount)); } @Override public EthiopianDate minus(long amountToAdd, TemporalUnit unit) { return getChronology().date( getChronology().toGregorian(this).minus(amountToAdd, unit)); } int getYear() { return year; } int getMonth() { return month; } int getDay() { return day; } private void validate(int year, int month, int day) { if (1 > day || day > 30) { throw new DateTimeException("Invalid date '" + day + "'. Day must be between 1-30"); } else if (1 > month || month > 13) { throw new DateTimeException("Invalid month '" + month + "'. Month must be between 1-13"); } else if (month == 13 && day > 6) { throw new DateTimeException("Invalid date 'Ṗagume " + day + "' " + year); } else if (!getChronology().isLeapYear(year) && month == 13 && day > 5) { throw new DateTimeException("Invalid date 'Ṗagume 6' as '" + year + "' is not a leap year"); } } @Override public boolean equals(Object obj) { if (obj instanceof EthiopianDate) { return equals((EthiopianDate) obj); } return false; } @Override public int hashCode() { int hash = 21; hash = 97 * hash + this.year; hash = 97 * hash + this.month; hash = 97 * hash + this.day; return hash; } public boolean equals(EthiopianDate date) { return this.compareTo(date) == 0; } }