using System; using System.Collections.Generic; using System.Text; using System.Resources; using System.IO; namespace Genus.Core.Utils { /* Calendar is an abstract class. Calendar is designed as a singleton pattern. Classes that extend Calendar must define the IsHoliday(Date) method. They should also define a private constructor and a single static readonly instance variable "c". Examples of holidays: -Canadian holidays vs. US holidays vs. World holidays -Genus company holidays -Days the TSX or NASDAQ markets are closed -Banking holidays RBCCalendar (implemented) GenusCalendar (implemented) USACalendar (not implemented) CanadaCalendar (not implemented) TSXCalendar (not implemented) UnitraxCalendar (not implemented) -- could be used to determine to download TA files or not */ public abstract class Calendar { public abstract bool IsHoliday(DateTime date); /* By default, Saturday and Sunday are never considered working days. If the date is a holiday then it's not a working day. If date is a Monday then it is a holiday if Saturday or Sunday were holidays. If date is a Tuesday then it is a holiday if 2 days out of Sat, Sun, Mon are holidays. You could continue with this logic (if date is a Wednesday and 3 out of 4 days are holidays ...) but that never actually happens. */ public virtual bool IsWorkingDay(DateTime date) { if (date.DayOfWeek == DayOfWeek.Saturday) return false; if (date.DayOfWeek == DayOfWeek.Sunday) return false; if (IsHoliday(date)) return false; if (date.DayOfWeek == DayOfWeek.Monday) { // if Saturday or Sunday is a holiday, then Monday is not a working day if (IsHoliday(date.AddDays(-1))) return false; if (IsHoliday(date.AddDays(-2))) return false; } else if (date.DayOfWeek == DayOfWeek.Tuesday) { bool isSatHoliday = IsHoliday(date.AddDays(-3)); bool isSunHoliday = IsHoliday(date.AddDays(-2)); bool isMonHoliday = IsHoliday(date.AddDays(-1)); if (isSatHoliday && isSunHoliday) return false; // e.g. Xmas on Saturday if (isSatHoliday && isMonHoliday) return false; // are any holidays 1 day apart? if (isSunHoliday && isMonHoliday) return false; // e.g. Xmas on Sunday } return true; } public virtual bool IsFirstBusinessDayOfQuarter(DateTime date) { int month = date.Month; if ( month == 1 || month == 4 || month == 7 || month == 10 ) { DateTime d = new DateTime(date.Year, date.Month, 1); while (!IsWorkingDay(d)) d = d.AddDays(1); return date.Day == d.Day; } return false; } public virtual bool IsLastBusinessDayOfQuarter(DateTime date) { int month = date.Month; if (month == 4 || month == 6 || month == 9 || month == 12) { DateTime d = new DateTime(date.Year, date.Month, 1); d = d.AddMonths(1).AddDays(-1); while (!IsWorkingDay(d)) d = d.AddDays(-1); return date.Day == d.Day; } return false; } public virtual bool IsFirstBusinessDayOfYear(DateTime date) { DateTime d = new DateTime(date.Year, 1, 1); while (!IsWorkingDay(d)) d = d.AddDays(1); return d == date; } public virtual bool IsLastBusinessDayOfYear(DateTime date) { DateTime d = new DateTime(date.Year, 12, DateTime.DaysInMonth(date.Year, 12)); while (!IsWorkingDay(d)) d = d.AddDays(-1); return d == date; } public virtual bool IsFirstBusinessDayOfSemiAnnual(DateTime date) { if ( date.Month == 1 || date.Month == 7 ) { DateTime d = new DateTime(date.Year, date.Month, 1); while (!IsWorkingDay(d)) d = d.AddDays(1); return d == date; } return false; } public virtual bool IsLastBusinessDayOfSemiAnnual(DateTime date) { if (date.Month == 6 || date.Month == 12) { DateTime d = new DateTime(date.Year, date.Month, DateTime.DaysInMonth(date.Year, date.Month)); while (!IsWorkingDay(d)) d = d.AddDays(-1); return d == date; } return false; } public virtual bool IsFirstBusinessDayOfMonth(DateTime date) { DateTime d = new DateTime(date.Year, date.Month, 1); while (!IsWorkingDay(d)) d = d.AddDays(1); return date.Day == d.Day; } public virtual bool IsLastBusinessDayOfMonth(DateTime date) { DateTime d = new DateTime(date.Year, date.Month, DateTime.DaysInMonth(date.Year, date.Month)); if (!IsWorkingDay(d)) d = PreviousBusinessDay(d); return d.Day == date.Day; } public virtual bool IsFirstBusinessDayOfWeek(DateTime date) { date = date.Date; if (!IsWorkingDay(date)) return false; DateTime pbd = PreviousBusinessDay(date); return pbd.DayOfWeek > date.DayOfWeek; } public virtual bool IsLastBusinessDayOfWeek(DateTime date) { date = date.Date; if (!IsWorkingDay(date)) return false; DateTime nbd = NextBusinessDay(date); return nbd.DayOfWeek < date.DayOfWeek; } public virtual DateTime PreviousBusinessDay(DateTime date) { DateTime d = date.AddDays(-1); while (!IsWorkingDay(d)) d = d.AddDays(-1); return d; } public virtual DateTime NextBusinessDay(DateTime date) { DateTime d = date.AddDays(1); while (!IsWorkingDay(d)) d = d.AddDays(1); return d; } //------------------------------------------------------------------------------------------------------ public static bool IsNewYears(DateTime date) { return date.Month == 1 && date.Day == 1; } private static void getEasterMD(int y, out int easterMonth, out int easterDay) { int a=y%19; int b=y/100; int c=y%100; int d=b/4; int e=b%4; int f=(b+8)/25; int g=(b-f+1)/3; int h=(19*a+b-d-g+15)%30; int i=c/4; int k=c%4; int l=(32+2*e+2*i-h-k)%7; int m=(a+11*h+22*l)/451; easterMonth=(h+l-7*m+114)/31; int p=(h+l-7*m+114)%31; easterDay=p+1; } // 3rd Monday in February public static bool IsFamilyDayOntario(DateTime date) { // Family Day in Ontario wasn't observed until 2008. if (date.Year < 2008) return false; if (date.Month != 2) return false; if (date.DayOfWeek != DayOfWeek.Monday) return false; int numMondays = 0; while (date.Month == 2) { if (date.DayOfWeek == DayOfWeek.Monday) numMondays++; date = date.AddDays(-1); } return numMondays == 3; } // Easter always falls on Sunday, generally it's not considered a holiday because // Calendars can use the IsEasterMonday method instead. Don't define Easter and // EasterMonday has holidays because then Tuesday will not be a working day. public static bool IsEaster(DateTime date) { int easterMonth = 0; int easterDay = 0; getEasterMD(date.Year, out easterMonth, out easterDay); return date.Month == easterMonth && date.Day == easterDay; } public static bool IsGoodFriday(DateTime date) { int easterMonth = 0; int easterDay = 0; getEasterMD(date.Year, out easterMonth, out easterDay); int goodFriday=easterDay-2; if (goodFriday < 1) { goodFriday+=31; easterMonth--; } return date.Month == easterMonth && date.Day == goodFriday; } public static bool IsEasterMonday(DateTime date) { int easterMonth = 0; int easterDay = 0; getEasterMD(date.Year, out easterMonth, out easterDay); int easterMonday = easterDay + 1; if (easterMonday > 31) { easterMonday = 1; easterMonth = 4; } return date.Month == easterMonth && date.Day == easterMonday; } // celebrated on the last Monday before or on May 24 public static bool IsVictoriaDay(DateTime date) { if (date.Month != 5) return false; DateTime d = new DateTime(date.Year, 5, 24); while (d.DayOfWeek != DayOfWeek.Monday) d = d.AddDays(-1); return date.Day == d.Day; } public static bool IsCanadaDay(DateTime date) { return date.Month == 7 && date.Day == 1; } // first Monday in August -- Canadian Holiday public static bool IsCivicDay(DateTime date) { // aka B.C. Day if (date.Month != 8) return false; DateTime d = new DateTime(date.Year, 8, 1); while (d.DayOfWeek != DayOfWeek.Monday) d = d.AddDays(1); return date.Day == d.Day; } // first Monday in September -- US Holiday public static bool IsLaborDay(DateTime date) { if (date.Month != 9) return false; DateTime d = new DateTime(date.Year, 9, 1); while (d.DayOfWeek != DayOfWeek.Monday) d = d.AddDays(1); return date.Day == d.Day; } // fourth Thursday in November public static bool IsThanksGivingUSA(DateTime date) { if (date.Month != 11) return false; DateTime d = new DateTime(date.Year, 11, 1); int x = 0; while (true) { if (d.DayOfWeek == DayOfWeek.Thursday) x++; if (x == 4) break; d = d.AddDays(1); } return date.Day == d.Day; } // Second Monday in October public static bool IsThanksGivingCanada(DateTime date) { if (date.Month != 10) return false; DateTime d = new DateTime(date.Year, 10, 1); int x = 0; while (true) { if (d.DayOfWeek == DayOfWeek.Monday) x++; if (x == 2) break; d = d.AddDays(1); } return date.Day == d.Day; } public static bool IsRemembranceDay(DateTime date) { return date.Month == 11 && date.Day == 11; } public static bool IsChristmas(DateTime date) { return date.Month == 12 && date.Day == 25; } public static bool IsBoxingDay(DateTime date) { return date.Month == 12 && date.Day == 26; } #region US Holidays // 3rd monday in Jan public static bool IsMartinLutherKingDay(DateTime date) { // MLK Day was closed for 1 minute of silence at noon since 1986, and closed all day beginning in 1998. if (date.Year < 1998) return false; if (date.Month != 1) return false; DateTime d = new DateTime(date.Year, 1, 1); int x = 0; while (true) { if (d.DayOfWeek == DayOfWeek.Monday) x++; if (x == 3) break; d = d.AddDays(1); } return date.Day == d.Day; } // Feb 15 // Observed is the first monday on or after Feb 15 public static bool IsPresidentsDay(DateTime date) { if (date.Month != 2) return false; DateTime d = new DateTime(date.Year, 2, 15); while (d.DayOfWeek != DayOfWeek.Monday) d = d.AddDays(1); return date.Day == d.Day; } // last Monday in May public static bool IsMemorialDay(DateTime date) { if (date.Month != 5) return false; DateTime d = new DateTime(date.Year, date.Month, DateTime.DaysInMonth(date.Year, date.Month)); while (true) { if (d.DayOfWeek == DayOfWeek.Monday) break; d = d.AddDays(-1); } return date.Day == d.Day; } // July 4 public static bool IsIndependenceDay(DateTime date) { return date.Month == 7 && date.Day == 4; } // Nov 11 public static bool IsVeteransDay(DateTime date) { return date.Month == 11 && date.Day == 11; } public static String getHolidayName(DateTime date) { if (IsBoxingDay(date)) return "BoxingDay"; if (IsCanadaDay(date)) return "CanadaDay"; if (IsChristmas(date)) return "Christmas"; if (IsCivicDay(date)) return "CivicDay"; if (IsEaster(date)) return "Easter"; if (IsEasterMonday(date)) return "EasterMonday"; if (IsFamilyDayOntario(date)) return "FamilyDayOntario"; if (IsGoodFriday(date)) return "GoodFriday"; if (IsIndependenceDay(date)) return "IndependenceDay"; if (IsLaborDay(date)) return "LaborDay"; if (IsMartinLutherKingDay(date)) return "MartinLurtherKingDay"; if (IsMemorialDay(date)) return "MemorialDay"; if (IsNewYears(date)) return "NewYears"; if (IsPresidentsDay(date)) return "PresidentsDay"; if (IsRemembranceDay(date)) return "RemembranceDay"; if (IsThanksGivingCanada(date)) return "ThanksGivingCanada"; if (IsThanksGivingUSA(date)) return "ThanksGivingUSA"; if (IsVeteransDay(date)) return "VeteransDay"; if (IsVictoriaDay(date)) return "VictoriaDay"; return null; } #endregion public static bool IsFirst60Days(DateTime date) { // bit of optimization. Jan & Feb are always in first 60 days // Anything after March 3 is never in first 60 days. if (date.Month == 1 || date.Month == 2) return true; else if (date.Month > 3 || date.Day > 3) return false; // generally, March 1st is the 60th day. // but in a leap year Feb 29th is the 60th day. // If the 60th day falls on Sat or Sun then the // next Monday is considered the 60th day DateTime d = new DateTime(date.Year, 1, 1); d = d.AddDays(59); // add 59 days, not 60! if (d.DayOfWeek == DayOfWeek.Saturday) d = d.AddDays(2); else if (d.DayOfWeek == DayOfWeek.Sunday) d = d.AddDays(1); return date.Date <= d; } } }