fix: correct Jalali calendar year conversion
Complete rewrite of gregorianToJalali and jalaliToGregorian using proper JDN arithmetic. Removed broken epoch offset (226899 / year 979) and replaced with jalaliEpochJDN = 1948320 (March 21, 622 CE). Verified: 2026-06-24 -> Jalali 1405-04-03 (correct) Nowruz 1405 verified as 2026-03-21
This commit is contained in:
@@ -59,78 +59,75 @@ func monthLenHijri(year, month int) int {
|
||||
return 29
|
||||
}
|
||||
|
||||
func gregorianToJalali(gy, gm, gd int) (int, int, int) {
|
||||
gdm := []int{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}
|
||||
gy2 := gy - 1
|
||||
gd2 := gdm[gm-1] + gd
|
||||
if gm > 2 && isGregorianLeap(gy) {
|
||||
gd2++
|
||||
}
|
||||
gd2 += gy2*365 + gy2/4 - gy2/100 + gy2/400
|
||||
gd2 -= 226899
|
||||
// JDN for March 21, 622 CE (Jalali epoch: 1 Farvardin 1)
|
||||
const jalaliEpochJDN = 1948320
|
||||
|
||||
jy := 979
|
||||
func gregorianToJDN(gy, gm, gd int) int {
|
||||
a := (14 - gm) / 12
|
||||
y := gy + 4800 - a
|
||||
m := gm + 12*a - 3
|
||||
return gd + (153*m+2)/5 + 365*y + y/4 - y/100 + y/400 - 32045
|
||||
}
|
||||
|
||||
func jdnToGregorian(jdn int) (int, int, int) {
|
||||
f := jdn + 1401 + ((4*jdn+274277)/146097)*3/4 - 38
|
||||
e := 4*f + 3
|
||||
g := (e % 1461) / 4
|
||||
h := 5*g + 2
|
||||
day := (h%153)/5 + 1
|
||||
month := ((h/153 + 2) % 12) + 1
|
||||
year := e/1461 - 4716 + (14-month)/12
|
||||
return year, month, day
|
||||
}
|
||||
|
||||
func gregorianToJalali(gy, gm, gd int) (int, int, int) {
|
||||
jdn := gregorianToJDN(gy, gm, gd)
|
||||
days := jdn - jalaliEpochJDN
|
||||
if days < 0 {
|
||||
return 0, 0, 0
|
||||
}
|
||||
|
||||
jy := 1
|
||||
for {
|
||||
jyDays := 365
|
||||
yearDays := 365
|
||||
if isJalaliLeap(jy) {
|
||||
jyDays = 366
|
||||
yearDays = 366
|
||||
}
|
||||
if gd2 < jyDays {
|
||||
if days < yearDays {
|
||||
break
|
||||
}
|
||||
gd2 -= jyDays
|
||||
days -= yearDays
|
||||
jy++
|
||||
}
|
||||
|
||||
jm := 1
|
||||
for _, d := range jalaliMonthDays {
|
||||
if gd2 < d {
|
||||
for mm := 0; mm < 12; mm++ {
|
||||
md := monthLenJalali(jy, mm+1)
|
||||
if days < md {
|
||||
break
|
||||
}
|
||||
gd2 -= d
|
||||
days -= md
|
||||
jm++
|
||||
}
|
||||
return jy, jm, gd2 + 1
|
||||
jd := days + 1
|
||||
return jy, jm, jd
|
||||
}
|
||||
|
||||
func jalaliToGregorian(jy, jm, jd int) (int, int, int) {
|
||||
jy2 := jy - 979
|
||||
days := jy2 * 365
|
||||
for y := 979; y < jy; y++ {
|
||||
days := 0
|
||||
for y := 1; y < jy; y++ {
|
||||
if isJalaliLeap(y) {
|
||||
days++
|
||||
days += 366
|
||||
} else {
|
||||
days += 365
|
||||
}
|
||||
}
|
||||
|
||||
jdm := []int{0, 31, 62, 93, 124, 155, 186, 216, 246, 276, 306, 336}
|
||||
days += jdm[jm-1] + jd - 1
|
||||
days += 226899
|
||||
|
||||
gy := 1
|
||||
for {
|
||||
gyDays := 365
|
||||
if isGregorianLeap(gy) {
|
||||
gyDays = 366
|
||||
}
|
||||
if days < gyDays {
|
||||
break
|
||||
}
|
||||
days -= gyDays
|
||||
gy++
|
||||
for m := 1; m < jm; m++ {
|
||||
days += monthLenJalali(jy, m)
|
||||
}
|
||||
|
||||
gm := 1
|
||||
for i, d := range gregMonthDays {
|
||||
if gm == 2 && isGregorianLeap(gy) {
|
||||
d = 29
|
||||
}
|
||||
if days < d {
|
||||
break
|
||||
}
|
||||
days -= d
|
||||
gm = i + 2
|
||||
}
|
||||
return gy, gm, days + 1
|
||||
days += jd - 1
|
||||
jdn := jalaliEpochJDN + days
|
||||
return jdnToGregorian(jdn)
|
||||
}
|
||||
|
||||
func hijriToGregorian(hy, hm, hd int) (int, int, int) {
|
||||
@@ -153,11 +150,7 @@ func hijriToGregorian(hy, hm, hd int) (int, int, int) {
|
||||
}
|
||||
|
||||
func gregorianToHijri(gy, gm, gd int) (int, int, int) {
|
||||
a := (14 - gm) / 12
|
||||
y := gy + 4800 - a
|
||||
m := gm + 12*a - 3
|
||||
jdn := gd + (153*m+2)/5 + 365*y + y/4 - y/100 + y/400 - 32045
|
||||
|
||||
jdn := gregorianToJDN(gy, gm, gd)
|
||||
days := jdn - 1948440
|
||||
|
||||
hy := 1
|
||||
@@ -259,7 +252,6 @@ func buildCalendarMonth(cal string, year, month int) calMonth {
|
||||
totalDays = monthLenGreg(year, month)
|
||||
|
||||
dow := dayOfWeekGregorian(year, month, 1)
|
||||
// Convert Sunday=0 to Monday=0 alignment
|
||||
startOffset := (dow + 6) % 7
|
||||
|
||||
var days []calDay
|
||||
|
||||
Reference in New Issue
Block a user