{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
-----------------------------------------------------------------------------
-- |
-- Module      :  Data.HodaTime.Calendar.Hebrew
-- Copyright   :  (C) 2017 Jason Johnson
-- License     :  BSD-style (see the file LICENSE)
-- Maintainer  :  Jason Johnson <jason.johnson.081@gmail.com>
-- Stability   :  experimental
-- Portability :  POSIX, Windows
--
-- This is the module for 'CalendarDate' and 'CalendarDateTime' in the 'Hebrew' (Jewish) calendar, a lunisolar calendar that keeps its lunar months in step with the solar year by inserting a thirteenth
-- month ('AdarI') seven times in each nineteen-year Metonic cycle (in years 3, 6, 8, 11, 14, 17 and 19).  A common year has twelve months and a leap year thirteen; two of the months ('Cheshvan' and
-- 'Kislev') can independently gain or lose a day so that the year comes out to one of six permitted lengths (353\/354\/355 days common, 383\/384\/385 leap).  The year number changes at 1 'Tishri' (Rosh
-- Hashanah), and dates share the same absolute timeline as every other calendar.
--
-- == Month numbering: civil vs. scriptural
--
-- There are two traditional ways to /number/ the Hebrew months, and — as with the Islamic leap patterns — the calendar is parameterised over the choice at the /type level/ so that a date always records which
-- convention it uses and the type system refuses to mix the two.  The choice does not change the underlying calendar at all (the months, their lengths and the day a given date falls on are identical); it only
-- changes which ordinal number 'fromEnum' \/ 'toEnum' assign to each month:
--
--     * __Civil__ (the default) counts from 'Tishri', the month of Rosh Hashanah at which the year number turns over.  This is the numbering used by the .NET @HebrewCalendar@ and is the natural one for most
--       software: Tishri = 1, Cheshvan = 2, … , with the leap month 'AdarI' falling in the middle of the sequence in a leap year.
--
--     * __Scriptural__ (biblical\/ecclesiastical) counts from 'Nisan', the \"first month\" of the Exodus.  Nisan = 1, Iyar = 2, … , Tishri = 7, and the leap month 'AdarI' is numbered last (after 'Shevat'),
--       keeping the numbers of the other twelve months fixed between common and leap years.
--
-- The month /constructors/ are shared across both conventions (the parameter is phantom for storage), so 'Nisan' is the same month either way — only its 'Enum' number differs.  Each convention has a type
-- synonym, 'HebrewCivil' and 'HebrewScriptural', and 'HebrewCivil' is the default.
--
-- == The two Adars
--
-- In a common year there is a single month 'Adar'.  A leap year inserts an extra month, 'AdarI' (Adar Rishon), /before/ it; the original 'Adar' then plays the role of \"Adar II\" (Adar Sheni) and still
-- carries Purim.  So 'Adar' is present every year and 'AdarI' exists only in leap years — attempting to build a date in 'AdarI' in a common year yields 'Nothing', exactly as an out-of-range day or year does.
----------------------------------------------------------------------------
module Data.HodaTime.Calendar.Hebrew
(
  -- * Constructors (default civil calendar)
   calendarDate
  ,fromNthDay
  ,fromWeekDate
  -- * Constructors (choose the numbering)
  ,calendarDate'
  ,fromNthDay'
  ,fromWeekDate'
  -- * Types
  ,Hebrew
  ,MonthNumbering(..)
  ,Month(..)
  ,DayOfWeek(..)
  ,KnownNumbering
  -- * Named calendars (month-numbering type synonyms)
  ,HebrewCivil
  ,HebrewScriptural
)
where

import Data.HodaTime.CalendarDateTime.Internal (IsCalendar(..), IsCalendarDateTime(..), CalendarDate, DayNth, DayOfMonth, Year, WeekNumber, CalendarDateTime(..), LocalTime(..), Date)
import Control.DeepSeq (NFData(..))
import Data.Hashable (Hashable(..))
import Data.HodaTime.Instant.Internal (Instant(..))
import Data.HodaTime.Calendar.Internal (mkFromNthDay, moveByDow, dayOfWeekFromDays)
import Data.Int (Int32)
import Data.List (elemIndex)
import Data.Maybe (fromJust)
import Data.Word (Word8)
import Control.Monad (guard)

-- types

-- | The two conventions for numbering the Hebrew months, used as the (kind-'MonthNumbering') type parameter of 'Hebrew'
--   (see the module header).
data MonthNumbering = Civil | Scriptural

-- | The Hebrew (Jewish) calendar, parameterised by its month-numbering convention (see 'MonthNumbering').
data Hebrew (n :: MonthNumbering)

-- | The Hebrew calendar numbered from 'Tishri' (the .NET @HebrewCalendar@ convention).  This is the default.
type HebrewCivil      = Hebrew 'Civil
-- | The Hebrew calendar numbered from 'Nisan' (the biblical \/ ecclesiastical convention).
type HebrewScriptural = Hebrew 'Scriptural

-- | Reflects a 'MonthNumbering' down to the calendar-order index at which it begins counting months: civil starts at
--   'Tishri' (0) and scriptural at 'Nisan' (7).  Read it via @TypeApplications@, e.g. @'numberingStart' \@'Civil'@.
class KnownNumbering (n :: MonthNumbering) where
  numberingStart :: Int

instance KnownNumbering 'Civil      where numberingStart :: Int
numberingStart = Int
0
instance KnownNumbering 'Scriptural where numberingStart :: Int
numberingStart = Int
7   -- 'Nisan' is calendar-order index 7

-- | The Hebrew calendar. All field access and conversions run in numbering-independent calendar order; the
--   numbering only selects how 'Month' values are numbered by 'Enum'.
instance KnownNumbering n => IsCalendar (Hebrew n) where
  -- | Denormalized: the flat, epoch-relative day count plus the decoded day, calendar-order month index and year.
  data Date (Hebrew n) = HebrewDate {-# UNPACK #-} !Int32 {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8 {-# UNPACK #-} !Int32
    deriving (Date (Hebrew n) -> Date (Hebrew n) -> Bool
(Date (Hebrew n) -> Date (Hebrew n) -> Bool)
-> (Date (Hebrew n) -> Date (Hebrew n) -> Bool)
-> Eq (Date (Hebrew n))
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall (n :: MonthNumbering).
Date (Hebrew n) -> Date (Hebrew n) -> Bool
$c== :: forall (n :: MonthNumbering).
Date (Hebrew n) -> Date (Hebrew n) -> Bool
== :: Date (Hebrew n) -> Date (Hebrew n) -> Bool
$c/= :: forall (n :: MonthNumbering).
Date (Hebrew n) -> Date (Hebrew n) -> Bool
/= :: Date (Hebrew n) -> Date (Hebrew n) -> Bool
Eq, Eq (Date (Hebrew n))
Eq (Date (Hebrew n)) =>
(Date (Hebrew n) -> Date (Hebrew n) -> Ordering)
-> (Date (Hebrew n) -> Date (Hebrew n) -> Bool)
-> (Date (Hebrew n) -> Date (Hebrew n) -> Bool)
-> (Date (Hebrew n) -> Date (Hebrew n) -> Bool)
-> (Date (Hebrew n) -> Date (Hebrew n) -> Bool)
-> (Date (Hebrew n) -> Date (Hebrew n) -> Date (Hebrew n))
-> (Date (Hebrew n) -> Date (Hebrew n) -> Date (Hebrew n))
-> Ord (Date (Hebrew n))
Date (Hebrew n) -> Date (Hebrew n) -> Bool
Date (Hebrew n) -> Date (Hebrew n) -> Ordering
Date (Hebrew n) -> Date (Hebrew n) -> Date (Hebrew n)
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall (n :: MonthNumbering). Eq (Date (Hebrew n))
forall (n :: MonthNumbering).
Date (Hebrew n) -> Date (Hebrew n) -> Bool
forall (n :: MonthNumbering).
Date (Hebrew n) -> Date (Hebrew n) -> Ordering
forall (n :: MonthNumbering).
Date (Hebrew n) -> Date (Hebrew n) -> Date (Hebrew n)
$ccompare :: forall (n :: MonthNumbering).
Date (Hebrew n) -> Date (Hebrew n) -> Ordering
compare :: Date (Hebrew n) -> Date (Hebrew n) -> Ordering
$c< :: forall (n :: MonthNumbering).
Date (Hebrew n) -> Date (Hebrew n) -> Bool
< :: Date (Hebrew n) -> Date (Hebrew n) -> Bool
$c<= :: forall (n :: MonthNumbering).
Date (Hebrew n) -> Date (Hebrew n) -> Bool
<= :: Date (Hebrew n) -> Date (Hebrew n) -> Bool
$c> :: forall (n :: MonthNumbering).
Date (Hebrew n) -> Date (Hebrew n) -> Bool
> :: Date (Hebrew n) -> Date (Hebrew n) -> Bool
$c>= :: forall (n :: MonthNumbering).
Date (Hebrew n) -> Date (Hebrew n) -> Bool
>= :: Date (Hebrew n) -> Date (Hebrew n) -> Bool
$cmax :: forall (n :: MonthNumbering).
Date (Hebrew n) -> Date (Hebrew n) -> Date (Hebrew n)
max :: Date (Hebrew n) -> Date (Hebrew n) -> Date (Hebrew n)
$cmin :: forall (n :: MonthNumbering).
Date (Hebrew n) -> Date (Hebrew n) -> Date (Hebrew n)
min :: Date (Hebrew n) -> Date (Hebrew n) -> Date (Hebrew n)
Ord)

  -- | The Hebrew months, listed in calendar order from 'Tishri'.  'AdarI' (the leap month) sits between 'Shevat' and
  --   'Adar'; it exists only in leap years.  The constructors are shared by both numbering conventions — only their
  --   'Enum' numbers differ.
  data Month (Hebrew n) =
      Tishri | Cheshvan | Kislev | Tevet | Shevat | AdarI | Adar | Nisan | Iyar | Sivan | Tammuz | Av | Elul
    deriving (Int -> Month (Hebrew n) -> ShowS
[Month (Hebrew n)] -> ShowS
Month (Hebrew n) -> String
(Int -> Month (Hebrew n) -> ShowS)
-> (Month (Hebrew n) -> String)
-> ([Month (Hebrew n)] -> ShowS)
-> Show (Month (Hebrew n))
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall (n :: MonthNumbering). Int -> Month (Hebrew n) -> ShowS
forall (n :: MonthNumbering). [Month (Hebrew n)] -> ShowS
forall (n :: MonthNumbering). Month (Hebrew n) -> String
$cshowsPrec :: forall (n :: MonthNumbering). Int -> Month (Hebrew n) -> ShowS
showsPrec :: Int -> Month (Hebrew n) -> ShowS
$cshow :: forall (n :: MonthNumbering). Month (Hebrew n) -> String
show :: Month (Hebrew n) -> String
$cshowList :: forall (n :: MonthNumbering). [Month (Hebrew n)] -> ShowS
showList :: [Month (Hebrew n)] -> ShowS
Show, ReadPrec [Month (Hebrew n)]
ReadPrec (Month (Hebrew n))
Int -> ReadS (Month (Hebrew n))
ReadS [Month (Hebrew n)]
(Int -> ReadS (Month (Hebrew n)))
-> ReadS [Month (Hebrew n)]
-> ReadPrec (Month (Hebrew n))
-> ReadPrec [Month (Hebrew n)]
-> Read (Month (Hebrew n))
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
forall (n :: MonthNumbering). ReadPrec [Month (Hebrew n)]
forall (n :: MonthNumbering). ReadPrec (Month (Hebrew n))
forall (n :: MonthNumbering). Int -> ReadS (Month (Hebrew n))
forall (n :: MonthNumbering). ReadS [Month (Hebrew n)]
$creadsPrec :: forall (n :: MonthNumbering). Int -> ReadS (Month (Hebrew n))
readsPrec :: Int -> ReadS (Month (Hebrew n))
$creadList :: forall (n :: MonthNumbering). ReadS [Month (Hebrew n)]
readList :: ReadS [Month (Hebrew n)]
$creadPrec :: forall (n :: MonthNumbering). ReadPrec (Month (Hebrew n))
readPrec :: ReadPrec (Month (Hebrew n))
$creadListPrec :: forall (n :: MonthNumbering). ReadPrec [Month (Hebrew n)]
readListPrec :: ReadPrec [Month (Hebrew n)]
Read, Month (Hebrew n) -> Month (Hebrew n) -> Bool
(Month (Hebrew n) -> Month (Hebrew n) -> Bool)
-> (Month (Hebrew n) -> Month (Hebrew n) -> Bool)
-> Eq (Month (Hebrew n))
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall (n :: MonthNumbering).
Month (Hebrew n) -> Month (Hebrew n) -> Bool
$c== :: forall (n :: MonthNumbering).
Month (Hebrew n) -> Month (Hebrew n) -> Bool
== :: Month (Hebrew n) -> Month (Hebrew n) -> Bool
$c/= :: forall (n :: MonthNumbering).
Month (Hebrew n) -> Month (Hebrew n) -> Bool
/= :: Month (Hebrew n) -> Month (Hebrew n) -> Bool
Eq, Eq (Month (Hebrew n))
Eq (Month (Hebrew n)) =>
(Month (Hebrew n) -> Month (Hebrew n) -> Ordering)
-> (Month (Hebrew n) -> Month (Hebrew n) -> Bool)
-> (Month (Hebrew n) -> Month (Hebrew n) -> Bool)
-> (Month (Hebrew n) -> Month (Hebrew n) -> Bool)
-> (Month (Hebrew n) -> Month (Hebrew n) -> Bool)
-> (Month (Hebrew n) -> Month (Hebrew n) -> Month (Hebrew n))
-> (Month (Hebrew n) -> Month (Hebrew n) -> Month (Hebrew n))
-> Ord (Month (Hebrew n))
Month (Hebrew n) -> Month (Hebrew n) -> Bool
Month (Hebrew n) -> Month (Hebrew n) -> Ordering
Month (Hebrew n) -> Month (Hebrew n) -> Month (Hebrew n)
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall (n :: MonthNumbering). Eq (Month (Hebrew n))
forall (n :: MonthNumbering).
Month (Hebrew n) -> Month (Hebrew n) -> Bool
forall (n :: MonthNumbering).
Month (Hebrew n) -> Month (Hebrew n) -> Ordering
forall (n :: MonthNumbering).
Month (Hebrew n) -> Month (Hebrew n) -> Month (Hebrew n)
$ccompare :: forall (n :: MonthNumbering).
Month (Hebrew n) -> Month (Hebrew n) -> Ordering
compare :: Month (Hebrew n) -> Month (Hebrew n) -> Ordering
$c< :: forall (n :: MonthNumbering).
Month (Hebrew n) -> Month (Hebrew n) -> Bool
< :: Month (Hebrew n) -> Month (Hebrew n) -> Bool
$c<= :: forall (n :: MonthNumbering).
Month (Hebrew n) -> Month (Hebrew n) -> Bool
<= :: Month (Hebrew n) -> Month (Hebrew n) -> Bool
$c> :: forall (n :: MonthNumbering).
Month (Hebrew n) -> Month (Hebrew n) -> Bool
> :: Month (Hebrew n) -> Month (Hebrew n) -> Bool
$c>= :: forall (n :: MonthNumbering).
Month (Hebrew n) -> Month (Hebrew n) -> Bool
>= :: Month (Hebrew n) -> Month (Hebrew n) -> Bool
$cmax :: forall (n :: MonthNumbering).
Month (Hebrew n) -> Month (Hebrew n) -> Month (Hebrew n)
max :: Month (Hebrew n) -> Month (Hebrew n) -> Month (Hebrew n)
$cmin :: forall (n :: MonthNumbering).
Month (Hebrew n) -> Month (Hebrew n) -> Month (Hebrew n)
min :: Month (Hebrew n) -> Month (Hebrew n) -> Month (Hebrew n)
Ord, Month (Hebrew n)
Month (Hebrew n) -> Month (Hebrew n) -> Bounded (Month (Hebrew n))
forall a. a -> a -> Bounded a
forall (n :: MonthNumbering). Month (Hebrew n)
$cminBound :: forall (n :: MonthNumbering). Month (Hebrew n)
minBound :: Month (Hebrew n)
$cmaxBound :: forall (n :: MonthNumbering). Month (Hebrew n)
maxBound :: Month (Hebrew n)
Bounded)

  data DayOfWeek (Hebrew n) = Sunday | Monday | Tuesday | Wednesday | Thursday | Friday | Saturday
    deriving (Int -> DayOfWeek (Hebrew n) -> ShowS
[DayOfWeek (Hebrew n)] -> ShowS
DayOfWeek (Hebrew n) -> String
(Int -> DayOfWeek (Hebrew n) -> ShowS)
-> (DayOfWeek (Hebrew n) -> String)
-> ([DayOfWeek (Hebrew n)] -> ShowS)
-> Show (DayOfWeek (Hebrew n))
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall (n :: MonthNumbering). Int -> DayOfWeek (Hebrew n) -> ShowS
forall (n :: MonthNumbering). [DayOfWeek (Hebrew n)] -> ShowS
forall (n :: MonthNumbering). DayOfWeek (Hebrew n) -> String
$cshowsPrec :: forall (n :: MonthNumbering). Int -> DayOfWeek (Hebrew n) -> ShowS
showsPrec :: Int -> DayOfWeek (Hebrew n) -> ShowS
$cshow :: forall (n :: MonthNumbering). DayOfWeek (Hebrew n) -> String
show :: DayOfWeek (Hebrew n) -> String
$cshowList :: forall (n :: MonthNumbering). [DayOfWeek (Hebrew n)] -> ShowS
showList :: [DayOfWeek (Hebrew n)] -> ShowS
Show, ReadPrec [DayOfWeek (Hebrew n)]
ReadPrec (DayOfWeek (Hebrew n))
Int -> ReadS (DayOfWeek (Hebrew n))
ReadS [DayOfWeek (Hebrew n)]
(Int -> ReadS (DayOfWeek (Hebrew n)))
-> ReadS [DayOfWeek (Hebrew n)]
-> ReadPrec (DayOfWeek (Hebrew n))
-> ReadPrec [DayOfWeek (Hebrew n)]
-> Read (DayOfWeek (Hebrew n))
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
forall (n :: MonthNumbering). ReadPrec [DayOfWeek (Hebrew n)]
forall (n :: MonthNumbering). ReadPrec (DayOfWeek (Hebrew n))
forall (n :: MonthNumbering). Int -> ReadS (DayOfWeek (Hebrew n))
forall (n :: MonthNumbering). ReadS [DayOfWeek (Hebrew n)]
$creadsPrec :: forall (n :: MonthNumbering). Int -> ReadS (DayOfWeek (Hebrew n))
readsPrec :: Int -> ReadS (DayOfWeek (Hebrew n))
$creadList :: forall (n :: MonthNumbering). ReadS [DayOfWeek (Hebrew n)]
readList :: ReadS [DayOfWeek (Hebrew n)]
$creadPrec :: forall (n :: MonthNumbering). ReadPrec (DayOfWeek (Hebrew n))
readPrec :: ReadPrec (DayOfWeek (Hebrew n))
$creadListPrec :: forall (n :: MonthNumbering). ReadPrec [DayOfWeek (Hebrew n)]
readListPrec :: ReadPrec [DayOfWeek (Hebrew n)]
Read, DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n) -> Bool
(DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n) -> Bool)
-> (DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n) -> Bool)
-> Eq (DayOfWeek (Hebrew n))
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall (n :: MonthNumbering).
DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n) -> Bool
$c== :: forall (n :: MonthNumbering).
DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n) -> Bool
== :: DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n) -> Bool
$c/= :: forall (n :: MonthNumbering).
DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n) -> Bool
/= :: DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n) -> Bool
Eq, Eq (DayOfWeek (Hebrew n))
Eq (DayOfWeek (Hebrew n)) =>
(DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n) -> Ordering)
-> (DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n) -> Bool)
-> (DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n) -> Bool)
-> (DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n) -> Bool)
-> (DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n) -> Bool)
-> (DayOfWeek (Hebrew n)
    -> DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n))
