{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
-----------------------------------------------------------------------------
-- |
-- Module      :  Data.HodaTime.Calendar.Islamic
-- 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 'Islamic' (Hijri) calendar, a purely lunar calendar of twelve months.  The odd-numbered months ('Muharram', 'RabiAlAwwal', … ) have
-- 30 days and the even-numbered months ('Safar', 'RabiAlThani', … ) have 29, except that the final month ('DhulHijjah') gains a thirtieth day in a leap year.  A common year is therefore 354 days and a
-- leap year 355 — roughly eleven days shorter than a solar year, so Islamic dates drift steadily backwards through the seasons.  Year 1 begins on 18.Jul.622 CE (proleptic Gregorian), the year of the
-- Hijra; dates share the same absolute timeline as every other calendar.
--
-- == Which Islamic calendar this is, and the choices we made
--
-- There is no single \"Islamic calendar\": the religiously authoritative one is /observational/ (each month begins on the naked-eye sighting of the new crescent), which is inherently non-algorithmic and
-- varies by location, so it cannot be computed.  What software can compute is either the /tabular/ (arithmetic) calendar or a tabulated astronomical calendar such as Umm al-Qura.  This module implements
-- the __tabular arithmetic__ calendar.  A tabular calendar leaves two parameters open — the /leap-year pattern/ and the /epoch/ — and we treat them differently:
--
--     * __Leap-year pattern: selectable, defaulting to \"Base16\" (type II).__  A leap pattern says which 11 of every 30 years carry the extra day.  Four patterns are in common use, and the calendar is
--       parameterised over them at the /type level/ (see below), so a date always records which pattern built it and the type system refuses to mix incompatible ones.  The default, __Base16__ — leap years
--       2, 5, 7, 10, 13, 16, 18, 21, 24, 26 and 29 of each cycle — is the pattern used by the .NET BCL @HijriCalendar@ and NodaTime's @IslamicBcl@, so it is the most interoperable choice and the one we
--       cross-check against.
--
--     * __Epoch: fixed to astronomical (\"Thursday\") — 18.Jul.622 CE (proleptic Gregorian), Julian day 1948439.__  The alternative \"civil\" (\"Friday\") epoch is exactly one day later.  Unlike the leap
--       pattern, the epoch does not change the calendar's internal structure (month lengths, leap years, arithmetic); it only shifts how Islamic dates line up with the absolute timeline — i.e. their
--       'Data.HodaTime.Instant.Instant', their Gregorian correspondence and their day-of-week — by that one day.  Because it is a one-day alignment convention rather than a structurally different calendar,
--       we fix it (to the astronomical epoch, matching the .NET BCL and NodaTime) rather than expose it.  Were it ever wanted it would become a second type parameter in exactly the same way as the leap
--       pattern, a non-breaking change (today's @Islamic l@ would become a synonym for @Islamic l Astronomical@).
--
-- Being purely arithmetic, the calendar is exact by definition (there is no astronomical approximation, unlike the astronomical Persian calendar) and total for every year, so — like the Coptic calendar —
-- it is only floored at year 1 (the Hijra) and has no upper bound.  Note that the tabular calendar can differ from an actual crescent sighting, and from the Umm al-Qura calendar, by a day or two; if you
-- need to match observation you must use sighting data, which is outside the scope of an arithmetic calendar.
--
-- == Selecting a leap pattern
--
-- The calendar type carries the leap pattern as a type parameter of kind 'LeapPattern': @'Islamic' l@.  This is why ordinary, non-configurable calendars such as 'Data.HodaTime.Calendar.Gregorian.Gregorian'
-- are unaffected — only a calendar that actually has a choice to record gains a parameter, and it is always fully applied (e.g. @'CalendarDateTime' ('Islamic' 'Base15')@).  Because the parameter is phantom,
-- the month and weekday constructors ('Muharram', 'Sunday', … ) are shared across every variant, but two dates built with different patterns have different types and cannot be combined or compared.
--
-- For convenience each pattern has a type synonym — 'IslamicBcl' (the Base16 default), 'IslamicBase15', 'IslamicIndian' and 'IslamicHabashAlHasib' — and the constructors come in two forms:
--
--     * 'calendarDate', 'fromNthDay' and 'fromWeekDate' build the default 'IslamicBcl' calendar and need no annotation.
--
--     * @calendarDate'@, @fromNthDay'@ and @fromWeekDate'@ are polymorphic in the pattern; choose one with a type annotation or @TypeApplications@, e.g. @calendarDate' \@Base15 d m y@ or
--       @calendarDate' d m y :: Maybe ('CalendarDate' 'IslamicBase15')@.
----------------------------------------------------------------------------
module Data.HodaTime.Calendar.Islamic
(
  -- * Constructors (default 'IslamicBcl' calendar)
   calendarDate
  ,fromNthDay
  ,fromWeekDate
  -- * Constructors (choose the leap pattern)
  ,calendarDate'
  ,fromNthDay'
  ,fromWeekDate'
  -- * Types
  ,Month(..)
  ,DayOfWeek(..)
  ,Islamic
  ,LeapPattern(..)
  ,KnownLeap
  -- * Named calendars (leap-pattern type synonyms)
  ,IslamicBcl
  ,IslamicBase15
  ,IslamicBase16
  ,IslamicIndian
  ,IslamicHabashAlHasib
)
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 (mkCommonDaySetter, mkCommonMonthSetter, mkYearSetter, mkFromNthDay, mkFromWeekDate, moveByDow, dayOfWeekFromDays)
import Data.Bits ((.&.), shiftL, testBit, popCount)
import Data.Int (Int32)
import Data.Word (Word8)
import Control.Monad (guard)

-- constants

monthsPerYear :: Int
monthsPerYear :: Int
monthsPerYear = Int
12

daysPerNonLeapYear :: Int
daysPerNonLeapYear :: Int
daysPerNonLeapYear = Int
354

daysPerLeapYear :: Int
daysPerLeapYear :: Int
daysPerLeapYear = Int
355

-- | Days in one 30-year leap cycle: 19 common years of 354 days plus 11 leap years of 355.
daysPerCycle :: Int
daysPerCycle :: Int
daysPerCycle = Int
19 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
daysPerNonLeapYear Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
11 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
daysPerLeapYear   -- 10631

-- | The four tabular leap-year patterns in common use, used as the (kind-'LeapPattern') type parameter of 'Islamic'.
--   Each names which 11 of the 30 cycle years carry the extra day; 'Base16' is the .NET BCL \/ NodaTime default (see
--   the module header).
data LeapPattern = Base15 | Base16 | Indian | HabashAlHasib

-- | Reflects a 'LeapPattern' type down to its leap-year bit set: bit @n@ is set when year @n@ of the 30-year cycle
--   (0-based, so @year \`mod\` 30@) is a leap year.  Use @TypeApplications@ to read it, e.g. @'leapPatternBits' \@Base16@.
class KnownLeap (l :: LeapPattern) where
  leapPatternBits :: Int

instance KnownLeap 'Base15        where leapPatternBits :: Int
leapPatternBits = Int
623158436     -- leap years 2,5,7,10,13,15,18,21,24,26,29
instance KnownLeap 'Base16        where leapPatternBits :: Int
leapPatternBits = Int
623191204     -- leap years 2,5,7,10,13,16,18,21,24,26,29 (.NET BCL / NodaTime)
instance KnownLeap 'Indian        where leapPatternBits :: Int
leapPatternBits = Int
690562340     -- leap years 2,5,8,10,13,16,19,21,24,27,29
instance KnownLeap 'HabashAlHasib where leapPatternBits :: Int
leapPatternBits = Int
153692453     -- leap years 2,5,8,11,13,16,19,21,24,27,30

-- | Days elapsed before each 0-based month, ignoring the leap day (which only affects the final month's own length).
--   Odd-numbered (1-based) months have 30 days and even-numbered months 29.
islamicMonthDayOffsets :: [Int]
islamicMonthDayOffsets :: [Int]
islamicMonthDayOffsets = [Int
0, Int
30, Int
59, Int
89, Int
118, Int
148, Int
177, Int
207, Int
236, Int
266, Int
295, Int
325]

-- | Universal flat day (day 0 = 1.Mar.2000 Gregorian) of 1.Muharram.1 — the astronomical (\"Thursday\") epoch, Julian
--   day 1948439 = 18.Jul.622 CE (proleptic Gregorian).  Islamic dates are stored directly on the universal timeline, so
--   the 'Instant' bridge is the identity and this constant appears only inside the day\/date conversions.
islamicEpoch :: Int
islamicEpoch :: Int
islamicEpoch = -Int
503166

firstIslDayTuple :: (Integral a, Integral b, Integral c) => (a, b, c)
firstIslDayTuple :: forall a b c. (Integral a, Integral b, Integral c) => (a, b, c)
firstIslDayTuple = (a
1, b
0, c
1)        -- NOTE: 1.Muharram.1

-- | 1.Muharram.1 sits exactly on the epoch (year 1 has no preceding days and Muharram is the first month), so a day is
--   \"before the calendar starts\" when it is earlier than the epoch.  This threshold is independent of the leap pattern.
invalidDayThresh :: Integral a => a
invalidDayThresh :: forall a. Integral a => a
invalidDayThresh = Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Int
forall a. Enum a => a -> a
pred Int
islamicEpoch)

-- | Islamic 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.  It is shared by every leap
--   pattern (the parameter @l@ is phantom).
epochDayOfWeek :: DayOfWeek (Islamic l)
epochDayOfWeek :: forall (l :: LeapPattern). DayOfWeek (Islamic l)
epochDayOfWeek = DayOfWeek (Islamic l)
forall (l :: LeapPattern). DayOfWeek (Islamic l)
Wednesday

-- types

-- | The Islamic (Hijri) calendar, parameterised by its leap-year pattern (see 'LeapPattern' and the module header).
data Islamic (l :: LeapPattern)

-- | The Base15 tabular calendar.
type IslamicBase15        = Islamic 'Base15
-- | The Base16 tabular calendar (same as 'IslamicBcl').
type IslamicBase16        = Islamic 'Base16
-- | The Indian tabular calendar.
type IslamicIndian        = Islamic 'Indian
-- | The Habash al-Hasib tabular calendar.
type IslamicHabashAlHasib = Islamic 'HabashAlHasib
-- | The default Islamic calendar: the Base16 leap pattern, matching the .NET BCL @HijriCalendar@ and NodaTime's @IslamicBcl@.
type IslamicBcl           = Islamic 'Base16

instance KnownLeap l => IsCalendar (Islamic l) where
  data Date (Islamic l) = IslamicDate {-# UNPACK #-} !Int32 {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8 {-# UNPACK #-} !Int32
    deriving (Date (Islamic l) -> Date (Islamic l) -> Bool
(Date (Islamic l) -> Date (Islamic l) -> Bool)
-> (Date (Islamic l) -> Date (Islamic l) -> Bool)
-> Eq (Date (Islamic l))
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall (l :: LeapPattern).
Date (Islamic l) -> Date (Islamic l) -> Bool
$c== :: forall (l :: LeapPattern).
Date (Islamic l) -> Date (Islamic l) -> Bool
== :: Date (Islamic l) -> Date (Islamic l) -> Bool
$c/= :: forall (l :: LeapPattern).
Date (Islamic l) -> Date (Islamic l) -> Bool
/= :: Date (Islamic l) -> Date (Islamic l) -> Bool
Eq, Eq (Date (Islamic l))
Eq (Date (Islamic l)) =>
(Date (Islamic l) -> Date (Islamic l) -> Ordering)
-> (Date (Islamic l) -> Date (Islamic l) -> Bool)
-> (Date (Islamic l) -> Date (Islamic l) -> Bool)
-> (Date (Islamic l) -> Date (Islamic l) -> Bool)
-> (Date (Islamic l) -> Date (Islamic l) -> Bool)
-> (Date (Islamic l) -> Date (Islamic l) -> Date (Islamic l))
-> (Date (Islamic l) -> Date (Islamic l) -> Date (Islamic l))
-> Ord (Date (Islamic l))
Date (Islamic l) -> Date (Islamic l) -> Bool
Date (Islamic l) -> Date (Islamic l) -> Ordering
Date (Islamic l) -> Date (Islamic l) -> Date (Islamic l)
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 (l :: LeapPattern). Eq (Date (Islamic l))
forall (l :: LeapPattern).
Date (Islamic l) -> Date (Islamic l) -> Bool
forall (l :: LeapPattern).
Date (Islamic l) -> Date (Islamic l) -> Ordering
forall (l :: LeapPattern).
Date (Islamic l) -> Date (Islamic l) -> Date (Islamic l)
$ccompare :: forall (l :: LeapPattern).
Date (Islamic l) -> Date (Islamic l) -> Ordering
compare :: Date (Islamic l) -> Date (Islamic l) -> Ordering
$c< :: forall (l :: LeapPattern).
Date (Islamic l) -> Date (Islamic l) -> Bool
< :: Date (Islamic l) -> Date (Islamic l) -> Bool
$c<= :: forall (l :: LeapPattern).
Date (Islamic l) -> Date (Islamic l) -> Bool
<= :: Date (Islamic l) -> Date (Islamic l) -> Bool
$c> :: forall (l :: LeapPattern).
Date (Islamic l) -> Date (Islamic l) -> Bool
> :: Date (Islamic l) -> Date (Islamic l) -> Bool
$c>= :: forall (l :: LeapPattern).
Date (Islamic l) -> Date (Islamic l) -> Bool
>= :: Date (Islamic l) -> Date (Islamic l) -> Bool
$cmax :: forall (l :: LeapPattern).
Date (Islamic l) -> Date (Islamic l) -> Date (Islamic l)
max :: Date (Islamic l) -> Date (Islamic l) -> Date (Islamic l)
$cmin :: forall (l :: LeapPattern).
Date (Islamic l) -> Date (Islamic l) -> Date (Islamic l)
min :: Date (Islamic l) -> Date (Islamic l) -> Date (Islamic l)
Ord)

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

  data Month (Islamic l) = Muharram | Safar | RabiAlAwwal | RabiAlThani | JumadaAlAwwal | JumadaAlThani | Rajab | Shaban | Ramadan | Shawwal | DhulQadah | DhulHijjah
    deriving (Int -> Month (Islamic l) -> ShowS
[Month (Islamic l)] -> ShowS
Month (Islamic l) -> String
(Int -> Month (Islamic l) -> ShowS)
-> (Month (Islamic l) -> String)
-> ([Month (Islamic l)] -> ShowS)
-> Show (Month (Islamic l))
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall (l :: LeapPattern). Int -> Month (Islamic l) -> ShowS
forall (l :: LeapPattern). [Month (Islamic l)] -> ShowS
forall (l :: LeapPattern). Month (Islamic l) -> String
$cshowsPrec :: forall (l :: LeapPattern). Int -> Month (Islamic l) -> ShowS
showsPrec :: Int -> Month (Islamic l) -> ShowS
$cshow :: forall (l :: LeapPattern). Month (Islamic l) -> String
show :: Month (Islamic l) -> String
$cshowList :: forall (l :: LeapPattern). [Month (Islamic l)] -> ShowS
showList :: [Month (Islamic l)] -> ShowS
Show, ReadPrec [Month (Islamic l)]
ReadPrec (Month (Islamic l))
Int -> ReadS (Month (Islamic l))
ReadS [Month (Islamic l)]
(Int -> ReadS (Month (Islamic l)))
-> ReadS [Month (Islamic l)]
-> ReadPrec (Month (Islamic l))
-> ReadPrec [Month (Islamic l)]
-> Read (Month (Islamic l))
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
forall (l :: LeapPattern). ReadPrec [Month (Islamic l)]
forall (l :: LeapPattern). ReadPrec (Month (Islamic l))
forall (l :: LeapPattern). Int -> ReadS (Month (Islamic l))
forall (l :: LeapPattern). ReadS [Month (Islamic l)]
$creadsPrec :: forall (l :: LeapPattern). Int -> ReadS (Month (Islamic l))
readsPrec :: Int -> ReadS (Month (Islamic l))
$creadList :: forall (l :: LeapPattern). ReadS [Month (Islamic l)]
readList :: ReadS [Month (Islamic l)]
$creadPrec :: forall (l :: LeapPattern). ReadPrec (Month (Islamic l))
readPrec :: ReadPrec (Month (Islamic l))
$creadListPrec :: forall (l :: LeapPattern). ReadPrec [Month (Islamic l)]
readListPrec :: ReadPrec [Month (Islamic l)]
Read, Month (Islamic l) -> Month (Islamic l) -> Bool
(Month (Islamic l) -> Month (Islamic l) -> Bool)
-> (Month (Islamic l) -> Month (Islamic l) -> Bool)
-> Eq (Month (Islamic l))
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall (l :: LeapPattern).
Month (Islamic l) -> Month (Islamic l) -> Bool
$c== :: forall (l :: LeapPattern).
Month (Islamic l) -> Month (Islamic l) -> Bool
== :: Month (Islamic l) -> Month (Islamic l) -> Bool
$c/= :: forall (l :: LeapPattern).
Month (Islamic l) -> Month (Islamic l) -> Bool
/= :: Month (Islamic l) -> Month (Islamic l) -> Bool
Eq, Eq (Month (Islamic l))
Eq (Month (Islamic l)) =>
(Month (Islamic l) -> Month (Islamic l) -> Ordering)
-> (Month (Islamic l) -> Month (Islamic l) -> Bool)
-> (Month (Islamic l) -> Month (Islamic l) -> Bool)
-> (Month (Islamic l) -> Month (Islamic l) -> Bool)
-> (Month (Islamic l) -> Month (Islamic l) -> Bool)
-> (Month (Islamic l) -> Month (Islamic l) -> Month (Islamic l))
-> (Month (Islamic l) -> Month (Islamic l) -> Month (Islamic l))
-> Ord (Month (Islamic l))
Month (Islamic l) -> Month (Islamic l) -> Bool
Month (Islamic l) -> Month (Islamic l) -> Ordering
Month (Islamic l) -> Month (Islamic l) -> Month (Islamic l)
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 (l :: LeapPattern). Eq (Month (Islamic l))
forall (l :: LeapPattern).
Month (Islamic l) -> Month (Islamic l) -> Bool
forall (l :: LeapPattern).
Month (Islamic l) -> Month (Islamic l) -> Ordering
forall (l :: LeapPattern).
Month (Islamic l) -> Month (Islamic l) -> Month (Islamic l)
$ccompare :: forall (l :: LeapPattern).
Month (Islamic l) -> Month (Islamic l) -> Ordering
compare :: Month (Islamic l) -> Month (Islamic l) -> Ordering
$c< :: forall (l :: LeapPattern).
Month (Islamic l) -> Month (Islamic l) -> Bool
< :: Month (Islamic l) -> Month (Islamic l) -> Bool
$c<= :: forall (l :: LeapPattern).
Month (Islamic l) -> Month (Islamic l) -> Bool
<= :: Month (Islamic l) -> Month (Islamic l) -> Bool
$c> :: forall (l :: LeapPattern).
Month (Islamic l) -> Month (Islamic l) -> Bool
> :: Month (Islamic l) -> Month (Islamic l) -> Bool
$c>= :: forall (l :: LeapPattern).
Month (Islamic l) -> Month (Islamic l) -> Bool
>= :: Month (Islamic l) -> Month (Islamic l) -> Bool
$cmax :: forall (l :: LeapPattern).
Month (Islamic l) -> Month (Islamic l) -> Month (Islamic l)
max :: Month (Islamic l) -> Month (Islamic l) -> Month (Islamic l)
$cmin :: forall (l :: LeapPattern).
Month (Islamic l) -> Month (Islamic l) -> Month (Islamic l)
min :: Month (Islamic l) -> Month (Islamic l) -> Month (Islamic l)
Ord, Int -> Month (Islamic l)
Month (Islamic l) -> Int
Month (Islamic l) -> [Month (Islamic l)]
Month (Islamic l) -> Month (Islamic l)
Month (Islamic l) -> Month (Islamic l) -> [Month (Islamic l)]
Month (Islamic l)
-> Month (Islamic l) -> Month (Islamic l) -> [Month (Islamic l)]
(Month (Islamic l) -> Month (Islamic l))
-> (Month (Islamic l) -> Month (Islamic l))
-> (Int -> Month (Islamic l))
-> (Month (Islamic l) -> Int)
-> (Month (Islamic l) -> [Month (Islamic l)])
-> (Month (Islamic l) -> Month (Islamic l) -> [Month (Islamic l)])
-> (Month (Islamic l) -> Month (Islamic l) -> [Month (Islamic l)])
-> (Month (Islamic l)
    -> Month (Islamic l) -> Month (Islamic l) -> [Month (Islamic l)])
-> Enum (Month (Islamic l))
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 (l :: LeapPattern). Int -> Month (Islamic l)
forall (l :: LeapPattern). Month (Islamic l) -> Int
forall (l :: LeapPattern). Month (Islamic l) -> [Month (Islamic l)]
forall (l :: LeapPattern). Month (Islamic l) -> Month (Islamic l)
forall (l :: LeapPattern).
Month (Islamic l) -> Month (Islamic l) -> [Month (Islamic l)]
forall (l :: LeapPattern).
Month (Islamic l)
-> Month (Islamic l) -> Month (Islamic l) -> [Month (Islamic l)]
$csucc :: forall (l :: LeapPattern). Month (Islamic l) -> Month (Islamic l)
succ :: Month (Islamic l) -> Month (Islamic l)
$cpred :: forall (l :: LeapPattern). Month (Islamic l) -> Month (Islamic l)
pred :: Month (Islamic l) -> Month (Islamic l)
$ctoEnum :: forall (l :: LeapPattern). Int -> Month (Islamic l)
toEnum :: Int -> Month (Islamic l)
$cfromEnum :: forall (l :: LeapPattern). Month (Islamic l) -> Int
fromEnum :: Month (Islamic l) -> Int
$cenumFrom :: forall (l :: LeapPattern). Month (Islamic l) -> [Month (Islamic l)]
enumFrom :: Month (Islamic l) -> [Month (Islamic l)]
$cenumFromThen :: forall (l :: LeapPattern).
Month (Islamic l) -> Month (Islamic l) -> [Month (Islamic l)]
enumFromThen :: Month (Islamic l) -> Month (Islamic l) -> [Month (Islamic l)]
$cenumFromTo :: forall (l :: LeapPattern).
Month (Islamic l) -> Month (Islamic l) -> [Month (Islamic l)]
enumFromTo :: Month (Islamic l) -> Month (Islamic l) -> [Month (Islamic l)]
$cenumFromThenTo :: forall (l :: LeapPattern).
Month (Islamic l)
-> Month (Islamic l) -> Month (Islamic l) -> [Month (Islamic l)]
enumFromThenTo :: Month (Islamic l)
-> Month (Islamic l) -> Month (Islamic l) -> [Month (Islamic l)]
Enum, Month (Islamic l)
Month (Islamic l)
-> Month (Islamic l) -> Bounded (Month (Islamic l))
forall a. a -> a -> Bounded a
forall (l :: LeapPattern). Month (Islamic l)
$cminBound :: forall (l :: LeapPattern). Month (Islamic l)
minBound :: Month (Islamic l)
$cmaxBound :: forall (l :: LeapPattern). Month (Islamic l)
maxBound :: Month (Islamic l)
Bounded)

  fromDays :: Int32 -> Date (Islamic l)
fromDays = Int -> Int32 -> Date (Islamic l)
forall (l :: LeapPattern). Int -> Int32 -> Date (Islamic l)
islamicFromDays (forall (l :: LeapPattern). KnownLeap l => Int
leapPatternBits @l)
  toDays :: Date (Islamic l) -> Int32
toDays = Date (Islamic l) -> Int32
forall (l :: LeapPattern). Date (Islamic l) -> Int32
islamicToDays
  toYmd :: Date (Islamic l) -> (Int32, Word8, Word8)
toYmd = Date (Islamic l) -> (Int32, Word8, Word8)
forall (l :: LeapPattern).
Date (Islamic l) -> (Int32, Word8, Word8)
islamicToYmd
  calendarName :: Date (Islamic l) -> String
calendarName Date (Islamic l)
_ = String
"Islamic"

  day' :: Date (Islamic l) -> Int
day' (IslamicDate Int32
_ Word8
d Word8
_ Int32
_) = Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
d
  setDay' :: Int -> Date (Islamic l) -> Date (Islamic l)
setDay' = let b :: Int
b = forall (l :: LeapPattern). KnownLeap l => Int
leapPatternBits @l in Int
-> (Int -> Month (Islamic Any) -> Int -> Int)
-> (Int32 -> Date (Islamic l))
-> (Date (Islamic l) -> (Int32, Word8, Word8))
-> Int
-> Date (Islamic l)
-> Date (Islamic l)
forall mon d.
Enum mon =>
Int
-> (Int -> mon -> Int -> Int)
-> (Int32 -> d)
-> (d -> (Int32, Word8, Word8))
-> Int
-> d
-> d
mkCommonDaySetter Int
forall a. Integral a => a
invalidDayThresh (Int -> Int -> Month (Islamic Any) -> Int -> Int
forall (l :: LeapPattern).
Int -> Int -> Month (Islamic l) -> Int -> Int
yearMonthDayToDays Int
b) (Int -> Int32 -> Date (Islamic l)
forall (l :: LeapPattern). Int -> Int32 -> Date (Islamic l)
islamicFromDays Int
b) Date (Islamic l) -> (Int32, Word8, Word8)
forall (l :: LeapPattern).
Date (Islamic l) -> (Int32, Word8, Word8)
islamicToYmd
  {-# INLINE day' #-}

  month' :: Date (Islamic l) -> Month (Islamic l)
month' (IslamicDate Int32
_ Word8
_ Word8
m Int32
_) = Int -> Month (Islamic l)
forall a. Enum a => Int -> a
toEnum (Int -> Month (Islamic l))
-> (Word8 -> Int) -> Word8 -> Month (Islamic l)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8 -> Month (Islamic l)) -> Word8 -> Month (Islamic l)
forall a b. (a -> b) -> a -> b
$ Word8
m
  setMonthIndex' :: Int -> Date (Islamic l) -> Date (Islamic l)
setMonthIndex' = let b :: Int
b = forall (l :: LeapPattern). KnownLeap l => Int
leapPatternBits @l in Int
-> (Int, Int, Word8)
-> (Month (Islamic Any) -> Int -> Int)
-> (Int -> Month (Islamic Any) -> Int -> Int)
-> (Date (Islamic l) -> (Int32, Word8, Word8))
-> (Int32 -> Date (Islamic l))
-> Int
-> Date (Islamic l)
-> Date (Islamic l)
forall mon d.
Enum mon =>
Int
-> (Int, Int, Word8)
-> (mon -> Int -> Int)
-> (Int -> mon -> Int -> Int)
-> (d -> (Int32, Word8, Word8))
-> (Int32 -> d)
-> Int
-> d
-> d
mkCommonMonthSetter Int
monthsPerYear (Int, Int, Word8)
forall a b c. (Integral a, Integral b, Integral c) => (a, b, c)
firstIslDayTuple (Int -> Month (Islamic Any) -> Int -> Int
forall (l :: LeapPattern). Int -> Month (Islamic l) -> Int -> Int
maxDaysInMonth Int
b) (Int -> Int -> Month (Islamic Any) -> Int -> Int
forall (l :: LeapPattern).
Int -> Int -> Month (Islamic l) -> Int -> Int
yearMonthDayToDays Int
b) Date (Islamic l) -> (Int32, Word8, Word8)
forall (l :: LeapPattern).
Date (Islamic l) -> (Int32, Word8, Word8)
islamicToYmd (Int -> Int32 -> Date (Islamic l)
forall (l :: LeapPattern). Int -> Int32 -> Date (Islamic l)
islamicFromDays Int
b)
  {-# INLINE month' #-}

  year' :: Date (Islamic l) -> Int
year' (IslamicDate Int32
_ Word8
_ Word8
_ Int32
y) = Int32 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int32
y
  setYear' :: Int -> Date (Islamic l) -> Date (Islamic l)
setYear' = let b :: Int
b = forall (l :: LeapPattern). KnownLeap l => Int
leapPatternBits @l in (Int, Word8, Word8)
-> (Month (Islamic Any) -> Int -> Int)
-> (Int -> Month (Islamic Any) -> Int -> Int)
-> (Date (Islamic l) -> (Int32, Word8, Word8))
-> (Int32 -> Date (Islamic l))
-> Int
-> Date (Islamic l)
-> Date (Islamic l)
forall mon d.
Enum mon =>
(Int, Word8, Word8)
-> (mon -> Int -> Int)
-> (Int -> mon -> Int -> Int)
-> (d -> (Int32, Word8, Word8))
-> (Int32 -> d)
-> Int
-> d
-> d
mkYearSetter (Int, Word8, Word8)
forall a b c. (Integral a, Integral b, Integral c) => (a, b, c)
firstIslDayTuple (Int -> Month (Islamic Any) -> Int -> Int
forall (l :: LeapPattern). Int -> Month (Islamic l) -> Int -> Int
maxDaysInMonth Int
b) (Int -> Int -> Month (Islamic Any) -> Int -> Int
forall (l :: LeapPattern).
Int -> Int -> Month (Islamic l) -> Int -> Int
yearMonthDayToDays Int
b) Date (Islamic l) -> (Int32, Word8, Word8)
forall (l :: LeapPattern).
Date (Islamic l) -> (Int32, Word8, Word8)
islamicToYmd (Int -> Int32 -> Date (Islamic l)
forall (l :: LeapPattern). Int -> Int32 -> Date (Islamic l)
islamicFromDays Int
b)
  {-# INLINE year' #-}

  dayOfWeek' :: Date (Islamic l) -> DayOfWeek (Islamic l)
dayOfWeek' (IslamicDate Int32
days Word8
_ Word8
_ Int32
_) = Int -> DayOfWeek (Islamic l)
forall a. Enum a => Int -> a
toEnum (Int -> DayOfWeek (Islamic l))
-> (Int32 -> Int) -> Int32 -> DayOfWeek (Islamic l)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DayOfWeek (Islamic Any) -> Int -> Int
forall dow. Enum dow => dow -> Int -> Int
dayOfWeekFromDays DayOfWeek (Islamic Any)
forall (l :: LeapPattern). DayOfWeek (Islamic l)
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 (Islamic l)) -> Int32 -> DayOfWeek (Islamic l)
forall a b. (a -> b) -> a -> b
$ Int32
days

  next' :: Int
-> DayOfWeek (Islamic l) -> Date (Islamic l) -> Date (Islamic l)
next' Int
n DayOfWeek (Islamic l)
dow (IslamicDate Int32
days Word8
_ Word8
_ Int32
_) = (Int32 -> Date (Islamic l))
-> DayOfWeek (Islamic l)
-> Int
-> DayOfWeek (Islamic l)
-> (Int -> Int -> Int)
-> (Int -> Int -> Int)
-> (Int -> Int -> Bool)
-> Int
-> Date (Islamic l)
forall dow d.
Enum dow =>
(Int32 -> d)
-> dow
-> Int
-> dow
-> (Int -> Int -> Int)
-> (Int -> Int -> Int)
-> (Int -> Int -> Bool)
-> Int
-> d
moveByDow (Int -> Int32 -> Date (Islamic l)
forall (l :: LeapPattern). Int -> Int32 -> Date (Islamic l)
islamicFromDays (forall (l :: LeapPattern). KnownLeap l => Int
leapPatternBits @l)) DayOfWeek (Islamic l)
forall (l :: LeapPattern). DayOfWeek (Islamic l)
epochDayOfWeek Int
n DayOfWeek (Islamic l)
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 (Islamic l) -> Date (Islamic l) -> Date (Islamic l)
previous' Int
n DayOfWeek (Islamic l)
dow (IslamicDate Int32
days Word8
_ Word8
_ Int32
_) = (Int32 -> Date (Islamic l))
-> DayOfWeek (Islamic l)
-> Int
-> DayOfWeek (Islamic l)
-> (Int -> Int -> Int)
-> (Int -> Int -> Int)
-> (Int -> Int -> Bool)
-> Int
-> Date (Islamic l)
forall dow d.
Enum dow =>
(Int32 -> d)
-> dow
-> Int
-> dow
-> (Int -> Int -> Int)
-> (Int -> Int -> Int)
-> (Int -> Int -> Bool)
-> Int
-> d
moveByDow (Int -> Int32 -> Date (Islamic l)
forall (l :: LeapPattern). Int -> Int32 -> Date (Islamic l)
islamicFromDays (forall (l :: LeapPattern). KnownLeap l => Int
leapPatternBits @l)) DayOfWeek (Islamic l)
forall (l :: LeapPattern). DayOfWeek (Islamic l)
epochDayOfWeek Int
n DayOfWeek (Islamic l)
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

instance NFData (Date (Islamic l)) where
  rnf :: Date (Islamic l) -> ()
rnf (IslamicDate 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 (Islamic l)) where
  hashWithSalt :: Int -> Date (Islamic l) -> Int
hashWithSalt Int
s (IslamicDate 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 (Islamic l)) where
  rnf :: Month (Islamic l) -> ()
rnf Month (Islamic l)
m = Month (Islamic l)
m Month (Islamic l) -> () -> ()
forall a b. a -> b -> b
`seq` ()

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

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

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

instance KnownLeap l => IsCalendarDateTime (Islamic l) where
  fromAdjustedInstant :: Instant -> CalendarDateTime (Islamic l)
fromAdjustedInstant (Instant Int32
days Word32
secs Word32
nsecs) = Date (Islamic l) -> LocalTime -> CalendarDateTime (Islamic l)
forall calendar.
Date calendar -> LocalTime -> CalendarDateTime calendar
CalendarDateTime (Int -> Int32 -> Date (Islamic l)
forall (l :: LeapPattern). Int -> Int32 -> Date (Islamic l)
islamicFromDays (forall (l :: LeapPattern). KnownLeap l => Int
leapPatternBits @l) Int32
days) (Word32 -> Word32 -> LocalTime
LocalTime Word32
secs Word32
nsecs)
  toUnadjustedInstant :: CalendarDateTime (Islamic l) -> Instant
toUnadjustedInstant (CalendarDateTime Date (Islamic l)
isd (LocalTime Word32
secs Word32
nsecs)) = Int32 -> Word32 -> Word32 -> Instant
Instant (Date (Islamic l) -> Int32
forall (l :: LeapPattern). Date (Islamic l) -> Int32
islamicToDays Date (Islamic l)
isd) Word32
secs Word32
nsecs

-- | Build the flat Islamic date (denormalized: keeps the day count plus the decoded day\/month\/year).
islamicFromDays :: Int -> Int32 -> Date (Islamic l)
islamicFromDays :: forall (l :: LeapPattern). Int -> Int32 -> Date (Islamic l)
islamicFromDays Int
bits Int32
days = Int32 -> Word8 -> Word8 -> Int32 -> Date (Islamic l)
forall (l :: LeapPattern).
Int32 -> Word8 -> Word8 -> Int32 -> Date (Islamic l)
IslamicDate Int32
days Word8
d Word8
m Int32
y
  where (Int32
y, Word8
m, Word8
d) = Int -> Int32 -> (Int32, Word8, Word8)
daysToYearMonthDay Int
bits Int32
days

islamicToDays :: Date (Islamic l) -> Int32
islamicToDays :: forall (l :: LeapPattern). Date (Islamic l) -> Int32
islamicToDays (IslamicDate Int32
days Word8
_ Word8
_ Int32
_) = Int32
days

islamicToYmd :: Date (Islamic l) -> (Int32, Word8, Word8)
islamicToYmd :: forall (l :: LeapPattern).
Date (Islamic l) -> (Int32, Word8, Word8)
islamicToYmd (IslamicDate Int32
_ Word8
d Word8
m Int32
y) = (Int32
y, Word8
m, Word8
d)

-- Constructors

-- | Smart constructor for the default 'IslamicBcl' calendar date.  Returns 'Nothing' if the day is out of range for the
--   month or the year is before the epoch (year 1).  Use @calendarDate'@ to pick a different leap pattern.
calendarDate :: DayOfMonth -> Month IslamicBcl -> Year -> Maybe (CalendarDate IslamicBcl)
calendarDate :: Int -> Month IslamicBcl -> Int -> Maybe (CalendarDate IslamicBcl)
calendarDate = Int -> Month IslamicBcl -> Int -> Maybe (CalendarDate IslamicBcl)
forall (l :: LeapPattern).
KnownLeap l =>
Int -> Month (Islamic l) -> Int -> Maybe (CalendarDate (Islamic l))
calendarDate'

-- | Smart constructor for an 'Islamic' calendar date in any leap pattern (chosen by the result type).  Returns 'Nothing'
--   if the day is out of range for the month or the year is before the epoch (year 1).
calendarDate' :: forall l. KnownLeap l => DayOfMonth -> Month (Islamic l) -> Year -> Maybe (CalendarDate (Islamic l))
calendarDate' :: forall (l :: LeapPattern).
KnownLeap l =>
Int -> Month (Islamic l) -> Int -> Maybe (CalendarDate (Islamic l))
calendarDate' Int
d Month (Islamic l)
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
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
<= Int -> Month (Islamic l) -> Int -> Int
forall (l :: LeapPattern). Int -> Month (Islamic l) -> Int -> Int
maxDaysInMonth Int
bits Month (Islamic l)
m Int
y
  let days :: Int32
days = Int -> Int32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Int32) -> Int -> Int32
forall a b. (a -> b) -> a -> b
$ Int -> Int -> Month (Islamic l) -> Int -> Int
forall (l :: LeapPattern).
Int -> Int -> Month (Islamic l) -> Int -> Int
yearMonthDayToDays Int
bits Int
y Month (Islamic l)
m Int
d
  Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> Maybe ()) -> Bool -> Maybe ()
forall a b. (a -> b) -> a -> b
$ Int32
days Int32 -> Int32 -> Bool
forall a. Ord a => a -> a -> Bool
> Int32
forall a. Integral a => a
invalidDayThresh
  CalendarDate (Islamic l) -> Maybe (CalendarDate (Islamic l))
forall a. a -> Maybe a
forall (m :: * -> *) a. Monad m => a -> m a
return (CalendarDate (Islamic l) -> Maybe (CalendarDate (Islamic l)))
-> CalendarDate (Islamic l) -> Maybe (CalendarDate (Islamic l))
forall a b. (a -> b) -> a -> b
$ Int -> Int32 -> CalendarDate (Islamic l)
forall (l :: LeapPattern). Int -> Int32 -> Date (Islamic l)
islamicFromDays Int
bits Int32
days
  where bits :: Int
bits = forall (l :: LeapPattern). KnownLeap l => Int
leapPatternBits @l

-- | Smart constructor for the default 'IslamicBcl' calendar date given as a day relative to a month (e.g. the third Monday of the month).  Returns 'Nothing' if the resulting date is invalid.
fromNthDay :: DayNth -> DayOfWeek IslamicBcl -> Month IslamicBcl -> Year -> Maybe (CalendarDate IslamicBcl)
fromNthDay :: DayNth
-> DayOfWeek IslamicBcl
-> Month IslamicBcl
-> Int
-> Maybe (CalendarDate IslamicBcl)
fromNthDay = DayNth
-> DayOfWeek IslamicBcl
-> Month IslamicBcl
-> Int
-> Maybe (CalendarDate IslamicBcl)
forall (l :: LeapPattern).
KnownLeap l =>
DayNth
-> DayOfWeek (Islamic l)
-> Month (Islamic l)
-> Int
-> Maybe (CalendarDate (Islamic l))
fromNthDay'

-- | As 'fromNthDay', but in any leap pattern (chosen by the result type).
fromNthDay' :: forall l. KnownLeap l => DayNth -> DayOfWeek (Islamic l) -> Month (Islamic l) -> Year -> Maybe (CalendarDate (Islamic l))
fromNthDay' :: forall (l :: LeapPattern).
KnownLeap l =>
DayNth
-> DayOfWeek (Islamic l)
-> Month (Islamic l)
-> Int
-> Maybe (CalendarDate (Islamic l))
fromNthDay' = Int
-> DayOfWeek (Islamic l)
-> (Int -> Month (Islamic l) -> Int -> Int)
-> (Month (Islamic l) -> Int -> Int)
-> (Int32 -> CalendarDate (Islamic l))
-> DayNth
-> DayOfWeek (Islamic l)
-> Month (Islamic l)
-> Int
-> Maybe (CalendarDate (Islamic l))
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
forall a. Integral a => a
invalidDayThresh DayOfWeek (Islamic l)
forall (l :: LeapPattern). DayOfWeek (Islamic l)
epochDayOfWeek (Int -> Int -> Month (Islamic l) -> Int -> Int
forall (l :: LeapPattern).
Int -> Int -> Month (Islamic l) -> Int -> Int
yearMonthDayToDays Int
bits) (Int -> Month (Islamic l) -> Int -> Int
forall (l :: LeapPattern). Int -> Month (Islamic l) -> Int -> Int
maxDaysInMonth Int
bits) (Int -> Int32 -> CalendarDate (Islamic l)
forall (l :: LeapPattern). Int -> Int32 -> Date (Islamic l)
islamicFromDays Int
bits)
  where bits :: Int
bits = forall (l :: LeapPattern). KnownLeap l => Int
leapPatternBits @l

-- | Smart constructor for the default 'IslamicBcl' calendar date given as a week date.  Note that this method assumes weeks start on Saturday (as in the Islamic calendar) and the first week of the year is
--   the one which has at least one day in the new year.
fromWeekDate :: WeekNumber -> DayOfWeek IslamicBcl -> Year -> Maybe (CalendarDate IslamicBcl)
fromWeekDate :: Int
-> DayOfWeek IslamicBcl -> Int -> Maybe (CalendarDate IslamicBcl)
fromWeekDate = Int
-> DayOfWeek IslamicBcl -> Int -> Maybe (CalendarDate IslamicBcl)
forall (l :: LeapPattern).
KnownLeap l =>
Int
-> DayOfWeek (Islamic l) -> Int -> Maybe (CalendarDate (Islamic l))
fromWeekDate'

-- | As 'fromWeekDate', but in any leap pattern (chosen by the result type).
fromWeekDate' :: forall l. KnownLeap l => WeekNumber -> DayOfWeek (Islamic l) -> Year -> Maybe (CalendarDate (Islamic l))
fromWeekDate' :: forall (l :: LeapPattern).
KnownLeap l =>
Int
-> DayOfWeek (Islamic l) -> Int -> Maybe (CalendarDate (Islamic l))
fromWeekDate' = Int
-> DayOfWeek (Islamic l)
-> (Int -> Month (Islamic Any) -> Int -> Int)
-> (Int32 -> CalendarDate (Islamic l))
-> Int
-> DayOfWeek (Islamic l)
-> Int
-> DayOfWeek (Islamic l)
-> Int
-> Maybe (CalendarDate (Islamic l))
forall mon dow d.
(Enum mon, Enum dow) =>
Int
-> dow
-> (Int -> mon -> Int -> Int)
-> (Int32 -> d)
-> Int
-> dow
-> Int
-> dow
-> Int
-> Maybe d
mkFromWeekDate Int
forall a. Integral a => a
invalidDayThresh DayOfWeek (Islamic l)
forall (l :: LeapPattern). DayOfWeek (Islamic l)
epochDayOfWeek (Int -> Int -> Month (Islamic Any) -> Int -> Int
forall (l :: LeapPattern).
Int -> Int -> Month (Islamic l) -> Int -> Int
yearMonthDayToDays Int
bits) (Int -> Int32 -> CalendarDate (Islamic l)
forall (l :: LeapPattern). Int -> Int32 -> Date (Islamic l)
islamicFromDays Int
bits) Int
1 DayOfWeek (Islamic l)
forall (l :: LeapPattern). DayOfWeek (Islamic l)
Saturday
  where bits :: Int
bits = forall (l :: LeapPattern). KnownLeap l => Int
leapPatternBits @l

-- helper functions

-- | A year is a leap year when the bit at @year \`mod\` 30@ of the given leap-pattern bit set is set.
isLeapYear :: Int -> Year -> Bool
isLeapYear :: Int -> Int -> Bool
isLeapYear Int
bits Int
y = Int -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit Int
bits (Int -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
y Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
30))

maxDaysInMonth :: Int -> Month (Islamic l) -> Year -> Int
maxDaysInMonth :: forall (l :: LeapPattern). Int -> Month (Islamic l) -> Int -> Int
maxDaysInMonth Int
bits Month (Islamic l)
R:MonthIslamic l
DhulHijjah Int
y
  | Int -> Int -> Bool
isLeapYear Int
bits Int
y                      = Int
30
  | Bool
otherwise                              = Int
29
maxDaysInMonth Int
_ Month (Islamic l)
m Int
_
  | Int -> Bool
forall a. Integral a => a -> Bool
even (Month (Islamic l) -> Int
forall a. Enum a => a -> Int
fromEnum Month (Islamic l)
m)                      = Int
30        -- odd (1-based) months: Muharram, RabiAlAwwal, …
  | Bool
otherwise                              = Int
29        -- even (1-based) months: Safar, RabiAlThani, …

-- | Number of leap years among the first @r@ years of a cycle (cycle positions 1 .. @r@, for @r@ in 0 .. 29).
leapsInFirst :: Int -> Int -> Int
leapsInFirst :: Int -> Int -> Int
leapsInFirst Int
bits Int
r = Int -> Int
forall a. Bits a => a -> Int
popCount (Int
bits Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. ((Int
1 Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`shiftL` (Int
r Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)) Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
2))

-- | Universal flat day (day 0 = 1.Mar.2000 Gregorian) of the given Islamic date, for the given leap-pattern bit set.
yearMonthDayToDays :: Int -> Year -> Month (Islamic l) -> DayOfMonth -> Int
yearMonthDayToDays :: forall (l :: LeapPattern).
Int -> Int -> Month (Islamic l) -> Int -> Int
yearMonthDayToDays Int
bits Int
y Month (Islamic l)
m Int
d = Int
islamicEpoch Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
daysBeforeYear Int -> Int -> Int
forall a. Num a => a -> a -> a
+ [Int]
islamicMonthDayOffsets [Int] -> Int -> Int
forall a. HasCallStack => [a] -> Int -> a
!! Month (Islamic l) -> Int
forall a. Enum a => a -> Int
fromEnum Month (Islamic l)
m Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
d Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1
  where
    (Int
c, Int
r) = (Int -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
y 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
30
    daysBeforeYear :: Int
daysBeforeYear = Int
c Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
daysPerCycle Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
r Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
daysPerNonLeapYear Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int -> Int -> Int
leapsInFirst Int
bits Int
r

daysToYearMonthDay :: Int -> Int32 -> (Int32, Word8, Word8)
daysToYearMonthDay :: Int -> Int32 -> (Int32, Word8, Word8)
daysToYearMonthDay Int
bits Int32
flatDays = (Int -> Int32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
y, Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
m, 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 -> Int -> Int
forall a. Num a => a -> a -> a
- Int
islamicEpoch                         -- days since 1.Muharram.1 (>= 0 for valid dates)
    (Int
cycles, Int
remCycle) = Int
n Int -> Int -> (Int, Int)
forall a. Integral a => a -> a -> (a, a)
`divMod` Int
daysPerCycle                     -- 10631-day, 30-year cycle
    (Int
yearInCycle, Int
dayOfYear) = Int -> Int -> (Int, Int)
findYear Int
0 Int
0
    y :: Int
y = Int
cycles Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
30 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
yearInCycle Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
    (Int
m, Int
d)
      | Int
dayOfYear Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
daysPerNonLeapYear    = (Int
11, Int
30)                -- 355th day: DhulHijjah 30 (leap years only)
      | Bool
otherwise                          = (Int
dayOfYear Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
2 Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
59, (Int
dayOfYear Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
59) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
30 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
    -- Walk the (at most 30) years of the cycle, subtracting each year's length until the remaining days fall inside one.
    findYear :: Int -> Int -> (Int, Int)
findYear Int
i Int
acc
      | Int
acc Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
diy Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
remCycle               = (Int
i, Int
remCycle Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
acc)
      | Bool
otherwise                          = Int -> Int -> (Int, Int)
findYear (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) (Int
acc Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
diy)
      where diy :: Int
diy = if Int -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit Int
bits ((Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
30) then Int
daysPerLeapYear else Int
daysPerNonLeapYear