diff --git a/julian/julian.go b/julian/julian.go index d3e5d1d..78c8bd6 100644 --- a/julian/julian.go +++ b/julian/julian.go @@ -15,15 +15,22 @@ import "time" // need to give special care to dates before 15. October 1582. // The julian.Date type is meant to represent a date in the Julian calendar, -// and only in the Julian calendar, Gregorian dates are represented with the -// time.Time type. -type Date struct { +// and only in the Julian calendar. +type JDate struct { year int month time.Month day int } -func greaterOrEqual(a, b Date) bool { +// The julian.GDate type is meant to represent a date in the Gregorian +// calendar. +type GDate struct { + year int + month time.Month + day int +} + +func greaterOrEqual(a, b JDate) bool { if a.year != b.year { return a.year > b.year } else if a.month != b.month { @@ -33,6 +40,7 @@ func greaterOrEqual(a, b Date) bool { } } +// Specifically for returning the length of a given month in the julian calendar. func monthLength(year int, month time.Month) int { lengths := map[time.Month]int{ time.January: 31, @@ -57,9 +65,9 @@ func monthLength(year int, month time.Month) int { return 28 } -// The dateDiff function calculates the Julian date which falls the given +// The jDateDiff function calculates the Julian date which falls the given // number of dates before or after the given date. -func dateDiff(d Date, days int) Date { +func jDateDiff(d JDate, days int) JDate { // keep in mind throughout this code that the original "days" value can // be negative var fourYearPeriods int @@ -101,23 +109,28 @@ func nextMonth(year int, month time.Month) (int, time.Month) { } // The NewDate function creates a new Julian date -func NewDate(year int, month time.Month, day int) Date { +func NewJDate(year int, month time.Month, day int) JDate { // TODO: deal with users giving negative dates for day > monthLength(year, month) { day -= monthLength(year, month) year, month = nextMonth(year, month) } - return Date{year, month, day} + return JDate{year, month, day} } -// The function JDateToTime converts a given Julian date into a Gregorian date +// The NewGDateFromTime creates a new Gregorian date, given a time.Time object +func NewGDateFromTime(t time.Time) GDate { + return GDate{t.Year(), t.Month(), t.Day()} +} + +// The function JDateToGDate converts a given Julian date into a Gregorian date // represented with the time.Time type. // // The algorithm, in large part: follows this article: // https://en.wikipedia.org/wiki/Conversion_between_Julian_and_Gregorian_calendars -func JDateToTime(d Date) time.Time { +func JDateToGDate(d JDate) GDate { offset := -2 - borderDate := Date{100, time.March, 2} + borderDate := JDate{100, time.March, 2} // We don't increase the offset for years divisible by 400, ie. every // fourth loop, we keep track of that with skipYear, we can't simply // check borderDate.year % 400, because when we reach 31. December @@ -129,27 +142,27 @@ func JDateToTime(d Date) time.Time { // year y+100 borderDate.year += 100 if skipYear%4 != 0 { - borderDate = dateDiff(borderDate, -1) + borderDate = jDateDiff(borderDate, -1) offset++ } skipYear++ } - d = dateDiff(d, offset) - return time.Date(d.year, d.month, d.day, 0, 0, 0, 0, time.UTC) + d = jDateDiff(d, offset) + return GDate{d.year, d.month, d.day} } -// The function TimeToJDate converts a given Gregorian date into a Julian date. +// The function GDateToJDate converts a given Gregorian date into a Julian date. // // The algorithm, in large part: follows this article: // https://en.wikipedia.org/wiki/Conversion_between_Julian_and_Gregorian_calendars -func TimeToJDate(t time.Time) Date { +func GDateToJDate(g GDate) JDate { offset := -2 // The date when the offset changes in the gregorian calendar is always // 1st of March, so we can always just check the year, and see if we're // past 1st of March year - year := t.Year() - if t.Month() < time.March { + year := g.year + if g.month < time.March { year-- } @@ -161,7 +174,7 @@ func TimeToJDate(t time.Time) Date { borderYear += 100 } - d := Date{t.Year(), t.Month(), t.Day()} - d = dateDiff(d, -offset) + d := JDate{g.year, g.month, g.day} + d = jDateDiff(d, -offset) return d } diff --git a/julian/julian_test.go b/julian/julian_test.go index e60a38e..137dd01 100644 --- a/julian/julian_test.go +++ b/julian/julian_test.go @@ -38,21 +38,21 @@ func TestMonthLength(t *testing.T) { } } -func TestDateDiff(t *testing.T) { +func TestJDateDiff(t *testing.T) { var tests = []struct { - d Date + d JDate days int - want Date + want JDate }{ - {Date{2001, time.January, 20}, 5, Date{2001, time.January, 25}}, - {Date{2001, time.February, 28}, 5, Date{2001, time.March, 5}}, - {Date{2004, time.February, 28}, 5, Date{2004, time.March, 4}}, + {JDate{2001, time.January, 20}, 5, JDate{2001, time.January, 25}}, + {JDate{2001, time.February, 28}, 5, JDate{2001, time.March, 5}}, + {JDate{2004, time.February, 28}, 5, JDate{2004, time.March, 4}}, } for _, tt := range tests { testname := fmt.Sprintf("%v, %d", tt.d, tt.days) t.Run(testname, func(t *testing.T) { - ans := dateDiff(tt.d, tt.days) + ans := jDateDiff(tt.d, tt.days) if ans != tt.want { t.Errorf("got %d, want %d", ans, tt.want) } @@ -67,78 +67,75 @@ func TestNextMonth(t *testing.T) { } } -func TestJDateToTime(t *testing.T) { - gDate := func(year int, month time.Month, day int) time.Time { - return time.Date(year, month, day, 0, 0, 0, 0, time.UTC) - } +func TestJDateToGDate(t *testing.T) { var tests = []struct { - d Date - want time.Time + d JDate + want GDate }{ - {Date{100, time.February, 29}, gDate(100, time.February, 27)}, - {Date{100, time.March, 1}, gDate(100, time.February, 28)}, - {Date{100, time.March, 2}, gDate(100, time.March, 1)}, - {Date{200, time.February, 28}, gDate(200, time.February, 27)}, - {Date{200, time.February, 29}, gDate(200, time.February, 28)}, - {Date{200, time.March, 1}, gDate(200, time.March, 1)}, - {Date{300, time.February, 28}, gDate(300, time.February, 28)}, - {Date{300, time.February, 29}, gDate(300, time.March, 1)}, - {Date{300, time.March, 1}, gDate(300, time.March, 2)}, - {Date{500, time.February, 28}, gDate(500, time.March, 1)}, - {Date{500, time.February, 29}, gDate(500, time.March, 2)}, - {Date{500, time.March, 1}, gDate(500, time.March, 3)}, - {Date{600, time.February, 28}, gDate(600, time.March, 2)}, - {Date{600, time.February, 29}, gDate(600, time.March, 3)}, - {Date{600, time.March, 1}, gDate(600, time.March, 4)}, - {Date{700, time.February, 28}, gDate(700, time.March, 3)}, - {Date{700, time.February, 29}, gDate(700, time.March, 4)}, - {Date{700, time.March, 1}, gDate(700, time.March, 5)}, - {Date{900, time.February, 28}, gDate(900, time.March, 4)}, - {Date{900, time.February, 29}, gDate(900, time.March, 5)}, - {Date{900, time.March, 1}, gDate(900, time.March, 6)}, - {Date{1000, time.February, 28}, gDate(1000, time.March, 5)}, - {Date{1000, time.February, 29}, gDate(1000, time.March, 6)}, - {Date{1000, time.March, 1}, gDate(1000, time.March, 7)}, - {Date{1100, time.February, 28}, gDate(1100, time.March, 6)}, - {Date{1100, time.February, 29}, gDate(1100, time.March, 7)}, - {Date{1100, time.March, 1}, gDate(1100, time.March, 8)}, - {Date{1300, time.February, 28}, gDate(1300, time.March, 7)}, - {Date{1300, time.February, 29}, gDate(1300, time.March, 8)}, - {Date{1300, time.March, 1}, gDate(1300, time.March, 9)}, - {Date{1400, time.February, 28}, gDate(1400, time.March, 8)}, - {Date{1400, time.February, 29}, gDate(1400, time.March, 9)}, - {Date{1400, time.March, 1}, gDate(1400, time.March, 10)}, - {Date{1500, time.February, 28}, gDate(1500, time.March, 9)}, - {Date{1500, time.February, 29}, gDate(1500, time.March, 10)}, - {Date{1500, time.March, 1}, gDate(1500, time.March, 11)}, - {Date{1582, time.October, 4}, gDate(1582, time.October, 14)}, - {Date{1582, time.October, 5}, gDate(1582, time.October, 15)}, - {Date{1582, time.October, 6}, gDate(1582, time.October, 16)}, - {Date{1700, time.February, 18}, gDate(1700, time.February, 28)}, - {Date{1700, time.February, 19}, gDate(1700, time.March, 1)}, - {Date{1700, time.February, 28}, gDate(1700, time.March, 10)}, - {Date{1700, time.February, 29}, gDate(1700, time.March, 11)}, - {Date{1700, time.March, 1}, gDate(1700, time.March, 12)}, - {Date{1800, time.February, 17}, gDate(1800, time.February, 28)}, - {Date{1800, time.February, 18}, gDate(1800, time.March, 1)}, - {Date{1800, time.February, 28}, gDate(1800, time.March, 11)}, - {Date{1800, time.February, 29}, gDate(1800, time.March, 12)}, - {Date{1800, time.March, 1}, gDate(1800, time.March, 13)}, - {Date{1900, time.February, 16}, gDate(1900, time.February, 28)}, - {Date{1900, time.February, 17}, gDate(1900, time.March, 1)}, - {Date{1900, time.February, 28}, gDate(1900, time.March, 12)}, - {Date{1900, time.February, 29}, gDate(1900, time.March, 13)}, - {Date{1900, time.March, 1}, gDate(1900, time.March, 14)}, - {Date{2100, time.February, 15}, gDate(2100, time.February, 28)}, - {Date{2100, time.February, 16}, gDate(2100, time.March, 1)}, - {Date{2100, time.February, 28}, gDate(2100, time.March, 13)}, - {Date{2100, time.February, 29}, gDate(2100, time.March, 14)}, + {JDate{100, time.February, 29}, GDate{100, time.February, 27}}, + {JDate{100, time.March, 1}, GDate{100, time.February, 28}}, + {JDate{100, time.March, 2}, GDate{100, time.March, 1}}, + {JDate{200, time.February, 28}, GDate{200, time.February, 27}}, + {JDate{200, time.February, 29}, GDate{200, time.February, 28}}, + {JDate{200, time.March, 1}, GDate{200, time.March, 1}}, + {JDate{300, time.February, 28}, GDate{300, time.February, 28}}, + {JDate{300, time.February, 29}, GDate{300, time.March, 1}}, + {JDate{300, time.March, 1}, GDate{300, time.March, 2}}, + {JDate{500, time.February, 28}, GDate{500, time.March, 1}}, + {JDate{500, time.February, 29}, GDate{500, time.March, 2}}, + {JDate{500, time.March, 1}, GDate{500, time.March, 3}}, + {JDate{600, time.February, 28}, GDate{600, time.March, 2}}, + {JDate{600, time.February, 29}, GDate{600, time.March, 3}}, + {JDate{600, time.March, 1}, GDate{600, time.March, 4}}, + {JDate{700, time.February, 28}, GDate{700, time.March, 3}}, + {JDate{700, time.February, 29}, GDate{700, time.March, 4}}, + {JDate{700, time.March, 1}, GDate{700, time.March, 5}}, + {JDate{900, time.February, 28}, GDate{900, time.March, 4}}, + {JDate{900, time.February, 29}, GDate{900, time.March, 5}}, + {JDate{900, time.March, 1}, GDate{900, time.March, 6}}, + {JDate{1000, time.February, 28}, GDate{1000, time.March, 5}}, + {JDate{1000, time.February, 29}, GDate{1000, time.March, 6}}, + {JDate{1000, time.March, 1}, GDate{1000, time.March, 7}}, + {JDate{1100, time.February, 28}, GDate{1100, time.March, 6}}, + {JDate{1100, time.February, 29}, GDate{1100, time.March, 7}}, + {JDate{1100, time.March, 1}, GDate{1100, time.March, 8}}, + {JDate{1300, time.February, 28}, GDate{1300, time.March, 7}}, + {JDate{1300, time.February, 29}, GDate{1300, time.March, 8}}, + {JDate{1300, time.March, 1}, GDate{1300, time.March, 9}}, + {JDate{1400, time.February, 28}, GDate{1400, time.March, 8}}, + {JDate{1400, time.February, 29}, GDate{1400, time.March, 9}}, + {JDate{1400, time.March, 1}, GDate{1400, time.March, 10}}, + {JDate{1500, time.February, 28}, GDate{1500, time.March, 9}}, + {JDate{1500, time.February, 29}, GDate{1500, time.March, 10}}, + {JDate{1500, time.March, 1}, GDate{1500, time.March, 11}}, + {JDate{1582, time.October, 4}, GDate{1582, time.October, 14}}, + {JDate{1582, time.October, 5}, GDate{1582, time.October, 15}}, + {JDate{1582, time.October, 6}, GDate{1582, time.October, 16}}, + {JDate{1700, time.February, 18}, GDate{1700, time.February, 28}}, + {JDate{1700, time.February, 19}, GDate{1700, time.March, 1}}, + {JDate{1700, time.February, 28}, GDate{1700, time.March, 10}}, + {JDate{1700, time.February, 29}, GDate{1700, time.March, 11}}, + {JDate{1700, time.March, 1}, GDate{1700, time.March, 12}}, + {JDate{1800, time.February, 17}, GDate{1800, time.February, 28}}, + {JDate{1800, time.February, 18}, GDate{1800, time.March, 1}}, + {JDate{1800, time.February, 28}, GDate{1800, time.March, 11}}, + {JDate{1800, time.February, 29}, GDate{1800, time.March, 12}}, + {JDate{1800, time.March, 1}, GDate{1800, time.March, 13}}, + {JDate{1900, time.February, 16}, GDate{1900, time.February, 28}}, + {JDate{1900, time.February, 17}, GDate{1900, time.March, 1}}, + {JDate{1900, time.February, 28}, GDate{1900, time.March, 12}}, + {JDate{1900, time.February, 29}, GDate{1900, time.March, 13}}, + {JDate{1900, time.March, 1}, GDate{1900, time.March, 14}}, + {JDate{2100, time.February, 15}, GDate{2100, time.February, 28}}, + {JDate{2100, time.February, 16}, GDate{2100, time.March, 1}}, + {JDate{2100, time.February, 28}, GDate{2100, time.March, 13}}, + {JDate{2100, time.February, 29}, GDate{2100, time.March, 14}}, } for _, tt := range tests { testname := fmt.Sprintf("%v, %v", tt.d, tt.want) t.Run(testname, func(t *testing.T) { - ans := JDateToTime(tt.d) + ans := JDateToGDate(tt.d) if ans != tt.want { t.Errorf("got %v, want %v", ans, tt.want) } @@ -146,78 +143,75 @@ func TestJDateToTime(t *testing.T) { } } -func TestTimeToJDate(t *testing.T) { - gDate := func(year int, month time.Month, day int) time.Time { - return time.Date(year, month, day, 0, 0, 0, 0, time.UTC) - } +func TestGDateToJDate(t *testing.T) { var tests = []struct { - gd time.Time - want Date + gd GDate + want JDate }{ - {gDate(100, time.February, 27), Date{100, time.February, 29}}, - {gDate(100, time.February, 28), Date{100, time.March, 1}}, - {gDate(100, time.March, 1), Date{100, time.March, 2}}, - {gDate(200, time.February, 27), Date{200, time.February, 28}}, - {gDate(200, time.February, 28), Date{200, time.February, 29}}, - {gDate(200, time.March, 1), Date{200, time.March, 1}}, - {gDate(300, time.February, 28), Date{300, time.February, 28}}, - {gDate(300, time.March, 1), Date{300, time.February, 29}}, - {gDate(300, time.March, 2), Date{300, time.March, 1}}, - {gDate(500, time.March, 1), Date{500, time.February, 28}}, - {gDate(500, time.March, 2), Date{500, time.February, 29}}, - {gDate(500, time.March, 3), Date{500, time.March, 1}}, - {gDate(600, time.March, 2), Date{600, time.February, 28}}, - {gDate(600, time.March, 3), Date{600, time.February, 29}}, - {gDate(600, time.March, 4), Date{600, time.March, 1}}, - {gDate(700, time.March, 3), Date{700, time.February, 28}}, - {gDate(700, time.March, 4), Date{700, time.February, 29}}, - {gDate(700, time.March, 5), Date{700, time.March, 1}}, - {gDate(900, time.March, 4), Date{900, time.February, 28}}, - {gDate(900, time.March, 5), Date{900, time.February, 29}}, - {gDate(900, time.March, 6), Date{900, time.March, 1}}, - {gDate(1000, time.March, 5), Date{1000, time.February, 28}}, - {gDate(1000, time.March, 6), Date{1000, time.February, 29}}, - {gDate(1000, time.March, 7), Date{1000, time.March, 1}}, - {gDate(1100, time.March, 6), Date{1100, time.February, 28}}, - {gDate(1100, time.March, 7), Date{1100, time.February, 29}}, - {gDate(1100, time.March, 8), Date{1100, time.March, 1}}, - {gDate(1300, time.March, 7), Date{1300, time.February, 28}}, - {gDate(1300, time.March, 8), Date{1300, time.February, 29}}, - {gDate(1300, time.March, 9), Date{1300, time.March, 1}}, - {gDate(1400, time.March, 8), Date{1400, time.February, 28}}, - {gDate(1400, time.March, 9), Date{1400, time.February, 29}}, - {gDate(1400, time.March, 10), Date{1400, time.March, 1}}, - {gDate(1500, time.March, 9), Date{1500, time.February, 28}}, - {gDate(1500, time.March, 10), Date{1500, time.February, 29}}, - {gDate(1500, time.March, 11), Date{1500, time.March, 1}}, - {gDate(1582, time.October, 14), Date{1582, time.October, 4}}, - {gDate(1582, time.October, 15), Date{1582, time.October, 5}}, - {gDate(1582, time.October, 16), Date{1582, time.October, 6}}, - {gDate(1700, time.February, 28), Date{1700, time.February, 18}}, - {gDate(1700, time.March, 1), Date{1700, time.February, 19}}, - {gDate(1700, time.March, 10), Date{1700, time.February, 28}}, - {gDate(1700, time.March, 11), Date{1700, time.February, 29}}, - {gDate(1700, time.March, 12), Date{1700, time.March, 1}}, - {gDate(1800, time.February, 28), Date{1800, time.February, 17}}, - {gDate(1800, time.March, 1), Date{1800, time.February, 18}}, - {gDate(1800, time.March, 11), Date{1800, time.February, 28}}, - {gDate(1800, time.March, 12), Date{1800, time.February, 29}}, - {gDate(1800, time.March, 13), Date{1800, time.March, 1}}, - {gDate(1900, time.February, 28), Date{1900, time.February, 16}}, - {gDate(1900, time.March, 1), Date{1900, time.February, 17}}, - {gDate(1900, time.March, 12), Date{1900, time.February, 28}}, - {gDate(1900, time.March, 13), Date{1900, time.February, 29}}, - {gDate(1900, time.March, 14), Date{1900, time.March, 1}}, - {gDate(2100, time.February, 28), Date{2100, time.February, 15}}, - {gDate(2100, time.March, 1), Date{2100, time.February, 16}}, - {gDate(2100, time.March, 13), Date{2100, time.February, 28}}, - {gDate(2100, time.March, 14), Date{2100, time.February, 29}}, + {GDate{100, time.February, 27}, JDate{100, time.February, 29}}, + {GDate{100, time.February, 28}, JDate{100, time.March, 1}}, + {GDate{100, time.March, 1}, JDate{100, time.March, 2}}, + {GDate{200, time.February, 27}, JDate{200, time.February, 28}}, + {GDate{200, time.February, 28}, JDate{200, time.February, 29}}, + {GDate{200, time.March, 1}, JDate{200, time.March, 1}}, + {GDate{300, time.February, 28}, JDate{300, time.February, 28}}, + {GDate{300, time.March, 1}, JDate{300, time.February, 29}}, + {GDate{300, time.March, 2}, JDate{300, time.March, 1}}, + {GDate{500, time.March, 1}, JDate{500, time.February, 28}}, + {GDate{500, time.March, 2}, JDate{500, time.February, 29}}, + {GDate{500, time.March, 3}, JDate{500, time.March, 1}}, + {GDate{600, time.March, 2}, JDate{600, time.February, 28}}, + {GDate{600, time.March, 3}, JDate{600, time.February, 29}}, + {GDate{600, time.March, 4}, JDate{600, time.March, 1}}, + {GDate{700, time.March, 3}, JDate{700, time.February, 28}}, + {GDate{700, time.March, 4}, JDate{700, time.February, 29}}, + {GDate{700, time.March, 5}, JDate{700, time.March, 1}}, + {GDate{900, time.March, 4}, JDate{900, time.February, 28}}, + {GDate{900, time.March, 5}, JDate{900, time.February, 29}}, + {GDate{900, time.March, 6}, JDate{900, time.March, 1}}, + {GDate{1000, time.March, 5}, JDate{1000, time.February, 28}}, + {GDate{1000, time.March, 6}, JDate{1000, time.February, 29}}, + {GDate{1000, time.March, 7}, JDate{1000, time.March, 1}}, + {GDate{1100, time.March, 6}, JDate{1100, time.February, 28}}, + {GDate{1100, time.March, 7}, JDate{1100, time.February, 29}}, + {GDate{1100, time.March, 8}, JDate{1100, time.March, 1}}, + {GDate{1300, time.March, 7}, JDate{1300, time.February, 28}}, + {GDate{1300, time.March, 8}, JDate{1300, time.February, 29}}, + {GDate{1300, time.March, 9}, JDate{1300, time.March, 1}}, + {GDate{1400, time.March, 8}, JDate{1400, time.February, 28}}, + {GDate{1400, time.March, 9}, JDate{1400, time.February, 29}}, + {GDate{1400, time.March, 10}, JDate{1400, time.March, 1}}, + {GDate{1500, time.March, 9}, JDate{1500, time.February, 28}}, + {GDate{1500, time.March, 10}, JDate{1500, time.February, 29}}, + {GDate{1500, time.March, 11}, JDate{1500, time.March, 1}}, + {GDate{1582, time.October, 14}, JDate{1582, time.October, 4}}, + {GDate{1582, time.October, 15}, JDate{1582, time.October, 5}}, + {GDate{1582, time.October, 16}, JDate{1582, time.October, 6}}, + {GDate{1700, time.February, 28}, JDate{1700, time.February, 18}}, + {GDate{1700, time.March, 1}, JDate{1700, time.February, 19}}, + {GDate{1700, time.March, 10}, JDate{1700, time.February, 28}}, + {GDate{1700, time.March, 11}, JDate{1700, time.February, 29}}, + {GDate{1700, time.March, 12}, JDate{1700, time.March, 1}}, + {GDate{1800, time.February, 28}, JDate{1800, time.February, 17}}, + {GDate{1800, time.March, 1}, JDate{1800, time.February, 18}}, + {GDate{1800, time.March, 11}, JDate{1800, time.February, 28}}, + {GDate{1800, time.March, 12}, JDate{1800, time.February, 29}}, + {GDate{1800, time.March, 13}, JDate{1800, time.March, 1}}, + {GDate{1900, time.February, 28}, JDate{1900, time.February, 16}}, + {GDate{1900, time.March, 1}, JDate{1900, time.February, 17}}, + {GDate{1900, time.March, 12}, JDate{1900, time.February, 28}}, + {GDate{1900, time.March, 13}, JDate{1900, time.February, 29}}, + {GDate{1900, time.March, 14}, JDate{1900, time.March, 1}}, + {GDate{2100, time.February, 28}, JDate{2100, time.February, 15}}, + {GDate{2100, time.March, 1}, JDate{2100, time.February, 16}}, + {GDate{2100, time.March, 13}, JDate{2100, time.February, 28}}, + {GDate{2100, time.March, 14}, JDate{2100, time.February, 29}}, } for _, tt := range tests { testname := fmt.Sprintf("%v, %v", tt.gd, tt.want) t.Run(testname, func(t *testing.T) { - ans := TimeToJDate(tt.gd) + ans := GDateToJDate(tt.gd) if ans != tt.want { t.Errorf("got %v, want %v", ans, tt.want) }