#![allow(clippy::manual_range_contains)]
use crate::shared::shared;
use crate::time::calendar::{Calendar, CalendarImpl, is_weekend_sat_sun};
use crate::time::date::{Date, Month, Year};
use crate::time::weekday::Weekday;
const HOLIDAY_HORIZON: Year = 2050;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Market {
Settlement,
Krx,
}
pub struct SouthKorea;
impl SouthKorea {
pub fn new(market: Market) -> Calendar {
let imp: crate::shared::Shared<dyn CalendarImpl> = match market {
Market::Settlement => shared(SettlementImpl),
Market::Krx => shared(KrxImpl),
};
Calendar::from_impl(imp)
}
}
fn settlement_is_business_day(date: Date) -> bool {
let w = date.weekday();
let d = date.day_of_month();
let m = date.month();
let y = date.year();
assert!(
y <= HOLIDAY_HORIZON,
"South Korea public/lunar holidays are tabulated only through {HOLIDAY_HORIZON} \
(matching QuantLib); year {y} is beyond the supported horizon"
);
!(is_weekend_sat_sun(w)
|| (d == 1 && m == Month::January)
|| (d == 1 && m == Month::March)
|| (w == Weekday::Monday && (d == 2 || d == 3) && m == Month::March && y > 2021)
|| (d == 5 && m == Month::April && y <= 2005)
|| (d == 1 && m == Month::May)
|| (d == 5 && m == Month::May)
|| (w == Weekday::Monday && (d == 6 || d == 7) && m == Month::May && y > 2013)
|| (d == 6 && m == Month::June)
|| (d == 17 && m == Month::July && y <= 2007)
|| (d == 15 && m == Month::August)
|| (w == Weekday::Monday && (d == 16 || d == 17) && m == Month::August && y > 2020)
|| (d == 3 && m == Month::October)
|| (w == Weekday::Monday && (d == 4 || d == 5) && m == Month::October && y > 2020)
|| (d == 25 && m == Month::December)
|| (w == Weekday::Monday && (d == 26 || d == 27) && m == Month::December && y > 2022)
|| ((d == 21 || d == 22 || d == 23) && m == Month::January && y == 2004)
|| ((d == 8 || d == 9 || d == 10) && m == Month::February && y == 2005)
|| ((d == 28 || d == 29 || d == 30) && m == Month::January && y == 2006)
|| (d == 19 && m == Month::February && y == 2007)
|| ((d == 6 || d == 7 || d == 8) && m == Month::February && y == 2008)
|| ((d == 25 || d == 26 || d == 27) && m == Month::January && y == 2009)
|| ((d == 13 || d == 14 || d == 15) && m == Month::February && y == 2010)
|| ((d == 2 || d == 3 || d == 4) && m == Month::February && y == 2011)
|| ((d == 23 || d == 24) && m == Month::January && y == 2012)
|| (d == 11 && m == Month::February && y == 2013)
|| ((d == 30 || d == 31) && m == Month::January && y == 2014)
|| ((d == 18 || d == 19 || d == 20) && m == Month::February && y == 2015)
|| ((d >= 7 && d <= 10) && m == Month::February && y == 2016)
|| ((d >= 27 && d <= 30) && m == Month::January && y == 2017)
|| ((d == 15 || d == 16 || d == 17) && m == Month::February && y == 2018)
|| ((d == 4 || d == 5 || d == 6) && m == Month::February && y == 2019)
|| ((d >= 24 && d <= 27) && m == Month::January && y == 2020)
|| ((d == 11 || d == 12 || d == 13) && m == Month::February && y == 2021)
|| (((d == 31 && m == Month::January)
|| ((d == 1 || d == 2) && m == Month::February))
&& y == 2022)
|| ((d == 23 || d == 24) && m == Month::January && y == 2023)
|| ((d >= 9 && d <= 12) && m == Month::February && y == 2024)
|| ((d == 28 || d == 29 || d == 30) && m == Month::January && y == 2025)
|| ((d == 16 || d == 17 || d == 18) && m == Month::February && y == 2026)
|| ((d == 8 || d == 9) && m == Month::February && y == 2027)
|| ((d == 26 || d == 27 || d == 28) && m == Month::January && y == 2028)
|| ((d == 12 || d == 13 || d == 14) && m == Month::February && y == 2029)
|| ((d == 4 || d == 5) && m == Month::February && y == 2030)
|| ((d == 22 || d == 23 || d == 24) && m == Month::January && y == 2031)
|| ((d == 10 || d == 11 || d == 12) && m == Month::February && y == 2032)
|| (((d == 31 && m == Month::January)
|| ((d == 1 || d == 2) && m == Month::February))
&& y == 2033)
|| ((d == 20 || d == 21) && m == Month::February && y == 2034)
|| ((d == 7 || d == 8 || d == 9) && m == Month::February && y == 2035)
|| ((d == 28 || d == 29 || d == 30) && m == Month::January && y == 2036)
|| ((d == 16 || d == 17) && m == Month::February && y == 2037)
|| ((d == 3 || d == 4 || d == 5) && m == Month::February && y == 2038)
|| ((d == 24 || d == 25 || d == 26) && m == Month::January && y == 2039)
|| ((d == 13 || d == 14) && m == Month::February && y == 2040)
|| (((d == 31 && m == Month::January)
|| ((d == 1 || d == 2) && m == Month::February))
&& y == 2041)
|| ((d == 21 || d == 22 || d == 23) && m == Month::January && y == 2042)
|| ((d == 9 || d == 10 || d == 11) && m == Month::February && y == 2043)
|| ((((d == 29 || d == 30 || d == 31) && m == Month::January)
|| (d == 1 && m == Month::February))
&& y == 2044)
|| ((d == 16 || d == 17 || d == 18) && m == Month::February && y == 2045)
|| ((d == 5 || d == 6 || d == 7) && m == Month::February && y == 2046)
|| ((d >= 25 && d <= 28) && m == Month::January && y == 2047)
|| ((d == 13 || d == 14 || d == 15) && m == Month::February && y == 2048)
|| ((d == 1 || d == 2 || d == 3) && m == Month::February && y == 2049)
|| ((d == 24 || d == 25) && m == Month::January && y == 2050)
|| (d == 15 && m == Month::April && y == 2004) || (d == 31 && m == Month::May && y == 2006) || (d == 19 && m == Month::December && y == 2007) || (d == 9 && m == Month::April && y == 2008) || (d == 2 && m == Month::June && y == 2010) || (d == 11 && m == Month::April && y == 2012) || (d == 19 && m == Month::December && y == 2012) || (d == 4 && m == Month::June && y == 2014) || (d == 13 && m == Month::April && y == 2016) || (d == 9 && m == Month::May && y == 2017) || (d == 13 && m == Month::June && y == 2018) || (d == 15 && m == Month::April && y == 2020) || (d == 9 && m == Month::March && y == 2022) || (d == 1 && m == Month::June && y == 2022) || (d == 10 && m == Month::April && y == 2024) || (d == 26 && m == Month::May && y == 2004)
|| (d == 15 && m == Month::May && y == 2005)
|| (d == 5 && m == Month::May && y == 2006)
|| (d == 24 && m == Month::May && y == 2007)
|| (d == 12 && m == Month::May && y == 2008)
|| (d == 2 && m == Month::May && y == 2009)
|| (d == 21 && m == Month::May && y == 2010)
|| (d == 10 && m == Month::May && y == 2011)
|| (d == 28 && m == Month::May && y == 2012)
|| (d == 17 && m == Month::May && y == 2013)
|| (d == 6 && m == Month::May && y == 2014)
|| (d == 25 && m == Month::May && y == 2015)
|| (d == 14 && m == Month::May && y == 2016)
|| (d == 3 && m == Month::May && y == 2017)
|| (d == 22 && m == Month::May && y == 2018)
|| (d == 12 && m == Month::May && y == 2019)
|| (d == 30 && m == Month::April && y == 2020)
|| (d == 19 && m == Month::May && y == 2021)
|| (d == 8 && m == Month::May && y == 2022)
|| (d == 29 && m == Month::May && y == 2023) || (d == 15 && m == Month::May && y == 2024)
|| (d == 6 && m == Month::May && y == 2025)
|| (d == 25 && m == Month::May && y == 2026) || (d == 13 && m == Month::May && y == 2027)
|| (d == 2 && m == Month::May && y == 2028)
|| (d == 21 && m == Month::May && y == 2029) || (d == 9 && m == Month::May && y == 2030)
|| (d == 28 && m == Month::May && y == 2031)
|| (d == 17 && m == Month::May && y == 2032) || (d == 6 && m == Month::May && y == 2033)
|| (d == 25 && m == Month::May && y == 2034)
|| (d == 15 && m == Month::May && y == 2035)
|| (d == 6 && m == Month::May && y == 2036) || (d == 22 && m == Month::May && y == 2037)
|| (d == 11 && m == Month::May && y == 2038)
|| (d == 2 && m == Month::May && y == 2039) || (d == 18 && m == Month::May && y == 2040)
|| (d == 7 && m == Month::May && y == 2041)
|| (d == 26 && m == Month::May && y == 2042)
|| (d == 18 && m == Month::May && y == 2043) || (d == 6 && m == Month::May && y == 2044)
|| (d == 24 && m == Month::May && y == 2045)
|| (d == 14 && m == Month::May && y == 2046) || (d == 2 && m == Month::May && y == 2047)
|| (d == 20 && m == Month::May && y == 2048)
|| (d == 10 && m == Month::May && y == 2049) || (d == 30 && m == Month::May && y == 2050)
|| (d == 14 && m == Month::August && y == 2015)
|| (d == 17 && m == Month::August && y == 2020)
|| (d == 2 && m == Month::October && y == 2023)
|| (d == 1 && m == Month::October && y == 2024)
|| (d == 27 && m == Month::January && y == 2025)
|| ((d == 27 || d == 28 || d == 29) && m == Month::September && y == 2004)
|| ((d == 17 || d == 18 || d == 19) && m == Month::September && y == 2005)
|| ((d == 5 || d == 6 || d == 7) && m == Month::October && y == 2006)
|| ((d == 24 || d == 25 || d == 26) && m == Month::September && y == 2007)
|| ((d == 13 || d == 14 || d == 15) && m == Month::September && y == 2008)
|| ((d == 2 || d == 3 || d == 4) && m == Month::October && y == 2009)
|| ((d == 21 || d == 22 || d == 23) && m == Month::September && y == 2010)
|| ((d == 12 || d == 13) && m == Month::September && y == 2011)
|| (d == 1 && m == Month::October && y == 2012)
|| ((d == 18 || d == 19 || d == 20) && m == Month::September && y == 2013)
|| ((d == 8 || d == 9 || d == 10) && m == Month::September && y == 2014)
|| ((d == 28 || d == 29) && m == Month::September && y == 2015)
|| ((d == 14 || d == 15 || d == 16) && m == Month::September && y == 2016)
|| ((d >= 3 && d <= 6) && m == Month::October && y == 2017)
|| ((d >= 23 && d <= 26) && m == Month::September && y == 2018)
|| ((d == 12 || d == 13 || d == 14) && m == Month::September && y == 2019)
|| (((d == 30 && m == Month::September)
|| ((d == 1 || d == 2) && m == Month::October))
&& y == 2020)
|| ((d == 20 || d == 21 || d == 22) && m == Month::September && y == 2021)
|| ((d == 9 || d == 10 || d == 11) && m == Month::September && y == 2022)
|| ((d >= 9 && d <= 12) && m == Month::September && y == 2022)
|| ((d == 28 || d == 29 || d == 30) && m == Month::September && y == 2023)
|| ((d == 16 || d == 17 || d == 18) && m == Month::September && y == 2024)
|| ((d == 6 || d == 7 || d == 8) && m == Month::October && y == 2025)
|| ((d == 24 || d == 25 || d == 26) && m == Month::September && y == 2026)
|| ((d == 14 || d == 15 || d == 16) && m == Month::September && y == 2027)
|| ((d >= 2 && d <= 5) && m == Month::October && y == 2028)
|| ((d >= 21 && d <= 24) && m == Month::September && y == 2029)
|| ((d == 11 || d == 12 || d == 13) && m == Month::September && y == 2030)
|| (((d == 30 && m == Month::September)
|| ((d == 1 || d == 2) && m == Month::October))
&& y == 2031)
|| ((d == 20 || d == 21) && m == Month::September && y == 2032)
|| ((d == 7 || d == 8 || d == 9) && m == Month::September && y == 2033)
|| ((d == 26 || d == 27 || d == 28) && m == Month::September && y == 2034)
|| ((d == 17 || d == 18) && m == Month::September && y == 2035)
|| ((d >= 3 && d <= 7) && m == Month::October && y == 2036)
|| ((d == 23 || d == 24 || d == 25) && m == Month::September && y == 2037)
|| ((d == 13 || d == 14 || d == 15) && m == Month::September && y == 2038)
|| ((d == 3 || d == 4 || d == 5) && m == Month::October && y == 2039)
|| ((d == 20 || d == 21 || d == 22) && m == Month::September && y == 2040)
|| ((d == 9 || d == 10 || d == 11) && m == Month::September && y == 2041)
|| ((d == 29 || d == 30) && m == Month::September && y == 2042)
|| ((d == 16 || d == 17 || d == 18) && m == Month::September && y == 2043)
|| ((d == 4 || d == 5 || d == 6) && m == Month::October && y == 2044)
|| ((d == 25 || d == 26 || d == 27) && m == Month::September && y == 2045)
|| ((d >= 14 && d <= 17) && m == Month::September && y == 2046)
|| ((d == 4 || d == 5 || d == 7) && m == Month::October && y == 2047)
|| ((d == 21 || d == 22 || d == 23) && m == Month::September && y == 2048)
|| ((d >= 10 && d <= 13) && m == Month::September && y == 2049)
|| ((((d == 29 || d == 30) && m == Month::September)
|| (d == 1 && m == Month::October))
&& y == 2050)
|| (d == 9 && m == Month::October && y >= 2013)
|| (w == Weekday::Monday && (d == 10 || d == 11) && m == Month::October && y > 2020))
}
struct SettlementImpl;
impl CalendarImpl for SettlementImpl {
fn name(&self) -> String {
"South-Korean settlement".to_string()
}
fn is_weekend(&self, w: Weekday) -> bool {
is_weekend_sat_sun(w)
}
fn is_business_day(&self, date: Date) -> bool {
settlement_is_business_day(date)
}
}
struct KrxImpl;
impl CalendarImpl for KrxImpl {
fn name(&self) -> String {
"South-Korea exchange".to_string()
}
fn is_weekend(&self, w: Weekday) -> bool {
is_weekend_sat_sun(w)
}
fn is_business_day(&self, date: Date) -> bool {
if !settlement_is_business_day(date) {
return false;
}
let d = date.day_of_month();
let w = date.weekday();
let m = date.month();
let y = date.year();
if (((d == 29 || d == 30) && w == Weekday::Friday) || d == 31) && m == Month::December {
return false;
}
if (d == 6 && m == Month::May && y == 2016) || (d == 2 && m == Month::October && y == 2017)
{
return false;
}
true
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn names_match_quantlib() {
assert_eq!(
SouthKorea::new(Market::Settlement).name(),
"South-Korean settlement"
);
assert_eq!(SouthKorea::new(Market::Krx).name(), "South-Korea exchange");
}
#[test]
fn fixed_holidays() {
let c = SouthKorea::new(Market::Settlement);
assert!(c.is_holiday(Date::new(1, Month::January, 2019)));
assert!(c.is_holiday(Date::new(1, Month::March, 2019)));
assert!(c.is_holiday(Date::new(1, Month::May, 2019)));
assert!(c.is_holiday(Date::new(5, Month::May, 2019)));
assert!(c.is_holiday(Date::new(6, Month::June, 2019)));
assert!(c.is_holiday(Date::new(15, Month::August, 2019)));
assert!(c.is_holiday(Date::new(3, Month::October, 2019)));
assert!(c.is_holiday(Date::new(25, Month::December, 2019)));
}
#[test]
fn weekend_rule() {
let c = SouthKorea::new(Market::Krx);
assert!(c.is_weekend(Weekday::Saturday));
assert!(c.is_weekend(Weekday::Sunday));
assert!(!c.is_weekend(Weekday::Monday));
}
#[test]
fn in_horizon_query_works() {
let c = SouthKorea::new(Market::Settlement);
assert!(c.is_holiday(Date::new(1, Month::January, HOLIDAY_HORIZON)));
}
#[test]
#[should_panic(expected = "beyond the supported horizon")]
fn beyond_horizon_panics() {
let c = SouthKorea::new(Market::Settlement);
let _ = c.is_business_day(Date::new(1, Month::January, HOLIDAY_HORIZON + 1));
}
}