-> (DayOfWeek (Hebrew n)
    -> DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n))
-> Ord (DayOfWeek (Hebrew n))
DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n) -> Bool
DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n) -> Ordering
DayOfWeek (Hebrew n)
-> DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n)
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall (n :: MonthNumbering). Eq (DayOfWeek (Hebrew n))
forall (n :: MonthNumbering).
DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n) -> Bool
forall (n :: MonthNumbering).
DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n) -> Ordering
forall (n :: MonthNumbering).
DayOfWeek (Hebrew n)
-> DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n)
$ccompare :: forall (n :: MonthNumbering).
DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n) -> Ordering
compare :: DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n) -> Ordering
$c< :: forall (n :: MonthNumbering).
DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n) -> Bool
< :: DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n) -> Bool
$c<= :: forall (n :: MonthNumbering).
DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n) -> Bool
<= :: DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n) -> Bool
$c> :: forall (n :: MonthNumbering).
DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n) -> Bool
> :: DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n) -> Bool
$c>= :: forall (n :: MonthNumbering).
DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n) -> Bool
>= :: DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n) -> Bool
$cmax :: forall (n :: MonthNumbering).
DayOfWeek (Hebrew n)
-> DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n)
max :: DayOfWeek (Hebrew n)
-> DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n)
$cmin :: forall (n :: MonthNumbering).
DayOfWeek (Hebrew n)
-> DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n)
min :: DayOfWeek (Hebrew n)
-> DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n)
Ord, Int -> DayOfWeek (Hebrew n)
DayOfWeek (Hebrew n) -> Int
DayOfWeek (Hebrew n) -> [DayOfWeek (Hebrew n)]
DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n)
DayOfWeek (Hebrew n)
-> DayOfWeek (Hebrew n) -> [DayOfWeek (Hebrew n)]
DayOfWeek (Hebrew n)
-> DayOfWeek (Hebrew n)
-> DayOfWeek (Hebrew n)
-> [DayOfWeek (Hebrew n)]
(DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n))
-> (DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n))
-> (Int -> DayOfWeek (Hebrew n))
-> (DayOfWeek (Hebrew n) -> Int)
-> (DayOfWeek (Hebrew n) -> [DayOfWeek (Hebrew n)])
-> (DayOfWeek (Hebrew n)
    -> DayOfWeek (Hebrew n) -> [DayOfWeek (Hebrew n)])
