package org.mafagafogigante.dungeon.date;
import org.mafagafogigante.dungeon.logging.DungeonLogger;
import org.jetbrains.annotations.NotNull;
import java.io.Serializable;
/**
* Dungeon Date class. Stores an immutable time stamp.
*
* <p>Dungeon's date system has years of 10 months, months of 10 days and days of 24 hours of 60 minutes of 60 seconds.
* All the public constants made available by this class refer to this date system. Therefore they should not be used to
* represent or take place into calculations of real world time.
*/
public class Date implements Comparable<Date>, Serializable {
/**
* The time, in milliseconds.
*/
private long time; // Supports 1067519911 full years.
private Date(long millis) {
time = millis;
}
/**
* Constructs a date from the provided parameters.
*
* @param year the year, positive
* @param month the month, positive, smaller than or equal to the number of months in a year
* @param day the day, positive, smaller than or equal to the number of days in a month
* @param hour the hour, nonnegative, smaller than the number of hours in a day
* @param minute the minute, nonnegative, smaller than the number of minutes in an hour
* @param second the second, nonnegative, smaller than the number of seconds in a minute
*/
public Date(long year, long month, long day, long hour, long minute, long second) {
this(year, month, day);
if (hour < 0) {
DungeonLogger.warning("Tried to construct Date with negative hour.");
hour = 0;
} else if (hour >= DungeonTimeUnit.DAY.as(DungeonTimeUnit.HOUR)) {
DungeonLogger.warning("Tried to construct Date with nonexistent hour.");
// First hour of the next day. Even if the code supplied this, log a warning as this is likely a bug.
hour = DungeonTimeUnit.DAY.as(DungeonTimeUnit.HOUR);
}
if (minute < 0) {
DungeonLogger.warning("Tried to construct Date with negative minute.");
minute = 0;
} else if (minute >= DungeonTimeUnit.HOUR.as(DungeonTimeUnit.MINUTE)) {
DungeonLogger.warning("Tried to construct Date with nonexistent minute.");
// First minute of the next hour. Even if the code supplied this, log a warning as this is likely a bug.
minute = DungeonTimeUnit.HOUR.as(DungeonTimeUnit.MINUTE);
}
if (second < 0) {
DungeonLogger.warning("Tried to construct Date with negative second.");
second = 0;
} else if (second >= DungeonTimeUnit.MINUTE.as(DungeonTimeUnit.SECOND)) {
DungeonLogger.warning("Tried to construct Date with nonexistent second.");
// First second of the next minute. Even if the code supplied this, log a warning as this is likely a bug.
second = DungeonTimeUnit.MINUTE.as(DungeonTimeUnit.SECOND);
}
time += hour * DungeonTimeUnit.HOUR.milliseconds + minute * DungeonTimeUnit.MINUTE.milliseconds +
second * DungeonTimeUnit.SECOND.milliseconds;
}
/**
* Constructs a date from the provided parameters.
*
* @param year the year, positive
* @param month the month, positive, smaller than or equal to the number of months in a year
* @param day the day, positive, smaller than or equal to the number of days in a month
*/
public Date(long year, long month, long day) {
if (year <= 0) {
DungeonLogger.warning("Tried to construct Date with nonpositive year.");
year = 1;
}
if (month <= 0) {
DungeonLogger.warning("Tried to construct Date with nonpositive month.");
month = 1;
} else if (month > DungeonTimeUnit.YEAR.as(DungeonTimeUnit.MONTH)) {
DungeonLogger.warning("Tried to construct Date with nonexistent month.");
month = DungeonTimeUnit.YEAR.as(DungeonTimeUnit.MONTH);
}
if (day <= 0) {
DungeonLogger.warning("Tried to construct Date with nonpositive day.");
day = 1;
} else if (day > DungeonTimeUnit.MONTH.as(DungeonTimeUnit.DAY)) {
DungeonLogger.warning("Tried to construct Date with nonexistent day.");
day = DungeonTimeUnit.MONTH.as(DungeonTimeUnit.DAY);
}
time = DungeonTimeUnit.YEAR.milliseconds * (year - 1) + DungeonTimeUnit.MONTH.milliseconds * (month - 1) +
DungeonTimeUnit.DAY.milliseconds * (day - 1);
}
/**
* Returns the time since epoch in milliseconds.
*/
public long getTime() {
return time;
}
private long getSecond() {
return (time % DungeonTimeUnit.MINUTE.milliseconds) / DungeonTimeUnit.SECOND.milliseconds;
}
private long getMinute() {
return (time % DungeonTimeUnit.HOUR.milliseconds) / DungeonTimeUnit.MINUTE.milliseconds;
}
public long getHour() {
return (time % DungeonTimeUnit.DAY.milliseconds) / DungeonTimeUnit.HOUR.milliseconds;
}
public long getDay() {
return (time % DungeonTimeUnit.MONTH.milliseconds) / DungeonTimeUnit.DAY.milliseconds + 1;
}
public long getMonth() {
return (time % DungeonTimeUnit.YEAR.milliseconds) / DungeonTimeUnit.MONTH.milliseconds + 1;
}
public long getYear() {
return time / DungeonTimeUnit.YEAR.milliseconds + 1;
}
/**
* Returns a new Date object corresponding to this Date plus the specified amount of time.
*
* @param amount a positive integer
* @param unit a DungeonTimeUnit value, not null
* @return a new Date object
* @throws IllegalArgumentException if amount is not positive or if unit is null
*/
public Date plus(int amount, DungeonTimeUnit unit) {
if (amount <= 0) {
throw new IllegalArgumentException("amount must be positive.");
} else if (unit == null) {
throw new IllegalArgumentException("unit should not be null.");
} else {
return new Date(time + amount * unit.milliseconds);
}
}
/**
* Returns a new Date object corresponding to this Date minus the specified amount of time.
*
* @param amount a positive integer
* @param unit a DungeonTimeUnit value, not null
* @return a new Date object
* @throws IllegalArgumentException if amount is not positive or if unit is null
*/
public Date minus(int amount, DungeonTimeUnit unit) {
if (amount <= 0) {
throw new IllegalArgumentException("amount must be positive.");
} else if (unit == null) {
throw new IllegalArgumentException("unit should not be null.");
} else {
return new Date(time - amount * unit.milliseconds);
}
}
public String toDateString() {
return "day " + getDay() + " of month " + getMonth() + " of the year " + getYear();
}
public String toTimeString() {
return String.format("%02d:%02d:%02d", getHour(), getMinute(), getSecond());
}
@Override
public int compareTo(@NotNull Date date) {
if (time > date.time) {
return 1;
} else if (time == date.time) {
return 0;
} else {
return -1;
}
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Date date = (Date) o;
return time == date.time;
}
@Override
public int hashCode() {
return (int) (time ^ (time >>> 32));
}
/**
* Returns a String representation of this date, from year to second.
*
* @return a String
*/
@Override
public String toString() {
String format = "%d-%02d-%02d %02d:%02d:%02d";
return String.format(format, getYear(), getMonth(), getDay(), getHour(), getMinute(), getSecond());
}
}