package jalaali import ( "fmt" "time" ) var ( breaks = [...]int{-61, 9, 38, 199, 426, 686, 756, 818, 1111, 1181, 1210, 1635, 2060, 2097, 2192, 2262, 2324, 2394, 2456, 3178} ) // ToJalaali converts Gregorian to Jalaali date. Error is not nil if Jalaali // year passed to function is not valid. func ToJalaali(gregorianYear int, gregorianMonth time.Month, gregorianDay int) (int, Month, int, error) { jy, jm, jd, err := d2j(g2d(gregorianYear, int(gregorianMonth), gregorianDay)) return jy, Month(jm), jd, err } // ToGregorian converts Jalaali to Gregorian date. Error is not nil if Jalaali // year passed to function is not valid. func ToGregorian(jalaaliYear int, jalaaliMonth Month, jalaaliDay int) (int, time.Month, int, error) { // validate the jalaali date using the utility function if !IsValidDate(jalaaliYear, int(jalaaliMonth), jalaaliDay) { return 0, 0, 0, fmt.Errorf("invalid jalaali date: year=%d, month=%d, day=%d", jalaaliYear, jalaaliMonth, jalaaliDay) } jdn, err := j2d(jalaaliYear, int(jalaaliMonth), jalaaliDay) if err != nil { return 0, 0, 0, err } gy, gm, gd := d2g(jdn) return gy, time.Month(gm), gd, nil } func j2d(jy, jm, jd int) (jdn int, err error) { _, gy, march, err := jalCal(jy) if err != nil { return 0, err } return g2d(gy, 3, march) + (jm-1)*31 - div(jm, 7)*(jm-7) + jd - 1, nil } func d2j(jdn int) (int, int, int, error) { gy, _, _ := d2g(jdn) // Calculate Gregorian year (gy). jy := gy - 621 leap, _, march, err := jalCal(jy) jdn1f := g2d(gy, 3, march) if err != nil { return 0, 0, 0, err } // Find number of days that passed since 1 Farvardin. k := jdn - jdn1f if k >= 0 { if k <= 185 { // The first 6 months. jm := 1 + div(k, 31) jd := mod(k, 31) + 1 return jy, jm, jd, nil } // The remaining months. k -= 186 } else { // Previous Jalaali year. jy-- k += 179 if leap == 1 { k++ } } jm := 7 + div(k, 30) jd := mod(k, 30) + 1 return jy, jm, jd, nil } func jalCal(jy int) (int, int, int, error) { bl, gy, leapJ, jp := len(breaks), jy+621, -14, breaks[0] jump := 0 if jy < jp || jy >= breaks[bl-1] { return 0, 0, 0, &ErrorInvalidYear{jy} } // Find the limiting years for the Jalaali year jy. for i := 1; i < bl; i++ { jm := breaks[i] jump = jm - jp if jy < jm { break } leapJ += div(jump, 33)*8 + div(mod(jump, 33), 4) jp = jm } n := jy - jp // Find the number of leap years from AD 621 to the beginning // of the current Jalaali year in the Persian calendar. leapJ += div(n, 33)*8 + div(mod(n, 33)+3, 4) if mod(jump, 33) == 4 && jump-n == 4 { leapJ++ } // And the same in the Gregorian calendar (until the year gy). leapG := div(gy, 4) - div((div(gy, 100)+1)*3, 4) - 150 // Determine the Gregorian date of Farvardin the 1st. march := 20 + leapJ - leapG // Find how many years have passed since the last leap year. if jump-n < 6 { n -= jump + div(jump+4, 33)*33 } leap := mod(mod(n+1, 33)-1, 4) if leap == -1 { leap = 4 } return leap, gy, march, nil } func g2d(gy, gm, gd int) int { d := div((gy+div(gm-8, 6)+100100)*1461, 4) + div(153*mod(gm+9, 12)+2, 5) + gd - 34840408 d = d - div(div(gy+100100+div(gm-8, 6), 100)*3, 4) + 752 return d } func d2g(jdn int) (int, int, int) { j := 4*jdn + 139361631 j = j + div(div(4*jdn+183187720, 146097)*3, 4)*4 - 3908 i := div(mod(j, 1461), 4)*5 + 308 gd := div(mod(i, 153), 5) + 1 gm := mod(div(i, 153), 12) + 1 gy := div(j, 1461) - 100100 + div(8-gm, 6) return gy, gm, gd } func div(a, b int) int { return a / b } func mod(a, b int) int { return a % b }