-> (DayOfWeek (Hebrew n)
    -> DayOfWeek (Hebrew n) -> [DayOfWeek (Hebrew n)])
-> (DayOfWeek (Hebrew n)
    -> DayOfWeek (Hebrew n)
    -> DayOfWeek (Hebrew n)
    -> [DayOfWeek (Hebrew n)])
-> Enum (DayOfWeek (Hebrew n))
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
forall (n :: MonthNumbering). Int -> DayOfWeek (Hebrew n)
forall (n :: MonthNumbering). DayOfWeek (Hebrew n) -> Int
forall (n :: MonthNumbering).
DayOfWeek (Hebrew n) -> [DayOfWeek (Hebrew n)]
forall (n :: MonthNumbering).
DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n)
forall (n :: MonthNumbering).
DayOfWeek (Hebrew n)
-> DayOfWeek (Hebrew n) -> [DayOfWeek (Hebrew n)]
forall (n :: MonthNumbering).
DayOfWeek (Hebrew n)
-> DayOfWeek (Hebrew n)
-> DayOfWeek (Hebrew n)
-> [DayOfWeek (Hebrew n)]
$csucc :: forall (n :: MonthNumbering).
DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n)
succ :: DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n)
$cpred :: forall (n :: MonthNumbering).
DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n)
pred :: DayOfWeek (Hebrew n) -> DayOfWeek (Hebrew n)
$ctoEnum :: forall (n :: MonthNumbering). Int -> DayOfWeek (Hebrew n)
toEnum :: Int -> DayOfWeek (Hebrew n)
$cfromEnum :: forall (n :: MonthNumbering). DayOfWeek (Hebrew n) -> Int
fromEnum :: DayOfWeek (Hebrew n) -> Int
$cenumFrom :: forall (n :: MonthNumbering).
DayOfWeek (Hebrew n) -> [DayOfWeek (Hebrew n)]
enumFrom :: DayOfWeek (Hebrew n) -> [DayOfWeek (Hebrew n)]
$cenumFromThen :: forall (n :: MonthNumbering).
DayOfWeek (Hebrew n)
-> DayOfWeek (Hebrew n) -> [DayOfWeek (Hebrew n)]
enumFromThen :: DayOfWeek (Hebrew n)
-> DayOfWeek (Hebrew n) -> [DayOfWeek (Hebrew n)]
$cenumFromTo :: forall (n :: MonthNumbering).
DayOfWeek (Hebrew n)
-> DayOfWeek (Hebrew n) -> [DayOfWeek (Hebrew n)]
enumFromTo :: DayOfWeek (Hebrew n)
-> DayOfWeek (Hebrew n) -> [DayOfWeek (Hebrew n)]
$cenumFromThenTo :: forall (n :: MonthNumbering).
DayOfWeek (Hebrew n)
-> DayOfWeek (Hebrew n)
-> DayOfWeek (Hebrew n)
-> [DayOfWeek (Hebrew n)]
enumFromThenTo :: DayOfWeek (Hebrew n)
-> DayOfWeek (Hebrew n)
-> DayOfWeek (Hebrew n)
-> [DayOfWeek (Hebrew n)]
Enum, DayOfWeek (Hebrew n)
DayOfWeek (Hebrew n)
-> DayOfWeek (Hebrew n) -> Bounded (DayOfWeek (Hebrew n))
forall a. a -> a -> Bounded a
forall (n :: MonthNumbering). DayOfWeek (Hebrew n)
$cminBound :: forall (n :: MonthNumbering). DayOfWeek (Hebrew n)
minBound :: DayOfWeek (Hebrew n)
$cmaxBound :: forall (n :: MonthNumbering). DayOfWeek (Hebrew n)
maxBound :: DayOfWeek (Hebrew n)
Bounded)

  fromDays :: Int32 -> Date (Hebrew n)
