Skip to content

Commit

Permalink
Add months distance methods
Browse files Browse the repository at this point in the history
This makes the app free from months count assumption thus making it more flexible
for other kinds of calendars.
  • Loading branch information
ebraminio committed Oct 25, 2021
1 parent c696ea6 commit aa61452
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 3 deletions.
12 changes: 11 additions & 1 deletion src/main/java/io/github/persiancalendar/calendar/CivilDate.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* @author Amir
*/

public class CivilDate extends AbstractDate {
public class CivilDate extends AbstractDate implements YearMonthDate<CivilDate> {

public CivilDate(int year, int month, int dayOfMonth) {
super(year, month, dayOfMonth);
Expand Down Expand Up @@ -73,4 +73,14 @@ protected int[] fromJdn(long jdn) {
} else
return julianFromJdn(jdn);
}

@Override
public CivilDate monthStartOfMonthsDistance(int monthsDistance) {
return TwelveMonthsYear.monthStartOfMonthsDistance(this, monthsDistance, CivilDate::new);
}

@Override
public int monthsDistanceTo(CivilDate date) {
return TwelveMonthsYear.monthsDistanceTo(this, date);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* @author Amir
*/

public class IslamicDate extends AbstractDate {
public class IslamicDate extends AbstractDate implements YearMonthDate<IslamicDate> {

// Converters
public static boolean useUmmAlQura = false;
Expand Down Expand Up @@ -51,4 +51,14 @@ protected int[] fromJdn(long jdn) {

return result;
}

@Override
public IslamicDate monthStartOfMonthsDistance(int monthsDistance) {
return TwelveMonthsYear.monthStartOfMonthsDistance(this, monthsDistance, IslamicDate::new);
}

@Override
public int monthsDistanceTo(IslamicDate date) {
return TwelveMonthsYear.monthsDistanceTo(this, date);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import io.github.persiancalendar.calendar.persian.AlgorithmicConverter;
import io.github.persiancalendar.calendar.persian.LookupTableConverter;

public class PersianDate extends AbstractDate {
public class PersianDate extends AbstractDate implements YearMonthDate<PersianDate> {

public PersianDate(int year, int month, int dayOfMonth) {
super(year, month, dayOfMonth);
Expand All @@ -29,4 +29,14 @@ protected int[] fromJdn(long jdn) {
int[] result = LookupTableConverter.fromJdn(jdn);
return result == null ? AlgorithmicConverter.fromJdn(jdn) : result;
}

@Override
public PersianDate monthStartOfMonthsDistance(int monthsDistance) {
return TwelveMonthsYear.monthStartOfMonthsDistance(this, monthsDistance, PersianDate::new);
}

@Override
public int monthsDistanceTo(PersianDate date) {
return TwelveMonthsYear.monthsDistanceTo(this, date);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package io.github.persiancalendar.calendar;

interface YearMonthDate<T extends AbstractDate> {
// Ideally getYear()/getMonth()/getDay() also should be moved to this interface

T monthStartOfMonthsDistance(int monthsDistance);

int monthsDistanceTo(T date);

interface CreateDate<T extends AbstractDate> {
T createDate(int year, int month, int dayOfMonth);
}

class TwelveMonthsYear {
static <T extends AbstractDate> T monthStartOfMonthsDistance(
T baseDate, int monthsDistance, CreateDate<T> createDate
) {
int month = monthsDistance + baseDate.getMonth() - 1; // make it zero based for easier calculations
int year = baseDate.getYear() + month / 12;
month %= 12;
if (month < 0) {
year -= 1;
month += 12;
}
return createDate.createDate(year, month + 1, 1);
}

static <T extends AbstractDate> int monthsDistanceTo(T baseDate, T toDate) {
return (toDate.getYear() - baseDate.getYear()) * 12 + toDate.getMonth() - baseDate.getMonth();
}
}
}
31 changes: 31 additions & 0 deletions src/test/kotlin/io/github/persiancalendar/calendar/MainTests.kt
Original file line number Diff line number Diff line change
Expand Up @@ -179,4 +179,35 @@ class MainTests {
assertTrue(dayOfMonth == 1 || dayOfMonth == previousDayOfMonth + 1)
dayOfMonth
}.let {}

@Test
fun `Test month distance methods`() {
run {
val date = CivilDate(2014, 7, 7)
assertEquals(0, date.monthsDistanceTo(date))
assertEquals(-10, date.monthsDistanceTo(CivilDate(2013, 9, 5)))
assertEquals(30, date.monthsDistanceTo(CivilDate(2017, 1, 7)))
assertEquals(CivilDate(2013, 12, 1), date.monthStartOfMonthsDistance(-7))
assertEquals(CivilDate(2014, 6, 1), date.monthStartOfMonthsDistance(-1))
assertEquals(CivilDate(2014, 7, 1), date.monthStartOfMonthsDistance(0))
assertEquals(CivilDate(2014, 8, 1), date.monthStartOfMonthsDistance(1))
assertEquals(CivilDate(2015, 1, 1), date.monthStartOfMonthsDistance(6))
}

(-40..40).forEach {
val date = PersianDate(1318, 2, 5)
val dateWithDistance = date.monthStartOfMonthsDistance(it)
assertEquals(it, date.monthsDistanceTo(dateWithDistance))
}
(-40..40).forEach {
val date = CivilDate(2016, 7, 26)
val dateWithDistance = date.monthStartOfMonthsDistance(it)
assertEquals(it, date.monthsDistanceTo(dateWithDistance))
}
(-40..40).forEach {
val date = IslamicDate(1440, 7, 26)
val dateWithDistance = date.monthStartOfMonthsDistance(it)
assertEquals(it, date.monthsDistanceTo(dateWithDistance))
}
}
}

0 comments on commit aa61452

Please sign in to comment.