-- | Functions for working with Jalaali calendar systems.
-- This library mimics the API of "Data.Time.Calendar.Gregorian".
module Data.Time.Calendar.Jalaali
  ( isJalaaliLeapYear
  , toJalaali
  , fromJalaali
  , fromJalaaliValid
  , jalaaliMonthLength
  , showJalaali
  , addJalaaliMonthsClip
  , addJalaaliMonthsRollOver
  , addJalaaliYearsClip
  , addJalaaliYearsRollOver
  , addJalaaliDurationClip
  , addJalaaliDurationRollOver
  ) where


import Data.List (foldl')
import Data.Time.Calendar
  (Day, CalendarDiffDays(CalendarDiffDays), addDays, fromGregorian, toGregorian)


-- | Convert to Jalaali calendar. First element of result is year, second month
-- number (1-12), third day (1-31).
toJalaali :: Day -> (Integer, Int, Int)
toJalaali :: Day -> (Integer, Int, Int)
toJalaali Day
d = (Int -> Integer
forall a. Integral a => a -> Integer
toInteger Int
jy, Int
jm, Int
jd)
  where
    (Integer
gy, Int
gm, Int
gd) = Day -> (Integer, Int, Int)
toGregorian Day
d
    (Int
jy, Int
jm, Int
jd) = Int -> (Int, Int, Int)
d2j (Int -> (Int, Int, Int)) -> Int -> (Int, Int, Int)
forall a b. (a -> b) -> a -> b
$ Int -> Int -> Int -> Int
g2d (Integer -> Int
forall a. Num a => Integer -> a
fromInteger Integer
gy) Int
gm Int
gd


-- | Convert from Jalaali calendar. First argument is year, second month
-- number (1-12), third day (1-31). Invalid values will be clipped to the
-- correct range, month first, then day.
fromJalaali :: Integer -> Int -> Int -> Day
fromJalaali :: Integer -> Int -> Int -> Day
fromJalaali Integer
jy Int
jm Int
jd = Integer -> Int -> Int -> Day
fromGregorian (Int -> Integer
forall a. Integral a => a -> Integer
toInteger Int
gy) Int
gm Int
gd
  where
    jmv :: Int
jmv = Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
1 (Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
12 Int
jm)
    jdv :: Int
jdv = Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
1 (Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
31 Int
jd)
    jdv2 :: Int
jdv2 = Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
jdv (Integer -> Int -> Int
jalaaliMonthLength Integer
jy Int
jmv)
    (Int
gy, Int
gm, Int
gd) = Int -> (Int, Int, Int)
d2g (Int -> (Int, Int, Int)) -> Int -> (Int, Int, Int)
forall a b. (a -> b) -> a -> b
$ Int -> Int -> Int -> Int
j2d (Integer -> Int
forall a. Num a => Integer -> a
fromInteger Integer
jy) Int
jmv Int
jdv2


-- | Convert from Jalaali calendar. First argument is year, second month
-- number (1-12), third day (1-31). Invalid values will return Nothing.
fromJalaaliValid :: Integer -> Int -> Int -> Maybe Day
fromJalaaliValid :: Integer -> Int -> Int -> Maybe Day
fromJalaaliValid Integer
jy Int
jm Int
jd
  | Integer
jy Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
< (-Integer
61) = Maybe Day
forall a. Maybe a
Nothing
  | Integer
jy Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
> Integer
3177 = Maybe Day
forall a. Maybe a
Nothing
  | Int
jm Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
1 = Maybe Day
forall a. Maybe a
Nothing
  | Int
jm Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
12 = Maybe Day
forall a. Maybe a
Nothing
  | Int
jd Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
1 = Maybe Day
forall a. Maybe a
Nothing
  | Int
jd Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Integer -> Int -> Int
jalaaliMonthLength Integer
jy Int
jm = Maybe Day
forall a. Maybe a
Nothing
  | Bool
otherwise = Day -> Maybe Day
forall a. a -> Maybe a
Just (Day -> Maybe Day) -> Day -> Maybe Day
forall a b. (a -> b) -> a -> b
$ Integer -> Int -> Int -> Day
fromJalaali Integer
jy Int
jm Int
jd


-- | Show in slash-separated format (yyyy/mm/dd).
showJalaali :: Day -> String
showJalaali :: Day -> String
showJalaali Day
d = Integer -> String
forall a. Show a => a -> String
show Integer
jy String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"/" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. (Ord a, Num a, Show a) => a -> String
zeroPad Int
jm String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"/" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. (Ord a, Num a, Show a) => a -> String
zeroPad Int
jd
  where
    (Integer
jy, Int
jm, Int
jd) = Day -> (Integer, Int, Int)
toJalaali Day
d
    zeroPad :: a -> String
zeroPad a
n = if a
n a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
10 then String
"0" String -> String -> String
forall a. [a] -> [a] -> [a]
++ a -> String
forall a. Show a => a -> String
show a
n else a -> String
forall a. Show a => a -> String
show a
n


-- | The number of days in a given month according to the Jalaali calendar.
-- First argument is year, second is month.
jalaaliMonthLength :: Integer -> Int -> Int
jalaaliMonthLength :: Integer -> Int -> Int
jalaaliMonthLength Integer
jy Int
jm
  | Int
jm Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
6 = Int
31
  | Int
jm Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
11 = Int
30
  | Integer -> Bool
isJalaaliLeapYear Integer
jy = Int
30
  | Bool
otherwise = Int
29


-- | Add months, with days past the last day of the month clipped to the last
-- day. For instance, 1400/05/31 + 7 months = 1400/12/29.
addJalaaliMonthsClip :: Integer -> Day -> Day
addJalaaliMonthsClip :: Integer -> Day -> Day
addJalaaliMonthsClip Integer
m Day
d = Integer -> Int -> Int -> Day
fromJalaali Integer
jyn Int
jmn Int
jdn
  where
    (Integer
jy, Int
jm, Int
jd) = Day -> (Integer, Int, Int)
toJalaali Day
d
    jyn :: Integer
jyn = Int -> Integer
forall a. Integral a => a -> Integer
toInteger (((Integer -> Int
forall a. Num a => Integer -> a
fromInteger Integer
m) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
jm Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
12) Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
jy
    jmn :: Int
jmn = (((Integer -> Int
forall a. Num a => Integer -> a
fromInteger Integer
m) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
jm Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
12) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
    jdn :: Int
jdn = Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
jd (Integer -> Int -> Int
jalaaliMonthLength Integer
jyn Int
jmn)


-- | Add months, with days past the last day of the month rolling over to the
-- next month. For instance, 1400/05/31 + 7 months = 1401/01/02.
addJalaaliMonthsRollOver :: Integer -> Day -> Day
addJalaaliMonthsRollOver :: Integer -> Day -> Day
addJalaaliMonthsRollOver Integer
m Day
d =
  Integer -> Day -> Day
addDays (Int -> Integer
forall a. Integral a => a -> Integer
toInteger (Int
jd Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
jdn)) (Day -> Day) -> Day -> Day
forall a b. (a -> b) -> a -> b
$ Integer -> Int -> Int -> Day
fromJalaali Integer
jyn Int
jmn Int
jdn
  where
    (Integer
jy, Int
jm, Int
jd) = Day -> (Integer, Int, Int)
toJalaali Day
d
    jyn :: Integer
jyn = Int -> Integer
forall a. Integral a => a -> Integer
toInteger (((Integer -> Int
forall a. Num a => Integer -> a
fromInteger Integer
m) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
jm Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
12) Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
jy
    jmn :: Int
jmn = (((Integer -> Int
forall a. Num a => Integer -> a
fromInteger Integer
m) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
jm Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
12) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
    jdn :: Int
jdn = Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
jd (Integer -> Int -> Int
jalaaliMonthLength Integer
jyn Int
jmn)


-- | Add years, matching month and day, with Esfand 30th clipped to Esfand 29th
-- if necessary. For instance, 1399/12/30 + 1 year = 1400/12/29.
addJalaaliYearsClip :: Integer -> Day -> Day
addJalaaliYearsClip :: Integer -> Day -> Day
addJalaaliYearsClip Integer
y Day
d = Integer -> Int -> Int -> Day
fromJalaali Integer
jyn Int
jmn Int
jdn
  where
    (Integer
jy, Int
jm, Int
jd) = Day -> (Integer, Int, Int)
toJalaali Day
d
    jyn :: Integer
jyn = Integer
y Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
jy
    jmn :: Int
jmn = Int
jm
    jdn :: Int
jdn = Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
jd (Integer -> Int -> Int
jalaaliMonthLength Integer
jyn Int
jmn)


-- | Add years, matching month and day, with Esfand 30th rolled over to
-- Farvardin 1st if necessary. For instance, 1399/12/30 + 1 year = 1401/01/01.
addJalaaliYearsRollOver :: Integer -> Day -> Day
addJalaaliYearsRollOver :: Integer -> Day -> Day
addJalaaliYearsRollOver Integer
y Day
d =
  Integer -> Day -> Day
addDays (Int -> Integer
forall a. Integral a => a -> Integer
toInteger (Int
jd Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
jdn)) (Day -> Day) -> Day -> Day
forall a b. (a -> b) -> a -> b
$ Integer -> Int -> Int -> Day
fromJalaali Integer
jyn Int
jmn Int
jdn
  where
    (Integer
jy, Int
jm, Int
jd) = Day -> (Integer, Int, Int)
toJalaali Day
d
    jyn :: Integer
jyn = Integer
y Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
jy
    jmn :: Int
jmn = Int
jm
    jdn :: Int
jdn = Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
jd (Integer -> Int -> Int
jalaaliMonthLength Integer
jyn Int
jmn)


-- | Add months (clipped to last day), then add days.
addJalaaliDurationClip :: CalendarDiffDays -> Day -> Day
addJalaaliDurationClip :: CalendarDiffDays -> Day -> Day
addJalaaliDurationClip (CalendarDiffDays Integer
dm Integer
dd) Day
d =
  Integer -> Day -> Day
addDays Integer
dd (Day -> Day) -> Day -> Day
forall a b. (a -> b) -> a -> b
$ Integer -> Day -> Day
addJalaaliMonthsClip Integer
dm Day
d


-- | Add months (rolling over to next month), then add days.
addJalaaliDurationRollOver :: CalendarDiffDays -> Day -> Day
addJalaaliDurationRollOver :: CalendarDiffDays -> Day -> Day
addJalaaliDurationRollOver (CalendarDiffDays Integer
dm Integer
dd) Day
d =
  Integer -> Day -> Day
addDays Integer
dd (Day -> Day) -> Day -> Day
forall a b. (a -> b) -> a -> b
$ Integer -> Day -> Day
addJalaaliMonthsRollOver Integer
dm Day
d


-- | Is this year a leap year according to the Jalaali calendar?
isJalaaliLeapYear :: Integer -> Bool
isJalaaliLeapYear :: Integer -> Bool
isJalaaliLeapYear Integer
jy = Int
leap Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0
  where
    (Int
leap, Int
_, Int
_) = Int -> (Int, Int, Int)
jalCal (Integer -> Int
forall a. Num a => Integer -> a
fromInteger Integer
jy)


----------------------------------------------

type JalaaliYear = Int
type JalaaliMonth = Int
type JalaaliDay = Int
type GregorianYear = Int
type GregorianMonth = Int
type GregorianDay = Int
type JulianDayNumber = Int
type DayInMarch = Int
type LeapOffset = Int
type JalaaliDate = (JalaaliYear, JalaaliMonth, JalaaliDay)
type GregorianDate = (GregorianYear, GregorianMonth, GregorianDay)

-- Jalaali years starting the 33-year rule.
breaks :: [JalaaliYear]
breaks :: [Int]
breaks =  [ -Int
61, Int
9, Int
38, Int
199, Int
426, Int
686, Int
756, Int
818, Int
1111, Int
1181, Int
1210
          , Int
1635, Int
2060, Int
2097, Int
2192, Int
2262, Int
2324, Int
2394, Int
2456, Int
3178
          ]


{-
  This function determines if the Jalaali (Persian) year is
  leap (366-day long) or is the common year (365 days), and
  finds the day in March (Gregorian calendar) of the first
  day of the Jalaali year (jy).

  @param jy Jalaali calendar year (-61 to 3177)
  @return
    leap: number of years since the last leap year (0 to 4)
    gy: Gregorian year of the beginning of Jalaali year
    march: the March day of Farvardin the 1st (1st day of jy)
  @see: http://www.astro.uni.torun.pl/~kb/Papers/EMP/PersianC-EMP.htm
  @see: http://www.fourmilab.ch/documents/calendar/
-}
jalCal :: JalaaliYear -> (LeapOffset, GregorianYear, DayInMarch)
jalCal :: Int -> (Int, Int, Int)
jalCal Int
jy
  | Int
jy Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< (-Int
61) = String -> (Int, Int, Int)
forall a. HasCallStack => String -> a
error (String
"invalid Jalaali year " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
jy String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
", should be >= -61")
  | Int
jy Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
3177 = String -> (Int, Int, Int)
forall a. HasCallStack => String -> a
error (String
"invalid Jalaali year " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
jy String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
", should be <= 3177")
  | Bool
otherwise = (Int
leap, Int
gy, Int
dayInMarch)
    where
      gy :: Int
gy = Int
jy Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
621

      quot4 :: Int -> Int
quot4 = (Int -> Int -> Int
forall a. Integral a => a -> a -> a
`quot` Int
4)
      quot33 :: Int -> Int
quot33 = (Int -> Int -> Int
forall a. Integral a => a -> a -> a
`quot` Int
33)
      mod33 :: Int -> Int
mod33 = (Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
33)

      ([Int]
before, [Int]
after) = (Int -> Bool) -> [Int] -> ([Int], [Int])
forall a. (a -> Bool) -> [a] -> ([a], [a])
break (Int
jy Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<) [Int]
breaks
      n :: Int
n = Int
jy Int -> Int -> Int
forall a. Num a => a -> a -> a
- [Int] -> Int
forall a. [a] -> a
last [Int]
before

      years :: [Int]
years = [Int]
before [Int] -> [Int] -> [Int]
forall a. [a] -> [a] -> [a]
++ if [Int] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Int]
after then [] else [[Int] -> Int
forall a. [a] -> a
head [Int]
after]
      jumps :: [Int]
jumps = (Int -> Int -> Int) -> [Int] -> [Int] -> [Int]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith (-) (Int -> [Int] -> [Int]
forall a. Int -> [a] -> [a]
drop Int
1 [Int]
years) [Int]
years
      lastJump :: Int
lastJump = [Int] -> Int
forall a. [a] -> a
last [Int]
jumps

      -- Find the limiting years for the Jalaali year jy.
      leapJ' :: Int
leapJ' = (Int -> Int -> Int) -> Int -> [Int] -> Int
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' (\Int
acc Int
jump -> Int
acc Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int -> Int
quot33 Int
jump Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
8 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int -> Int
quot4 (Int -> Int
mod33 Int
jump)) (-Int
14) ([Int] -> [Int]
forall a. [a] -> [a]
init [Int]
jumps)
      -- Find the number of leap years from AD 621 to the beginning
      -- of the current Jalaali year in the Persian calendar.
      leapJ'' :: Int
leapJ'' = Int
leapJ' Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int -> Int
quot33 Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
8 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int -> Int
quot4 (Int -> Int
mod33 Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
3)
      leapJ :: Int
leapJ = Int
leapJ'' Int -> Int -> Int
forall a. Num a => a -> a -> a
+ if Int -> Int
mod33 Int
lastJump Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
4 Bool -> Bool -> Bool
&& (Int
lastJump Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
n) Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
4 then Int
1 else Int
0

      -- And the same in the Gregorian calendar (until the year gy).
      leapG :: Int
leapG = Int -> Int
quot4 Int
gy Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int -> Int
quot4 (((Int
gy Int -> Int -> Int
forall a. Integral a => a -> a -> a
`quot` Int
100) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
3) Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
150

      -- Determine the Gregorian date of Farvardin the 1st.
      dayInMarch :: Int
dayInMarch = Int
20 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
leapJ Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
leapG

      -- Find how many years have passed since the last leap year.
      n' :: Int
n' = Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
+ if Int
lastJump Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
6 then Int -> Int
quot33 (Int
lastJump Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
4) Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
33 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
lastJump else Int
0
      leap' :: Int
leap' = (Int -> Int
mod33 (Int
n' Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
4
      leap :: Int
leap = if Int
leap' Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== -Int
1 then Int
4 else Int
leap'


{-
  Converts a date of the Jalaali calendar to the Julian Day number.

  @param jy Jalaali year (1 to 3100)
  @param jm Jalaali month (1 to 12)
  @param jd Jalaali day (1 to 29/31)
  @return Julian Day number
-}
j2d :: JalaaliYear -> JalaaliMonth -> JalaaliDay -> JulianDayNumber
j2d :: Int -> Int -> Int -> Int
j2d Int
jy Int
jm Int
jd = Int
jdn Int -> Int -> Int
forall a. Num a => a -> a -> a
+ (Int
jm Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
31 Int -> Int -> Int
forall a. Num a => a -> a -> a
- (Int
jm Int -> Int -> Int
forall a. Integral a => a -> a -> a
`quot` Int
7) Int -> Int -> Int
forall a. Num a => a -> a -> a
* (Int
jm Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
7) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
jd Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1
  where
    (Int
_, Int
gy, Int
dayInMarch) = Int -> (Int, Int, Int)
jalCal Int
jy
    jdn :: Int
jdn = Int -> Int -> Int -> Int
g2d Int
gy Int
3 Int
dayInMarch


{-
  Converts the Julian Day number to a date in the Jalaali calendar.

  @param jdn Julian Day number
  @return
    jy: Jalaali year (1 to 3100)
    jm: Jalaali month (1 to 12)
    jd: Jalaali day (1 to 29/31)
-}
d2j :: JulianDayNumber -> JalaaliDate
d2j :: Int -> (Int, Int, Int)
d2j Int
jdn = (Int
jy, Int
jm, Int
jd)
  where
    (Int
gy, Int
_, Int
_) = Int -> (Int, Int, Int)
d2g Int
jdn
    jy' :: Int
jy' = Int
gy Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
621
    (Int
leap, Int
_, Int
dayInMarch) = Int -> (Int, Int, Int)
jalCal Int
jy'
    jdn1f :: Int
jdn1f = Int -> Int -> Int -> Int
g2d Int
gy Int
3 Int
dayInMarch
    k' :: Int
k' = Int
jdn Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
jdn1f
    k :: Int
k | Int
k' Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
0 Bool -> Bool -> Bool
&& Int
k' Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
185 = Int
k'
      | Int
k' Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
0 = Int
k' Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
186
      | Bool
otherwise = Int
k' Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
179 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ if Int
leap Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
1 then Int
1 else Int
0
    jy :: Int
jy = Int
jy' Int -> Int -> Int
forall a. Num a => a -> a -> a
- if Int
k' Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0 then Int
1 else Int
0 -- Previous Jalaali year.
    jm :: Int
jm =  if Int
k' Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
0 Bool -> Bool -> Bool
&& Int
k' Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
185
          then Int
1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ (Int
k Int -> Int -> Int
forall a. Integral a => a -> a -> a
`quot` Int
31)
          else Int
7 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ (Int
k Int -> Int -> Int
forall a. Integral a => a -> a -> a
`quot` Int
30)
    jd :: Int
jd =  Int -> Int -> Int
forall a. Num a => a -> a -> a
(+) Int
1 (Int -> Int -> Int
forall a. Integral a => a -> a -> a
mod Int
k (if Int
k' Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
0 Bool -> Bool -> Bool
&& Int
k' Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
185 then Int
31 else Int
30))


{-
  Calculates the Julian Day number from Gregorian or Julian
  calendar dates. This integer number corresponds to the noon of
  the date (i.e. 12 hours of Universal Time).
  The procedure was tested to be good since 1 March, -100100 (of both
  calendars) up to a few million years into the future.

  @param gy Calendar year (years BC numbered 0, -1, -2, ...)
  @param gm Calendar month (1 to 12)
  @param gd Calendar day of the month (1 to 28/29/30/31)
  @return Julian Day number
-}
g2d :: GregorianYear -> GregorianMonth -> GregorianDay -> JulianDayNumber
g2d :: Int -> Int -> Int -> Int
g2d Int
gy Int
gm Int
gd =
  Int
d Int -> Int -> Int
forall a. Num a => a -> a -> a
- ((((Int
gy Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
100100 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ ((Int
gm Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
8) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`quot` Int
6)) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`quot` Int
100) Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
3) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`quot` Int
4) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
752
  where
    d :: Int
d = ((Int
gy Int -> Int -> Int
forall a. Num a => a -> a -> a
+ ((Int
gm Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
8) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`quot` Int
6) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
100100) Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
1461) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`quot` Int
4 Int -> Int -> Int
forall a. Num a => a -> a -> a
+
        (Int
153 Int -> Int -> Int
forall a. Num a => a -> a -> a
* ((Int
gm Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
9) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
12) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`quot` Int
5 Int -> Int -> Int
forall a. Num a => a -> a -> a
+
        Int
gd Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
34840408


{-
  Calculates Gregorian and Julian calendar dates from the Julian Day number
  (jdn) for the period since jdn=-34839655 (i.e. the year -100100 of both
  calendars) to some millions years ahead of the present.

  @param jdn Julian Day number
  @return
    gy: Calendar year (years BC numbered 0, -1, -2, ...)
    gm: Calendar month (1 to 12)
    gd: Calendar day of the month M (1 to 28/29/30/31)
-}
d2g :: JulianDayNumber -> GregorianDate
d2g :: Int -> (Int, Int, Int)
d2g Int
jdn = (Int
gy, Int
gm, Int
gd)
  where
    j' :: Int
j' = Int
4 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
jdn Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
139361631
    j :: Int
j = Int
j' Int -> Int -> Int
forall a. Num a => a -> a -> a
+ ((((Int
4 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
jdn Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
183187720) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`quot` Int
146097) Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
3) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`quot` Int
4) Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
4 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
3908
    i :: Int
i = ((Int
j Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
1461) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`quot` Int
4) Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
5 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
308
    gd :: Int
gd = ((Int
i Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
153) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`quot` Int
5) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
    gm :: Int
gm = ((Int
i Int -> Int -> Int
forall a. Integral a => a -> a -> a
`quot` Int
153) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
12) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
    gy :: Int
gy = (Int
j Int -> Int -> Int
forall a. Integral a => a -> a -> a
`quot` Int
1461) Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
100100 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ ((Int
8 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
gm) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`quot` Int
6)