fromDays = Int32 -> Date (Hebrew n)
forall (n :: MonthNumbering). Int32 -> Date (Hebrew n)
hebrewFromDays
  toDays :: Date (Hebrew n) -> Int32
toDays = Date (Hebrew n) -> Int32
forall (n :: MonthNumbering). Date (Hebrew n) -> Int32
hebrewToDays
  toYmd :: Date (Hebrew n) -> (Int32, Word8, Word8)
toYmd = Date (Hebrew n) -> (Int32, Word8, Word8)
forall (n :: MonthNumbering).
Date (Hebrew n) -> (Int32, Word8, Word8)
hebrewToYmd
  calendarName :: Date (Hebrew n) -> String
calendarName Date (Hebrew n)
_ = String
"Hebrew"

  day' :: Date (Hebrew n) -> Int
day' (HebrewDate Int32
_ Word8
d Word8
_ Int32
_) = Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
d
  setDay' :: Int -> Date (Hebrew n) -> Date (Hebrew n)
setDay' = Int -> Date (Hebrew n) -> Date (Hebrew n)
forall (n :: MonthNumbering).
Int -> Date (Hebrew n) -> Date (Hebrew n)
setHebrewDay
  {-# INLINE day' #-}

  month' :: Date (Hebrew n) -> Month (Hebrew n)
month' (HebrewDate Int32
_ Word8
_ Word8
ci Int32
_) = Int -> Month (Hebrew n)
forall (n :: MonthNumbering). Int -> Month (Hebrew n)
monthAt (Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
ci)
  setMonthIndex' :: Int -> Date (Hebrew n) -> Date (Hebrew n)
setMonthIndex' = Int -> Int -> Date (Hebrew n) -> Date (Hebrew n)
forall (n :: MonthNumbering).
Int -> Int -> Date (Hebrew n) -> Date (Hebrew n)
setHebrewMonth (forall (n :: MonthNumbering). KnownNumbering n => Int
numberingStart @n)
  {-# INLINE month' #-}

  year' :: Date (Hebrew n) -> Int
year' (HebrewDate Int32
_ Word8
_ Word8
_ Int32
y) = Int32 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int32
y
  setYear' :: Int -> Date (Hebrew n) -> Date (Hebrew n)
setYear' = Int -> Date (Hebrew n) -> Date (Hebrew n)
forall (n :: MonthNumbering).
Int -> Date (Hebrew n) -> Date (Hebrew n)
setHebrewYear
  {-# INLINE year' #-}

  dayOfWeek' :: Date (Hebrew n) -> DayOfWeek (Hebrew n)
dayOfWeek' (HebrewDate Int32
days Word8
_ Word8
_ Int32
_) = Int -> DayOfWeek (Hebrew n)
forall a. Enum a => Int -> a
toEnum (Int -> DayOfWeek (Hebrew n))
-> (Int32 -> Int) -> Int32 -> DayOfWeek (Hebrew n)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DayOfWeek (Hebrew Any) -> Int -> Int
forall dow. Enum dow => dow -> Int -> Int
dayOfWeekFromDays DayOfWeek (Hebrew Any)
forall (n :: MonthNumbering). DayOfWeek (Hebrew n)
epochDayOfWeek (Int -> Int) -> (Int32 -> Int) -> Int32 -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int32 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int32 -> DayOfWeek (Hebrew n)) -> Int32 -> DayOfWeek (Hebrew n)
forall a b. (a -> b) -> a -> b
$ Int32
days

  next' :: Int -> DayOfWeek (Hebrew n) -> Date (Hebrew n) -> Date (Hebrew n)
next' Int
i DayOfWeek (Hebrew n)
dow (HebrewDate Int32
days Word8
_ Word8
_ Int32
_) = (Int32 -> Date (Hebrew n))
-> DayOfWeek (Hebrew n)
-> Int
-> DayOfWeek (Hebrew n)
-> (Int -> Int -> Int)
-> (Int -> Int -> Int)
-> (Int -> Int -> Bool)
-> Int
-> Date (Hebrew n)
forall dow d.
Enum dow =>
(Int32 -> d)
-> dow
-> Int
-> dow
-> (Int -> Int -> Int)
-> (Int -> Int -> Int)
-> (Int -> Int -> Bool)
-> Int
-> d
moveByDow Int32 -> Date (Hebrew n)
forall (n :: MonthNumbering). Int32 -> Date (Hebrew n)
hebrewFromDays DayOfWeek (Hebrew n)
forall (n :: MonthNumbering). DayOfWeek (Hebrew n)
epochDayOfWeek Int
i DayOfWeek (Hebrew n)
dow (-) Int -> Int -> Int
forall a. Num a => a -> a -> a
(+) Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
(>) (Int32 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int32
days)

  previous' :: Int -> DayOfWeek (Hebrew n) -> Date (Hebrew n) -> Date (Hebrew n)
previous' Int
i DayOfWeek (Hebrew n)
dow (HebrewDate Int32
days Word8
_ Word8
_ Int32
_) = (Int32 -> Date (Hebrew n))
-> DayOfWeek (Hebrew n)
-> Int
-> DayOfWeek (Hebrew n)
-> (Int -> Int -> Int)
-> (Int -> Int -> Int)
-> (Int -> Int -> Bool)
-> Int
-> Date (Hebrew n)
forall dow d.
Enum dow =>
(Int32 -> d)
-> dow
-> Int
-> dow
-> (Int -> Int -> Int)
-> (Int -> Int -> Int)
-> (Int -> Int -> Bool)
-> Int
-> d
moveByDow Int32 -> Date (Hebrew n)
forall (n :: MonthNumbering). Int32 -> Date (Hebrew n)
hebrewFromDays DayOfWeek (Hebrew n)
forall (n :: MonthNumbering). DayOfWeek (Hebrew n)
epochDayOfWeek Int
i DayOfWeek (Hebrew n)
dow Int -> Int -> Int
forall a. Num a => a -> a -> a
subtract (-) Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
(<) (Int32 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int32
days)  -- NOTE: subtract is (-) with the arguments flipped

-- | The 'Month' 'Enum' is the one place the numbering shows: it is calendar order rotated so counting begins at the
--   numbering's start month ('numberingStart').
instance KnownNumbering n => Enum (Month (Hebrew n)) where
  fromEnum :: Month (Hebrew n) -> Int
fromEnum Month (Hebrew n)
m = (Month (Hebrew n) -> Int
forall (n :: MonthNumbering). Month (Hebrew n) -> Int
calendarIndex Month (Hebrew n)
m Int -> Int -> Int
forall a. Num a => a -> a -> a
- forall (n :: MonthNumbering). KnownNumbering n => Int
numberingStart @n) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
monthCount
  toEnum :: Int -> Month (Hebrew n)
toEnum Int
i
    | Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
0 Bool -> Bool -> Bool
&& Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
monthCount = Int -> Month (Hebrew n)
forall (n :: MonthNumbering). Int -> Month (Hebrew n)
monthAt ((Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ forall (n :: MonthNumbering). KnownNumbering n => Int
numberingStart @n) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
monthCount)
    | Bool
otherwise               = String -> Month (Hebrew n)
forall a. HasCallStack => String -> a
error String
"Data.HodaTime.Calendar.Hebrew: toEnum: month out of range 0..12"

instance NFData (Date (Hebrew n)) where
  rnf :: Date (Hebrew n) -> ()
rnf (HebrewDate Int32
days Word8
d Word8
m Int32
y) = Int32 -> ()
forall a. NFData a => a -> ()
rnf Int32
days () -> () -> ()
forall a b. a -> b -> b
`seq` Word8 -> ()
forall a. NFData a => a -> ()
rnf Word8
d () -> () -> ()
forall a b. a -> b -> b
`seq` Word8 -> ()
forall a. NFData a => a -> ()
rnf Word8
m () -> () -> ()
forall a b. a -> b -> b
`seq` Int32 -> ()
forall a. NFData a => a -> ()
rnf Int32
y

instance Hashable (Date (Hebrew n)) where
  hashWithSalt :: Int -> Date (Hebrew n) -> Int
