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
|
return 29
|
||||||
}
|
}
|
||||||
|
|
||||||
func gregorianToJalali(gy, gm, gd int) (int, int, int) {
|
// JDN for March 21, 622 CE (Jalali epoch: 1 Farvardin 1)
|
||||||
gdm := []int{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}
|
const jalaliEpochJDN = 1948320
|
||||||
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
|
|
||||||
|
|
||||||
jy := 979
|
func gregorianToJDN(gy, gm, gd int) int {
|
||||||
for {
|
a := (14 - gm) / 12
|
||||||
jyDays := 365
|
y := gy + 4800 - a
|
||||||
if isJalaliLeap(jy) {
|
m := gm + 12*a - 3
|
||||||
jyDays = 366
|
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
|
||||||
}
|
}
|
||||||
if gd2 < jyDays {
|
|
||||||
|
jy := 1
|
||||||
|
for {
|
||||||
|
yearDays := 365
|
||||||
|
if isJalaliLeap(jy) {
|
||||||
|
yearDays = 366
|
||||||
|
}
|
||||||
|
if days < yearDays {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
gd2 -= jyDays
|
days -= yearDays
|
||||||
jy++
|
jy++
|
||||||
}
|
}
|
||||||
|
|
||||||
jm := 1
|
jm := 1
|
||||||
for _, d := range jalaliMonthDays {
|
for mm := 0; mm < 12; mm++ {
|
||||||
if gd2 < d {
|
md := monthLenJalali(jy, mm+1)
|
||||||
|
if days < md {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
gd2 -= d
|
days -= md
|
||||||
jm++
|
jm++
|
||||||
}
|
}
|
||||||
return jy, jm, gd2 + 1
|
jd := days + 1
|
||||||
|
return jy, jm, jd
|
||||||
}
|
}
|
||||||
|
|
||||||
func jalaliToGregorian(jy, jm, jd int) (int, int, int) {
|
func jalaliToGregorian(jy, jm, jd int) (int, int, int) {
|
||||||
jy2 := jy - 979
|
days := 0
|
||||||
days := jy2 * 365
|
for y := 1; y < jy; y++ {
|
||||||
for y := 979; y < jy; y++ {
|
|
||||||
if isJalaliLeap(y) {
|
if isJalaliLeap(y) {
|
||||||
days++
|
days += 366
|
||||||
|
} else {
|
||||||
|
days += 365
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for m := 1; m < jm; m++ {
|
||||||
jdm := []int{0, 31, 62, 93, 124, 155, 186, 216, 246, 276, 306, 336}
|
days += monthLenJalali(jy, m)
|
||||||
days += jdm[jm-1] + jd - 1
|
|
||||||
days += 226899
|
|
||||||
|
|
||||||
gy := 1
|
|
||||||
for {
|
|
||||||
gyDays := 365
|
|
||||||
if isGregorianLeap(gy) {
|
|
||||||
gyDays = 366
|
|
||||||
}
|
}
|
||||||
if days < gyDays {
|
days += jd - 1
|
||||||
break
|
jdn := jalaliEpochJDN + days
|
||||||
}
|
return jdnToGregorian(jdn)
|
||||||
days -= gyDays
|
|
||||||
gy++
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func hijriToGregorian(hy, hm, hd int) (int, int, int) {
|
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) {
|
func gregorianToHijri(gy, gm, gd int) (int, int, int) {
|
||||||
a := (14 - gm) / 12
|
jdn := gregorianToJDN(gy, gm, gd)
|
||||||
y := gy + 4800 - a
|
|
||||||
m := gm + 12*a - 3
|
|
||||||
jdn := gd + (153*m+2)/5 + 365*y + y/4 - y/100 + y/400 - 32045
|
|
||||||
|
|
||||||
days := jdn - 1948440
|
days := jdn - 1948440
|
||||||
|
|
||||||
hy := 1
|
hy := 1
|
||||||
@@ -259,7 +252,6 @@ func buildCalendarMonth(cal string, year, month int) calMonth {
|
|||||||
totalDays = monthLenGreg(year, month)
|
totalDays = monthLenGreg(year, month)
|
||||||
|
|
||||||
dow := dayOfWeekGregorian(year, month, 1)
|
dow := dayOfWeekGregorian(year, month, 1)
|
||||||
// Convert Sunday=0 to Monday=0 alignment
|
|
||||||
startOffset := (dow + 6) % 7
|
startOffset := (dow + 6) % 7
|
||||||
|
|
||||||
var days []calDay
|
var days []calDay
|
||||||
|
|||||||
Reference in New Issue
Block a user