2008年05月10日

この記事をクリップ! b.hatena.ne.jp/entry 特定の日付に対する休場判定処理ソースコード

現在、乖離率分布グラフの作成にOmegaChartを活用していますが、

OmegaChartは2007年以降の祝日法に完全に対応しておらず、
過去の国民の祝日・東証の業務規定を考慮した休場判定も未対応のため、
個人的に書き直しました。C#のソースコードは以下の通り。

適用する場合は Util.cs の該当部分を置き換えて下さい。
(参考になる方は極々一部の方のような気もしますが…。)

[5/11追記] 水曜日の振替休日への対応漏れを修正
public static bool IsMarketOpenDate(DateTime dt) {
    // 日曜日
    if (dt.DayOfWeek == DayOfWeek.Sunday) return false;

    // 株式会社東京証券取引所 業務規定による休業日
    if (dt.Month == 1 && dt.Day <= 3) return false;
    if (dt.Month == 12) {
        if (dt.Year >= 1989 && dt.Day == 31) return false;
        if (dt.Year <= 1988 && dt.Day >= 29) return false;
    }
    // 土曜日
    if (dt.DayOfWeek == DayOfWeek.Saturday) {
        if (IsFiveDayWorkWeek(dt)) return false;
    }
    // 国民の祝日
    if (IsHoliday(dt)) return false;

    // 振替休日
    if (dt.Year >= 1973 && dt.DayOfWeek == DayOfWeek.Monday) {
        if (IsHoliday(dt.AddDays(-1))) return false;
    }
    if (dt.Year >= 2007 && dt.DayOfWeek == DayOfWeek.Tuesday) {
        if (IsHoliday(dt.AddDays(-1)) &&
            IsHoliday(dt.AddDays(-2))) return false;
    }
    if (dt.Year >= 2007 && dt.DayOfWeek == DayOfWeek.Wednesday) {
        if (IsHoliday(dt.AddDays(-1)) &&
            IsHoliday(dt.AddDays(-2)) &&
            IsHoliday(dt.AddDays(-3))) return false;
    }
    return true;
}
public static bool IsFiveDayWorkWeek(DateTime dt) {
    // その月の何番目の○曜日か?
    int number = (int)((dt.Day - 1) / 7) + 1;

    if (dt.Year >= 1990) return true;
    if (dt.Year == 1989) return dt.Month >= 2 || number != 4;
    if (dt.Year >= 1987) return number == 2 || number == 3;
    if (dt.Year == 1986)
        return dt.Month >= 8
            ? (number == 2 || number == 3) : (number == 2);
    if (dt.Year >= 1984) return number == 2;
    if (dt.Year == 1983)
        return dt.Month >= 8
            ? (number == 2) : (number == 3);
    return number == 3;
}
public static bool IsHoliday(DateTime dt) {
    int year = dt.Year;
    int day = dt.Day;
    DayOfWeek dow = dt.DayOfWeek;

    // その月の何番目の○曜日か?
    int number = (int)((day - 1) / 7) + 1;

    switch (dt.Month) {
        case 1:
            // 元旦
            if (day == 1) return true;
            // 成人の日(第2月曜日)
            return (year <= 1999)
                ? (day == 15)
                : (dow == DayOfWeek.Monday && number == 2);
        case 2:
            // 建国記念の日
            if (day == 11) return true;
            // 昭和天皇の大喪の礼
            return year == 1989 && day == 24;
        case 3:
            // 春分の日
            return day == vernal_equinox(year);
        case 4:
            // 皇太子明仁親王の結婚の儀
            if (year == 1959 && day == 10) return true;
            // 昭和の日
            return day == 29;
        case 5:
            // 憲法記念日
            if (day == 3) return true;
            // [1986〜]国民の休日, [2007〜]みどりの日
            if (day == 4 && year >= 1986) return true;
            // こどもの日
            return day == 5;
        case 6:
            // 皇太子徳仁親王の結婚の儀
            return year == 1993 && day == 9;
        case 7:
            // 海の日(第3月曜日)
            if (year <= 1995) return false;
            if (year <= 2002) return day == 20;
            return dow == DayOfWeek.Monday && number == 3;
        case 9:
            // 敬老の日
            if (year <= 2002) {
                if (day == 15) return true;
            } else {
                if (dow == DayOfWeek.Monday && number == 3)
                    return true;
            }
            // 秋分の日
            int aut_eq = autumnal_equinox(year);
            if (day == aut_eq) return true;
            // 国民の休日(敬老の日と秋分の日に挟まれた場合)
            if (year >= 2003 && dow == DayOfWeek.Tuesday) {
                int prev_number = (int)(((day - 1) - 1) / 7) + 1;
                if (prev_number == 3 && (day + 1) == aut_eq)
                    return true;
            }
            return false;
        case 10:
            // 体育の日
            return (year <= 1999)
                ? (day == 10)
                : (dow == DayOfWeek.Monday && number == 2);
        case 11:
            // 即位礼正殿の儀
            if (year == 1990 && day == 12) return true;
            // 文化の日, 勤労感謝の日
            return day == 3 || day == 23;
        case 12:
            // 天皇誕生日
            return year >= 1989 && day == 23;
        default:
            return false;
    }
}
public static int vernal_equinox(int year) {
    double equinox = 0.242194 * (year - 1980);
    return (year < 1980)
        ? ((int)(20.8357 + equinox - (int)((year - 1983) / 4)))
        : ((int)(20.8431 + equinox - (int)((year - 1980) / 4)));
}
public static int autumnal_equinox(int year) {
    double equinox = 0.242194 * (year - 1980);
    return (year < 1980)
        ? ((int)(23.2588 + equinox - (int)((year - 1983) / 4)))
        : ((int)(23.2488 + equinox - (int)((year - 1980) / 4)));
}