hashWithSalt Int
s (HebrewDate Int32
days Word8
d Word8
m Int32
y) = Int
s Int -> Int32 -> Int
forall a. Hashable a => Int -> a -> Int
`hashWithSalt` Int32
days Int -> Word8 -> Int
forall a. Hashable a => Int -> a -> Int
`hashWithSalt` Word8
d Int -> Word8 -> Int
forall a. Hashable a => Int -> a -> Int
`hashWithSalt` Word8
m Int -> Int32 -> Int
forall a. Hashable a => Int -> a -> Int
`hashWithSalt` Int32
y

instance NFData (Month (Hebrew n)) where
  rnf :: Month (Hebrew n) -> ()
rnf Month (Hebrew n)
m = Month (Hebrew n)
m Month (Hebrew n) -> () -> ()
forall a b. a -> b -> b
`seq` ()

instance KnownNumbering n => Hashable (Month (Hebrew n)) where
  hashWithSalt :: Int -> Month (Hebrew n) -> Int
hashWithSalt Int
s = Int -> Int -> Int
forall a. Hashable a => Int -> a -> Int
hashWithSalt Int
s (Int -> Int)
-> (Month (Hebrew n) -> Int) -> Month (Hebrew n) -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Month (Hebrew n) -> Int
forall a. Enum a => a -> Int
fromEnum

instance NFData (DayOfWeek (Hebrew n)) where
  rnf :: DayOfWeek (Hebrew n) -> ()
rnf DayOfWeek (Hebrew n)
d = DayOfWeek (Hebrew n)
d DayOfWeek (Hebrew n) -> () -> ()
forall a b. a -> b -> b
`seq` ()

instance Hashable (DayOfWeek (Hebrew n)) where
  hashWithSalt :: Int -> DayOfWeek (Hebrew n) -> Int
hashWithSalt Int
s = Int -> Int -> Int
forall a. Hashable a => Int -> a -> Int
hashWithSalt Int
s (Int -> Int)
-> (DayOfWeek (Hebrew n) -> Int) -> DayOfWeek (Hebrew n) -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DayOfWeek (Hebrew n) -> Int
forall a. Enum a => a -> Int
fromEnum

instance IsCalendarDateTime (Hebrew n) where
  fromAdjustedInstant :: Instant -> CalendarDateTime (Hebrew n)
fromAdjustedInstant (Instant Int32
days Word32
secs Word32
nsecs) = Date (Hebrew n) -> LocalTime -> CalendarDateTime (Hebrew n)
forall calendar.
Date calendar -> LocalTime -> CalendarDateTime calendar
CalendarDateTime (Int32 -> Date (Hebrew n)
forall (n :: MonthNumbering). Int32 -> Date (Hebrew n)
hebrewFromDays Int32
days) (Word32 -> Word32 -> LocalTime
LocalTime Word32
secs Word32
nsecs)
  toUnadjustedInstant :: CalendarDateTime (Hebrew n) -> Instant
toUnadjustedInstant (CalendarDateTime Date (Hebrew n)
hd (LocalTime Word32
secs Word32
nsecs)) = Int32 -> Word32 -> Word32 -> Instant
Instant (Date (Hebrew n) -> Int32
forall (n :: MonthNumbering). Date (Hebrew n) -> Int32
hebrewToDays Date (Hebrew n)
hd) Word32
secs Word32
nsecs

-- constructors

-- | Smart constructor for a date in the default civil-numbered Hebrew calendar.  Returns 'Nothing' if the day is out of
--   range for the month (including 'AdarI' in a common year) or the year is before 1.  Use @calendarDate'@ to select the
--   scriptural numbering.
calendarDate :: DayOfMonth -> Month HebrewCivil -> Year -> Maybe (CalendarDate HebrewCivil)
calendarDate :: Int -> Month HebrewCivil -> Int -> Maybe (CalendarDate HebrewCivil)
calendarDate = Int -> Month HebrewCivil -> Int -> Maybe (CalendarDate HebrewCivil)
forall (n :: MonthNumbering).
Int -> Month (Hebrew n) -> Int -> Maybe (CalendarDate (Hebrew n))
calendarDate'

-- | Smart constructor for a 'Hebrew' date in either numbering (chosen by the result type).  Returns 'Nothing' if the
--   day is out of range for the month (including 'AdarI' in a common year) or the year is before 1.
calendarDate' :: DayOfMonth -> Month (Hebrew n) -> Year -> Maybe (CalendarDate (Hebrew n))
calendarDate' :: forall (n :: MonthNumbering).
Int -> Month (Hebrew n) -> Int -> Maybe (CalendarDate (Hebrew n))
calendarDate' Int
d Month (Hebrew n)
m Int
y = do
  Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> Maybe ()) -> Bool -> Maybe ()
forall a b. (a -> b) -> a -> b
$ Int
y Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
1
  Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> Maybe ()) -> Bool -> Maybe ()
forall a b. (a -> b) -> a -> b
$ Int
d Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0 Bool -> Bool -> Bool
&& Int
d Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Month (Hebrew n) -> Int -> Int
forall (n :: MonthNumbering). Month (Hebrew n) -> Int -> Int
maxDaysInMonth Month (Hebrew n)
m Int
y
  let days :: Int
days = Int -> Int -> Int -> Int
hebrewYearMonthDayToDays Int
y (Month (Hebrew n) -> Int
forall (n :: MonthNumbering). Month (Hebrew n) -> Int
calendarIndex Month (Hebrew n)
m) Int
d
  Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> Maybe ()) -> Bool -> Maybe ()
forall a b. (a -> b) -> a -> b
$ Int
days Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
invalidDayThresh
  CalendarDate (Hebrew n) -> Maybe (CalendarDate (Hebrew n))
forall a. a -> Maybe a
forall (m :: * -> *) a. Monad m => a -> m a
return (CalendarDate (Hebrew n) -> Maybe (CalendarDate (Hebrew n)))
-> CalendarDate (Hebrew n) -> Maybe (CalendarDate (Hebrew n))
forall a b. (a -> b) -> a -> b
$ Int32 -> CalendarDate (Hebrew n)
forall (n :: MonthNumbering). Int32 -> Date (Hebrew n)
hebrewFromDays (Int -> Int32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
days)

-- | Smart constructor for the default civil calendar given as a day relative to a month (e.g. the third Monday).
--   Returns 'Nothing' if the resulting date is invalid.
fromNthDay :: DayNth -> DayOfWeek HebrewCivil -> Month HebrewCivil -> Year -> Maybe (CalendarDate HebrewCivil)
fromNthDay :: DayNth
-> DayOfWeek HebrewCivil
-> Month HebrewCivil
-> Int
-> Maybe (CalendarDate HebrewCivil)
fromNthDay = DayNth
-> DayOfWeek HebrewCivil
-> Month HebrewCivil
-> Int
-> Maybe (CalendarDate HebrewCivil)
forall (n :: MonthNumbering).
KnownNumbering n =>
DayNth
-> DayOfWeek (Hebrew n)
-> Month (Hebrew n)
-> Int
-> Maybe (CalendarDate (Hebrew n))
fromNthDay'

-- | As 'fromNthDay', but in either numbering (chosen by the result type).
fromNthDay' :: KnownNumbering n => DayNth -> DayOfWeek (Hebrew n) -> Month (Hebrew n) -> Year -> Maybe (CalendarDate (Hebrew n))
fromNthDay' :: forall (n :: MonthNumbering).
KnownNumbering n =>
DayNth
-> DayOfWeek (Hebrew n)
-> Month (Hebrew n)
-> Int
-> Maybe (CalendarDate (Hebrew n))
fromNthDay' = Int
-> DayOfWeek (Hebrew n)
-> (Int -> Month (Hebrew n) -> Int -> Int)
-> (Month (Hebrew n) -> Int -> Int)
-> (Int32 -> CalendarDate (Hebrew n))
-> DayNth
-> DayOfWeek (Hebrew n)
-> Month (Hebrew n)
-> Int
-> Maybe (CalendarDate (Hebrew n))
forall mon dow d.
(Enum mon, Enum dow) =>
Int
-> dow
-> (Int -> mon -> Int -> Int)
-> (mon -> Int -> Int)
-> (Int32 -> d)
-> DayNth
-> dow
-> mon
-> Int
-> Maybe d
mkFromNthDay Int
invalidDayThresh DayOfWeek (Hebrew n)
forall (n :: MonthNumbering). DayOfWeek (Hebrew n)
epochDayOfWeek Int -> Month (Hebrew n) -> Int -> Int
forall {n :: MonthNumbering}. Int -> Month (Hebrew n) -> Int -> Int
ymd Month (Hebrew n) -> Int -> Int
forall (n :: MonthNumbering). Month (Hebrew n) -> Int -> Int
mdim Int32 -> CalendarDate (Hebrew n)
forall (n :: MonthNumbering). Int32 -> Date (Hebrew n)
hebrewFromDays
  where
    ymd :: Int -> Month (Hebrew n) -> Int -> Int
