/*
Реализация спецификаций CLDC версии 1.1 (JSR-139), MIDP версии 2.1 (JSR-118)
и других спецификаций для функционирования компактных приложений на языке
Java (мидлетов) в среде программного обеспечения Малик Эмулятор.
Copyright © 2016–2017, 2019–2023, 2025 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<https://www.gnu.org/licenses/>.
*/
package malik.emulator.time;
public abstract class CalendarSystem extends Object
{
public static final int MONDAY = 1;
public static final int TUESDAY = 2;
public static final int WEDNESDAY = 3;
public static final int THURSDAY = 4;
public static final int FRIDAY = 5;
public static final int SATURDAY = 6;
public static final int SUNDAY = 0;
public static final int JANUARY = 1;
public static final int FEBRUARY = 2;
public static final int MARCH = 3;
public static final int APRIL = 4;
public static final int MAY = 5;
public static final int JUNE = 6;
public static final int JULY = 7;
public static final int AUGUST = 8;
public static final int SEPTEMBER = 9;
public static final int OCTOBER = 10;
public static final int NOVEMBER = 11;
public static final int DECEMBER = 12;
static final byte[][] DAYS;
public static final CalendarSystem gregorian;
public static final CalendarSystem julian;
static {
DAYS = new byte[][] { { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } };
gregorian = new GregorianCalendarSystem();
julian = new JulianCalendarSystem();
}
protected CalendarSystem() {
}
public abstract boolean isLeapYear(int year);
public abstract int computeNumberOfDays(int year, int month);
public abstract int computeDayOfWeek(int year, int month, int day);
public abstract long computeFields(long time, int offset);
public abstract long computeTime(int year, int month, int day, int hour, int minute, int second, int millis, int offset);
public abstract long epochStart();
public int getYear(long fields) {
return (int) (fields >>> 48);
}
public int getMonth(long fields) {
return (int) (fields >>> 40) & 0xff;
}
public int getDay(long fields) {
return (int) (fields >>> 32) & 0xff;
}
public int getHour(long fields) {
return (int) (fields >>> 24) & 0xff;
}
public int getMinute(long fields) {
return (int) (fields >>> 16) & 0xff;
}
public int getSecond(long fields) {
return ((int) fields & 0xffff) / 1000;
}
public int getMillis(long fields) {
return ((int) fields & 0xffff) % 1000;
}
public long toFields(int year, int month, int day, int hour, int minute, int second, int millis) {
return (long) year << 48 | (long) (month & 0xff) << 40 | (long) (day & 0xff) << 32 | (long) (hour & 0xff) << 24 | (long) (minute & 0xff) << 16 | (long) ((second * 1000 + millis) & 0xffff);
}
public long computeTime(long fields, int offset) {
int millis = (int) fields & 0xffff;
return computeTime(
(int) (fields >>> 48), (int) (fields >> 40) & 0xff, (int) (fields >> 32) & 0xff, (int) (fields >> 24) & 0xff, (int) (fields >> 16) & 0xff, millis / 1000, millis % 1000, offset
);
}
public long setYear(long fields, int year) {
return fields & ~(0xffffL << 48) | (long) year << 48;
}
public long setMonth(long fields, int month) {
return fields & ~(0xffL << 40) | (long) (month & 0xff) << 40;
}
public long setDay(long fields, int day) {
return fields & ~(0xffL << 32) | (long) (day & 0xff) << 32;
}
public long setHour(long fields, int hour) {
return fields & ~(0xffL << 24) | (long) (hour & 0xff) << 24;
}
public long setMinute(long fields, int minute) {
return fields & ~(0xffL << 16) | (long) (minute & 0xff) << 16;
}
public long setSecond(long fields, int second) {
int millis = ((int) fields & 0xffff) % 1000;
return fields & ~0xffffL | (long) ((second * 1000 + millis) & 0xffff);
}
public long setMillis(long fields, int millis) {
int second = ((int) fields & 0xffff) / 1000;
return fields & ~0xffffL | (long) ((second * 1000 + millis) & 0xffff);
}
}
final class GregorianCalendarSystem extends CalendarSystem
{
private static final long EPOCH_START = 0x00003883122cd800L;
public GregorianCalendarSystem() {
}
public boolean isLeapYear(int year) {
if(year <= 0)
{
throw new IllegalArgumentException("CalendarSystem.isLeapYear: аргумент year может быть только положительным.");
}
return year % (year % 100 == 0 ? 400 : 4) == 0;
}
public int computeNumberOfDays(int year, int month) {
if(year <= 0)
{
throw new IllegalArgumentException("CalendarSystem.computeNumberOfDays: аргумент year может быть только положительным.");
}
if(month < 1 || month-- > 12)
{
throw new IllegalArgumentException("CalendarSystem.computeNumberOfDays: аргумент month может быть только от 1 до 12.");
}
return DAYS[isLeapYear(year) ? 1 : 0][month];
}
public int computeDayOfWeek(int year, int month, int day) {
if(year <= 0)
{
throw new IllegalArgumentException("CalendarSystem.computeDayOfWeek: аргумент year может быть только положительным.");
}
if(month < 1 || month > 12)
{
throw new IllegalArgumentException("CalendarSystem.computeDayOfWeek: аргумент month может быть только от 1 до 12.");
}
return (int) (((computeTime(year, month, day, 0, 0, 0, 0, 0) + EPOCH_START) / 86400000L) + 1L) % 7;
}
public long computeFields(long time, int offset) {
int year;
int month;
int day;
int hour;
int minute;
int millis;
int daysPerMonth;
long rem;
byte[] months;
hour = (int) ((rem = (time += EPOCH_START + (long) offset) % 86400000L) / 3600000L);
minute = (int) ((rem %= 3600000L) / 60000L);
millis = (int) (rem % 60000L);
year = (int) (((rem = time / 86400000L) / 146097L) * 400L);
if((rem %= 146097L) >= 146096L)
{
year += 399;
rem = 365L;
} else
{
year += (int) ((rem / 36524L) * 100L) + (int) (((rem %= 36524L) / 1461L) * 4L);
if((rem %= 1461L) >= 1460L)
{
year += 3;
rem = 365L;
} else
{
year += (int) (rem / 365L);
rem %= 365L;
}
}
months = DAYS[isLeapYear(++year) ? 1 : 0];
for(month = 0; rem >= (long) (daysPerMonth = months[month]); rem -= (long) daysPerMonth, month++);
month++;
day = (int) rem + 1;
return (long) year << 48 | (long) month << 40 | (long) day << 32 | (long) hour << 24 | (long) minute << 16 | (long) millis;
}
public long computeTime(int year, int month, int day, int hour, int minute, int second, int millis, int offset) {
int leap;
long result;
byte[] months;
if(year <= 0)
{
throw new IllegalArgumentException("CalendarSystem.computeTime: поле year может быть только положительным.");
}
if(month < 1 || month-- > 12)
{
throw new IllegalArgumentException("CalendarSystem.computeTime: поле month может быть только от 1 до 12.");
}
leap = isLeapYear(year--) ? 1 : 0;
result = -EPOCH_START + 12622780800000L * (long) (year / 400) + 3155673600000L * (long) ((year %= 400) / 100) + 126230400000L * (long) ((year %= 100) / 4) + 31536000000L * (long) (year % 4);
months = DAYS[leap];
for(int i = month; i-- > 0; result += 86400000L * (long) months[i]);
return result + 86400000L * (long) (day - 1) + 3600000L * (long) hour + 60000L * (long) minute + 1000L * (long) second + (long) millis - (long) offset;
}
public long epochStart() {
return EPOCH_START;
}
}
final class JulianCalendarSystem extends CalendarSystem
{
private static final long EPOCH_START = 0x000038831c799000L;
public JulianCalendarSystem() {
}
public boolean isLeapYear(int year) {
if(year <= 0)
{
throw new IllegalArgumentException("CalendarSystem.isLeapYear: аргумент year может быть только положительным.");
}
return year % 4 == 0;
}
public int computeNumberOfDays(int year, int month) {
if(year <= 0)
{
throw new IllegalArgumentException("CalendarSystem.computeNumberOfDays: аргумент year может быть только положительным.");
}
if(month < 1 || month-- > 12)
{
throw new IllegalArgumentException("CalendarSystem.computeNumberOfDays: аргумент month может быть только от 1 до 12.");
}
return DAYS[isLeapYear(year) ? 1 : 0][month];
}
public int computeDayOfWeek(int year, int month, int day) {
if(year <= 0)
{
throw new IllegalArgumentException("CalendarSystem.computeDayOfWeek: аргумент year может быть только положительным.");
}
if(month < 1 || month > 12)
{
throw new IllegalArgumentException("CalendarSystem.computeDayOfWeek: аргумент month может быть только от 1 до 12.");
}
return (int) (((computeTime(year, month, day, 0, 0, 0, 0, 0) + EPOCH_START) / 86400000L) + 6L) % 7;
}
public long computeFields(long time, int offset) {
int year;
int month;
int day;
int hour;
int minute;
int millis;
int daysPerMonth;
long rem;
byte[] months;
hour = (int) ((rem = (time += EPOCH_START + (long) offset) % 86400000L) / 3600000L);
minute = (int) ((rem %= 3600000L) / 60000L);
millis = (int) (rem % 60000L);
year = (int) (((rem = time / 86400000L) / 1461L) * 4L);
if((rem %= 1461L) >= 1460L)
{
year += 3;
rem = 365L;
} else
{
year += (int) (rem / 365L);
rem %= 365L;
}
months = DAYS[isLeapYear(++year) ? 1 : 0];
for(month = 0; rem >= (long) (daysPerMonth = months[month]); rem -= (long) daysPerMonth, month++);
month++;
day = (int) rem + 1;
return (long) year << 48 | (long) month << 40 | (long) day << 32 | (long) hour << 24 | (long) minute << 16 | (long) millis;
}
public long computeTime(int year, int month, int day, int hour, int minute, int second, int millis, int offset) {
int leap;
long result;
byte[] months;
if(year <= 0)
{
throw new IllegalArgumentException("CalendarSystem.computeTime: поле year может быть только положительным.");
}
if(month < 1 || month-- > 12)
{
throw new IllegalArgumentException("CalendarSystem.computeTime: поле month может быть только от 1 до 12.");
}
leap = isLeapYear(year--) ? 1 : 0;
result = -EPOCH_START + 126230400000L * (long) (year / 4) + 31536000000L * (long) (year % 4);
months = DAYS[leap];
for(int i = month; i-- > 0; result += 86400000L * (long) months[i]);
return result + 86400000L * (long) (day - 1) + 3600000L * (long) hour + 60000L * (long) minute + 1000L * (long) second + (long) millis - (long) offset;
}
public long epochStart() {
return EPOCH_START;
}
}