この記事へのトラックバックURL

http://trackback.blogsys.jp/livedoor/gotospace/51046995
この記事へのコメント
こんばんは。
ソースコード活用させていただきます。
本当にありがとうございます。

現状は、kt関数というフリーのアドインを使い、営業日一覧を作成して、
その一覧を見てスクリーニングの対象日をクリック、結果をクリップボードにコピー、
エクセルに貼付ける作業をしています。

これを機にC#をのんびりですが、勉強することにしました。
Amazonに猫でもわかるC#がありましたので・・・
私にもできると思います(笑)
m(_ _)m
Posted by 会社犬 at 2008年05月11日 00:16
はじめまして
自分もVBの休日関数を作っていたのですが、過去の休日には対応していませんでした。早速移植させていただきました。ありがとうございます。
Posted by こりおり at 2008年05月11日 10:36
会社犬さん

おおぉ、C#を始められるのですね!
是非是非、がんばって下さい。応援いたします。:-)
学んで損は無いと思います。
Posted by gotospace at 2008年05月11日 11:19
こりおりさん

こちらこそはじめまして。
参考になって良かったです。(*^^*)
Posted by gotospace at 2008年05月11日 11:21
はじめまして。
SDL+で、信用残を反映させる日の計算の中で休日判定を使用していましたが、こちらのソースを検証せずに(ぉぃ)そのまま0.03版に組み込ませていただきました。
ありがとうございました。
Posted by stray_nora at 2008年05月19日 02:54
stray_noraさん

はじめまして。
ツールいつも参考にさせて頂いております。
ありがとうございます。
Posted by gotospace at 2008年05月19日 08:34
当方、VC++で株関係のシェアウェアを作っている者ですが
この記事の休日判定コードを移植させていただきました。
過去20年間のデータで正しいかどうか検証してみましたが、問題ありませんでした。
大変参考になりました。ありがとうございます。
Posted by SonicBoom at 2010年05月29日 09:54
 (管理人にのみ通知)
 (管理人にのみ通知)
 
月別コラム
スポンサード リンク
逆アクセスRanking
実験中
あわせて読みたい
livedoor Blog
このBlogをはてなRSSに追加 このBlogを
はてなRSSに追加
このBlogをチェッカーズに追加 このBlogを
チェッカーズに追加
このBlogをリーダーに追加 このBlogを
リーダーに追加
アクセス解析