ymd Int
y Month (Hebrew n)
m Int
d = Int -> Int -> Int -> Int
hebrewYearMonthDayToDays Int
y (Month (Hebrew n) -> Int
forall (n :: MonthNumbering). Month (Hebrew n) -> Int
calendarIndex Month (Hebrew n)
m) Int
d
    mdim :: Month (Hebrew n) -> Int -> Int
mdim Month (Hebrew n)
m Int
y = Month (Hebrew n) -> Int -> Int
forall (n :: MonthNumbering). Month (Hebrew n) -> Int -> Int
maxDaysInMonth Month (Hebrew n)
m Int
y

-- | Smart constructor for the default civil calendar given as a week date.  Weeks are taken to start on 'Sunday' (as in
--   the Hebrew week) and week 1 is the one containing 1.'Tishri'.
fromWeekDate :: WeekNumber -> DayOfWeek HebrewCivil -> Year -> Maybe (CalendarDate HebrewCivil)
fromWeekDate :: Int
-> DayOfWeek HebrewCivil -> Int -> Maybe (CalendarDate HebrewCivil)
fromWeekDate = Int
-> DayOfWeek HebrewCivil -> Int -> Maybe (CalendarDate HebrewCivil)
forall (n :: MonthNumbering).
Int
-> DayOfWeek (Hebrew n) -> Int -> Maybe (CalendarDate (Hebrew n))
fromWeekDate'

-- | As 'fromWeekDate', but in either numbering (chosen by the result type).
fromWeekDate' :: WeekNumber -> DayOfWeek (Hebrew n) -> Year -> Maybe (CalendarDate (Hebrew n))
fromWeekDate' :: forall (n :: MonthNumbering).
Int
-> DayOfWeek (Hebrew n) -> Int -> Maybe (CalendarDate (Hebrew n))
fromWeekDate' Int
weekNum DayOfWeek (Hebrew n)
dow Int
y = do
  Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> Maybe ()) -> Bool -> Maybe ()
forall a b. (a -> b) -> a -> b
$ Int
days Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
invalidDayThresh
  CalendarDate (Hebrew n) -> Maybe (CalendarDate (Hebrew n))
forall a. a -> Maybe a
forall (m :: * -> *) a. Monad m => a -> m a
return (CalendarDate (Hebrew n) -> Maybe (CalendarDate (Hebrew n)))
-> CalendarDate (Hebrew n) -> Maybe (CalendarDate (Hebrew n))
forall a b. (a -> b) -> a -> b
$ Int32 -> CalendarDate (Hebrew n)
forall (n :: MonthNumbering). Int32 -> Date (Hebrew n)
hebrewFromDays (Int -> Int32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
days)
    where
      startOfYear :: Int
startOfYear = Int -> Int -> Int -> Int
hebrewYearMonthDayToDays Int
y Int
0 Int
1                -- 1.Tishri (calendar-order index 0)
      startDoW :: Int
startDoW = DayOfWeek (Hebrew Any) -> Int -> Int
forall dow. Enum dow => dow -> Int -> Int
dayOfWeekFromDays DayOfWeek (Hebrew Any)
forall (n :: MonthNumbering). DayOfWeek (Hebrew n)
epochDayOfWeek Int
startOfYear
      weekStartDays :: Int
weekStartDays = Int
startOfYear Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
startDoW                      -- the Sunday on or before 1.Tishri
      days :: Int
days = Int
weekStartDays Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int -> Int
forall a. Enum a => a -> a
pred Int
weekNum Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
7 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ DayOfWeek (Hebrew n) -> Int
forall a. Enum a => a -> Int
fromEnum DayOfWeek (Hebrew n)
dow

-- helper functions

-- | The Hebrew months in calendar order, starting at 'Tishri': the single source of truth for month ordering.  Both
--   numbering conventions derive from it (civil counts from the head; scriptural is this cycle rotated to begin at
--   'Nisan'), so their 'Enum' numbers cannot drift out of step.
calendarMonths :: [Month (Hebrew n)]
calendarMonths :: forall (n :: MonthNumbering). [Month (Hebrew n)]
calendarMonths = [Month (Hebrew n)
forall (n :: MonthNumbering). Month (Hebrew n)
Tishri, Month (Hebrew n)
forall (n :: MonthNumbering). Month (Hebrew n)
Cheshvan, Month (Hebrew n)
forall (n :: MonthNumbering). Month (Hebrew n)
Kislev, Month (Hebrew n)
forall (n :: MonthNumbering). Month (Hebrew n)
Tevet, Month (Hebrew n)
forall (n :: MonthNumbering). Month (Hebrew n)
Shevat, Month (Hebrew n)
forall (n :: MonthNumbering). Month (Hebrew n)
AdarI, Month (Hebrew n)
forall (n :: MonthNumbering). Month (Hebrew n)
Adar, Month (Hebrew n)
forall (n :: MonthNumbering). Month (Hebrew n)
Nisan, Month (Hebrew n)
forall (n :: MonthNumbering). Month (Hebrew n)
Iyar, Month (Hebrew n)
forall (n :: MonthNumbering). Month (Hebrew n)
Sivan, Month (Hebrew n)
forall (n :: MonthNumbering). Month (Hebrew n)
Tammuz, Month (Hebrew n)
forall (n :: MonthNumbering). Month (Hebrew n)
Av, Month (Hebrew n)
forall (n :: MonthNumbering). Month (Hebrew n)
Elul]

-- | The number of month constructors (13: the twelve common-year months plus the leap month 'AdarI').
monthCount :: Int
monthCount :: Int
monthCount = [Month (Hebrew Any)] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Month (Hebrew Any)]
forall (n :: MonthNumbering). [Month (Hebrew n)]
calendarMonths

-- | A month's 0-based position in calendar order (from 'Tishri'), independent of the numbering convention.  This is
--   the internal, storage-facing ordinal (and the civil 'Enum' number).
calendarIndex :: Month (Hebrew n) -> Int
calendarIndex :: forall (n :: MonthNumbering). Month (Hebrew n) -> Int
calendarIndex Month (Hebrew n)
m = Maybe Int -> Int
forall a. HasCallStack => Maybe a -> a
fromJust (Month (Hebrew n) -> [Month (Hebrew n)] -> Maybe Int
forall a. Eq a => a -> [a] -> Maybe Int
elemIndex Month (Hebrew n)
m [Month (Hebrew n)]
forall (n :: MonthNumbering). [Month (Hebrew n)]
calendarMonths)

-- | Inverse of 'calendarIndex', checked against the valid 0..12 range.
monthAt :: Int -> Month (Hebrew n)
monthAt :: forall (n :: MonthNumbering). Int -> Month (Hebrew n)
monthAt Int
i
  | Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
0 Bool -> Bool -> Bool
&& Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
monthCount = [Month (Hebrew n)]
forall (n :: MonthNumbering). [Month (Hebrew n)]
calendarMonths [Month (Hebrew n)] -> Int -> Month (Hebrew n)
forall a. HasCallStack => [a] -> Int -> a
!! Int
i
  | Bool
otherwise               = String -> Month (Hebrew n)
forall a. HasCallStack => String -> a
error String
"Data.HodaTime.Calendar.Hebrew: month index out of range 0..12"

-- | Calendar-order index of the leap month 'AdarI'.
adarICalIndex :: Int
adarICalIndex :: Int
adarICalIndex = Int
5

-- | Calendar-order index of 'Adar' (\"Adar II\" in a leap year).
adarCalIndex :: Int
adarCalIndex :: Int
adarCalIndex = Int
6

-- | Hebrew dates are stored directly on the universal timeline (day 0 = 1.Mar.2000 Gregorian = Wednesday), so the
--   'Instant' bridge is the identity and the epoch weekday is that of the shared day 0.
epochDayOfWeek :: DayOfWeek (Hebrew n)
epochDayOfWeek :: forall (n :: MonthNumbering). DayOfWeek (Hebrew n)
epochDayOfWeek = DayOfWeek (Hebrew n)
forall (n :: MonthNumbering). DayOfWeek (Hebrew n)
Wednesday

-- | The day before 1.Tishri.1: a day is \"before the calendar starts\" when it is on or before this.
invalidDayThresh :: Int
invalidDayThresh :: Int
invalidDayThresh = Int -> Int
forall a. Enum a => a -> a
pred (Int -> Int
firstDayOfYear Int
1)

-- | Anchors the molad-based day count to the shared timeline: the universal flat day of 1.Tishri.1 (the Hebrew epoch,
--   Rata Die -1373427 = universal day -2103607) less @'elapsedDays' 1@ (which is 1).  So
--   @'firstDayOfYear' = 'hebrewRefDay' + 'elapsedDays'@.
hebrewRefDay :: Int
hebrewRefDay :: Int
hebrewRefDay = -Int
2103608

-- Molad and Rosh Hashanah

-- | A year is a leap year (thirteen months) in 7 of every 19 (years 3, 6, 8, 11, 14, 17 and 19 of the Metonic cycle).
isLeapYear :: Year -> Bool
isLeapYear :: Int -> Bool
isLeapYear Int
y = (Int
7 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
y Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
19 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
7

-- | Number of months in a year (12 common, 13 leap).
monthsInYear :: Year -> Int
monthsInYear :: Int -> Int
monthsInYear Int
y = if Int -> Bool
isLeapYear Int
y then Int
13 else Int
12

-- | Lunar months from the epoch molad to the molad of 'Tishri' of the given year.
monthsElapsed :: Year -> Int
monthsElapsed :: Int -> Int
monthsElapsed Int
year = Int
235 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
cycles Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
12 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
inCycle Int -> Int -> Int
forall a. Num a => a -> a -> a
+ (Int
7 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
inCycle Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
19
  where (Int
cycles, Int
inCycle) = (Int
year Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Int -> Int -> (Int, Int)
forall a. Integral a => a -> a -> (a, a)
`divMod` Int
19

-- | Days from the epoch molad to 1.Tishri of the given year after the four postponement rules (dechiyot): the molad
--   rules (molad zaken, and the GaTaRaD \/ BeTUTaKPaT year-length fixes) and \"lo ADU rosh\" (Rosh Hashanah may not
--   fall on Sunday, Wednesday or Friday).  A part (chelek) is 1\/1080 of an hour, so a day is 25920 parts.
elapsedDays :: Year -> Int
elapsedDays :: Int -> Int
elapsedDays Int
year = Int
aduAdjusted
  where
    m :: Int
m = Int -> Int
monthsElapsed Int
year
    partsElapsed :: Int
partsElapsed = Int
204 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
793 Int -> Int -> Int
forall a. Num a => a -> a -> a
* (Int
m Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
1080)
    hoursElapsed :: Int
hoursElapsed = Int
5 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
12 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
m Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
793 Int -> Int -> Int
forall a. Num a => a -> a -> a
* (Int
m Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
1080) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
partsElapsed Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
1080
    moladDay :: Int
moladDay = Int
1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
29 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
m Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
hoursElapsed Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
24
    moladParts :: Int
moladParts = Int
1080 Int -> Int -> Int
forall a. Num a => a -> a -> a
* (Int
hoursElapsed Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
24) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
partsElapsed Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
1080
    postponed :: Int
postponed
      | Int
moladParts Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
19440                                                   = Int
moladDay Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1   -- molad zaken (molad at or after 18h)
      | Int
moladDay Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
7 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
2 Bool -> Bool -> Bool
&& Int
moladParts Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
9924  Bool -> Bool -> Bool
&& Bool -> Bool
not (Int -> Bool
isLeapYear Int
year) = Int
moladDay Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1   -- GaTaRaD (Tue, 9h204p, common year)
      | Int
moladDay Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
7 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
1 Bool -> Bool -> Bool
&& Int
moladParts Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
16789 Bool -> Bool -> Bool
&& Int -> Bool
isLeapYear (Int
year Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) = Int
moladDay Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1   -- BeTUTaKPaT (Mon, 15h589p, year after leap)
      | Bool
otherwise                                                             = Int
moladDay
    aduAdjusted :: Int
aduAdjusted = if Int
postponed Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
7 Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Int
0, Int
3, Int
5] then Int
postponed Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1 else Int
postponed

-- | Universal flat day (day 0 = 1.Mar.2000 Gregorian) of 1.Tishri of the given year (Rosh Hashanah).
firstDayOfYear :: Year -> Int
firstDayOfYear :: Int -> Int
firstDayOfYear Int
year = Int
hebrewRefDay Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int -> Int
elapsedDays Int
year

-- | Length of the given year in days (353\/354\/355 common, 383\/384\/385 leap).
daysInYear :: Year -> Int
daysInYear :: Int -> Int
daysInYear Int
year = Int -> Int
firstDayOfYear (Int
year Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int -> Int
firstDayOfYear Int
year

-- | In a \"complete\" (shelemah) year 'Cheshvan' has 30 days instead of 29.
isCheshvanLong :: Year -> Bool
isCheshvanLong :: Int -> Bool
isCheshvanLong Int
year = Int -> Int
daysInYear Int
year Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
10 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
5

-- | In a \"deficient\" (chaserah) year 'Kislev' has 29 days instead of 30.
isKislevShort :: Year -> Bool
isKislevShort :: Int -> Bool
isKislevShort Int
year = Int -> Int
daysInYear Int
year Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
10 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
3

-- | Length of the month at the given calendar-order index in the given year (0 for 'AdarI' in a common year, so any
--   day in it is out of range).
monthLengthByIndex :: Year -> Int -> Int
monthLengthByIndex :: Int -> Int -> Int
monthLengthByIndex Int
year Int
ci = case Int
ci of
  Int
0  -> Int
30                                    -- Tishri
  Int
1  -> if Int -> Bool
isCheshvanLong Int
year then Int
30 else Int
29-- Cheshvan
  Int
2  -> if Int -> Bool
isKislevShort  Int
year then Int
29 else Int
30-- Kislev
  Int
3  -> Int
29                                    -- Tevet
  Int
4  -> Int
30                                    -- Shevat
  Int
5  -> if Int -> Bool
isLeapYear Int
year then Int
30 else Int
0     -- AdarI (leap years only)
  Int
6  -> Int
29                                    -- Adar (Adar II in leap years)
  Int
7  -> Int
30                                    -- Nisan
  Int
8  -> Int
29                                    -- Iyar
  Int
9  -> Int
30                                    -- Sivan
  Int
10 -> Int
29                                    -- Tammuz
  Int
11 -> Int
30                                    -- Av
  Int
12 -> Int
29                                    -- Elul
  Int
_  -> Int
0

-- | Maximum day for a month in a given year (0 for 'AdarI' in a common year, so such a date is always rejected).
maxDaysInMonth :: Month (Hebrew n) -> Year -> Int
maxDaysInMonth :: forall (n :: MonthNumbering). Month (Hebrew n) -> Int -> Int
maxDaysInMonth Month (Hebrew n)
m Int
year = Int -> Int -> Int
monthLengthByIndex Int
year (Month (Hebrew n) -> Int
forall (n :: MonthNumbering). Month (Hebrew n) -> Int
calendarIndex Month (Hebrew n)
m)

-- | Days elapsed in the year before the first of the month at the given calendar-order index.
daysBeforeMonth :: Year -> Int -> Int
daysBeforeMonth :: Int -> Int -> Int
daysBeforeMonth Int
year Int
ci = [Int] -> Int
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum [Int -> Int -> Int
monthLengthByIndex Int
year Int
i | Int
i <- [Int
0 .. Int
ci Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1]]

-- Date <-> day count

-- | Universal flat day (day 0 = 1.Mar.2000 Gregorian) of the given year, calendar-order month index and day.
hebrewYearMonthDayToDays :: Year -> Int -> DayOfMonth -> Int
hebrewYearMonthDayToDays :: Int -> Int -> Int -> Int
hebrewYearMonthDayToDays Int
year Int
ci Int
d = Int -> Int
firstDayOfYear Int
year Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int -> Int -> Int
daysBeforeMonth Int
year Int
ci Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
d Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1

-- | Decode a universal flat day to @(year, calendar-order month index, day)@.
hebrewDaysToYmd :: Int32 -> (Int32, Word8, Word8)
hebrewDaysToYmd :: Int32 -> (Int32, Word8, Word8)
hebrewDaysToYmd Int32
flatDays = (Int -> Int32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
year, Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
ci, Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
d)
  where
    n :: Int
n = Int32 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int32
flatDays :: Int
    year :: Int
year = Int -> Int
findYear (Int -> Int
estimate Int
n)
    (Int
ci, Int
d) = Int -> Int -> (Int, Int)
findMonth Int
0 (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int -> Int
firstDayOfYear Int
year)
    findMonth :: Int -> Int -> (Int, Int)
findMonth Int
i Int
remaining
      | Int
remaining Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
len = (Int
i, Int
remaining Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)                  -- a 0-length AdarI in a common year is skipped here
      | Bool
otherwise       = Int -> Int -> (Int, Int)
findMonth (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) (Int
remaining Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
len)
      where len :: Int
len = Int -> Int -> Int
monthLengthByIndex Int
year Int
i
    -- a Hebrew year averages ~365.25 days, so dividing by 366 gives a safe under-estimate to search up from
    estimate :: Int -> Int
estimate Int
d0 = Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
1 (Int -> Int) -> Int -> Int
forall a b. (a -> b) -> a -> b
$ (Int
d0 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int -> Int
firstDayOfYear Int
1) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
366 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
    findYear :: Int -> Int
findYear Int
y
      | Int -> Int
firstDayOfYear Int
y Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
n        = Int -> Int
findYear (Int
y Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)
      | Int -> Int
firstDayOfYear (Int
y Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
n = Int -> Int
findYear (Int
y Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
      | Bool
otherwise                   = Int
y

-- | Build the flat Hebrew date (denormalized: keeps the day count plus the decoded day\/calendar-month\/year).
hebrewFromDays :: Int32 -> Date (Hebrew n)
hebrewFromDays :: forall (n :: MonthNumbering). Int32 -> Date (Hebrew n)
hebrewFromDays Int32
flatDays = Int32 -> Word8 -> Word8 -> Int32 -> Date (Hebrew n)
forall (n :: MonthNumbering).
Int32 -> Word8 -> Word8 -> Int32 -> Date (Hebrew n)
HebrewDate Int32
flatDays Word8
d Word8
ci Int32
y
  where (Int32
y, Word8
ci, Word8
d) = Int32 -> (Int32, Word8, Word8)
hebrewDaysToYmd Int32
flatDays

hebrewToDays :: Date (Hebrew n) -> Int32
hebrewToDays :: forall (n :: MonthNumbering). Date (Hebrew n) -> Int32
hebrewToDays (HebrewDate Int32
flatDays Word8
_ Word8
_ Int32
_) = Int32
flatDays

hebrewToYmd :: Date (Hebrew n) -> (Int32, Word8, Word8)
hebrewToYmd :: forall (n :: MonthNumbering).
Date (Hebrew n) -> (Int32, Word8, Word8)
hebrewToYmd (HebrewDate Int32
_ Word8
d Word8
ci Int32
y) = (Int32
y, Word8
ci, Word8
d)

-- setters (Hebrew-specific: the shared helpers assume a fixed month count and that the stored month index equals the
-- numbering's Enum number, neither of which holds here, so these work in numbering-independent calendar-index space)

-- | Set the day of month, rolling overflow into the next month.
setHebrewDay :: DayOfMonth -> Date (Hebrew n) -> Date (Hebrew n)
setHebrewDay :: forall (n :: MonthNumbering).
Int -> Date (Hebrew n) -> Date (Hebrew n)
setHebrewDay Int
newDay Date (Hebrew n)
date = Int32 -> Date (Hebrew n)
forall (n :: MonthNumbering). Int32 -> Date (Hebrew n)
hebrewFromDays (Int -> Int32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
days)
  where
    (Int32
y, Word8
ci, Word8
_) = Date (Hebrew n) -> (Int32, Word8, Word8)
forall (n :: MonthNumbering).
Date (Hebrew n) -> (Int32, Word8, Word8)
hebrewToYmd Date (Hebrew n)
date
    startOfMonth :: Int
startOfMonth = Int -> Int
forall a. Enum a => a -> a
pred (Int -> Int) -> Int -> Int
forall a b. (a -> b) -> a -> b
$ Int -> Int -> Int -> Int
hebrewYearMonthDayToDays (Int32 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int32
y) (Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
ci) Int
1
    raw :: Int
raw = Int
startOfMonth Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
newDay
    days :: Int
days = if Int
raw Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
invalidDayThresh then Int
raw else Int
invalidDayThresh Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1

-- | Set the numbered month. Values outside the current year move in calendar order,
--   calendar order (carrying the year at 'Tishri' and skipping the absent 'AdarI' in common years), clamping the day.
setHebrewMonth :: Int -> Int -> Date (Hebrew n) -> Date (Hebrew n)
setHebrewMonth :: forall (n :: MonthNumbering).
Int -> Int -> Date (Hebrew n) -> Date (Hebrew n)
setHebrewMonth Int
start Int
target Date (Hebrew n)
date = Int32 -> Date (Hebrew n)
forall (n :: MonthNumbering). Int32 -> Date (Hebrew n)
hebrewFromDays (Int -> Int32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
days)
  where
    (Int32
y, Word8
ci, Word8
d) = Date (Hebrew n) -> (Int32, Word8, Word8)
forall (n :: MonthNumbering).
Date (Hebrew n) -> (Int32, Word8, Word8)
hebrewToYmd Date (Hebrew n)
date
    yr :: Int
yr = Int32 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int32
y
    cur :: Int
cur = Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
ci
    current :: Int
current = (Int
cur Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
start) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
monthCount
    (Int
y', Int
ci') = Int -> Int -> Int -> (Int, Int)
addMonthsChrono Int
yr Int
cur (Int
target Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
current)
    mdim :: Int
mdim = Int -> Int -> Int
monthLengthByIndex (Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
1 Int
y') Int
ci'
    d' :: Int
d' = Int -> Int -> Int
forall a. Ord a => a -> a -> a
min (Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
d) Int
mdim
    raw :: Int
raw = Int -> Int -> Int -> Int
hebrewYearMonthDayToDays (Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
1 Int
y') Int
ci' Int
d'
    days :: Int
days = if Int
raw Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
invalidDayThresh then Int
raw else Int
invalidDayThresh Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1

-- | Set the year, clamping the day and moving 'AdarI' to 'Adar' when necessary.
setHebrewYear :: Year -> Date (Hebrew n) -> Date (Hebrew n)
setHebrewYear :: forall (n :: MonthNumbering).
Int -> Date (Hebrew n) -> Date (Hebrew n)
setHebrewYear Int
newYear Date (Hebrew n)
date = Int32 -> Date (Hebrew n)
forall (n :: MonthNumbering). Int32 -> Date (Hebrew n)
hebrewFromDays (Int -> Int32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
days)
  where
    (Int32
_, Word8
ci, Word8
d) = Date (Hebrew n) -> (Int32, Word8, Word8)
forall (n :: MonthNumbering).
Date (Hebrew n) -> (Int32, Word8, Word8)
hebrewToYmd Date (Hebrew n)
date
    y' :: Int
y' = Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
1 Int
newYear
    ci' :: Int
ci' = if Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
ci Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
adarICalIndex Bool -> Bool -> Bool
&& Bool -> Bool
not (Int -> Bool
isLeapYear Int
y') then Int
adarCalIndex else Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
ci
    mdim :: Int
mdim = Int -> Int -> Int
monthLengthByIndex Int
y' Int
ci'
    d' :: Int
d' = Int -> Int -> Int
forall a. Ord a => a -> a -> a
min (Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
d) Int
mdim
    days :: Int
days = Int -> Int -> Int -> Int
hebrewYearMonthDayToDays Int
y' Int
ci' Int
d'

-- | Move a @(year, calendar-order month index)@ by a number of months in calendar order, carrying the year at 'Tishri'
--   and stepping over the absent 'AdarI' in common years.
addMonthsChrono :: Year -> Int -> Int -> (Year, Int)
addMonthsChrono :: Int -> Int -> Int -> (Int, Int)
addMonthsChrono Int
year Int
ci Int
delta = Int -> Int -> (Int, Int)
go Int
year (Int -> Int -> Int
calIndexToPos Int
year Int
ci Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
delta)
  where
    go :: Int -> Int -> (Int, Int)
go Int
y Int
p
      | Int
p Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0               = Int -> Int -> (Int, Int)
go (Int
y Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) (Int
p Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int -> Int
monthsInYear (Int
y Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1))
      | Int
p Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int -> Int
monthsInYear Int
y = Int -> Int -> (Int, Int)
go (Int
y Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) (Int
p Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int -> Int
monthsInYear Int
y)
      | Bool
otherwise           = (Int
y, Int -> Int -> Int
posToCalIndex Int
y Int
p)

-- | Calendar-order index to sequential position within the year (common years have no 'AdarI', so 'Adar' onward shift down).
calIndexToPos :: Year -> Int -> Int
calIndexToPos :: Int -> Int -> Int
calIndexToPos Int
year Int
ci
  | Int -> Bool
isLeapYear Int
year    = Int
ci
  | Int
ci Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
adarICalIndex = Int
ci
  | Bool
otherwise          = Int
ci Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1

-- | Inverse of 'calIndexToPos'.
posToCalIndex :: Year -> Int -> Int
posToCalIndex :: Int -> Int -> Int
posToCalIndex Int
year Int
p
  | Int -> Bool
isLeapYear Int
year   = Int
p
  | Int
p Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
adarICalIndex = Int
p
  | Bool
otherwise         = Int
p Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1