WorkingDateTime Информация о дате и о дне ( рабочий, празднечный, сокращенный ) #CSharp
/// <summary> Информация о дате и о дне ( рабочий, празднечный, сокращенный ) </summary>
public class WorkingDateTime
{
/// <summary> Информация о дате и о дне ( рабочий, празднечный, сокращенный ) </summary>
public WorkingDateTime(DateTime date, bool IsWorkDay, bool IsWeekend, bool IsHalfDay)
{
private_date = date;
private_IsWorkDay = IsWorkDay;
private_IsWeekend = IsWeekend;
private_IsHalfDay = IsHalfDay;
}
/// <summary> Список нестандартных дат календаря рабочего времени, что мы получили с сервисов по API </summary>
public static List<WorkingDateTime> listWorkingDateTime = new List<WorkingDateTime>();
/// <summary> Рассматриваемая дата </summary>
public DateTime date { get { return private_date; } }
/// <summary> Рассматриваемая дата </summary>
private DateTime private_date { set; get; }
/// <summary> Факт того, что текущая дата является рабочим днем календаря </summary>
public bool IsWorkDay { get { return private_IsWorkDay; } }
/// <summary> Факт того, что текущая дата является рабочим днем календаря </summary>
private bool private_IsWorkDay { set; get; }
/// <summary> Факт того, что текущая дата является выходным или празднечным днем </summary>
public bool IsWeekend { get { return private_IsWeekend; } }
/// <summary> Факт того, что текущая дата является выходным или празднечным днем </summary>
private bool private_IsWeekend { set; get; }
/// <summary> Факт того, что текущая дата является сокращенным, рабочим днем днем </summary>
public bool IsHalfDay { get { return private_IsHalfDay; } }
/// <summary> Факт того, что текущая дата является сокращенным, рабочим днем днем </summary>
private bool private_IsHalfDay { set; get; }
/// <summary> Возвращает список дат рабочего календаря в промежутке чисел </summary>
/// <param name="startDate"></param>
/// <param name="endDate"></param>
/// <returns></returns>
public static List<WorkingDateTime> get(DateTime startDate, DateTime endDate)
{
if (startDate > endDate)
return new List<WorkingDateTime>();
//У нас есть 2 сервиса, которые могут рассказать о нестандартых датах рабочего календаря
//Речь идет о празднечных днях, о сокращенных дняи и субботах, воскресениях, которые могуб быть рабочеми!
//http://basicdata.ru/api/json/calend/ --Получение JSON результата, что вернет нестнандартные даты
//http://xmlcalendar.ru/data/ru/2018/calendar.xml --Полчение XML результата, что вернет нестандартные дни
startDate = startDate.Date;
endDate = endDate.Date;
//Сперва мы проверим, а есть ли эти даты уже в списке, что мы получили по API
lock (listWorkingDateTime)
{
if (listWorkingDateTime.Select(x => x.date).Contains(startDate) && listWorkingDateTime.Select(x => x.date).Contains(endDate))
return listWorkingDateTime.Where(x => x.date >= startDate && x.date <= endDate).ToList();
}
List<WorkingDateTime> listDateTimeApi = new List<WorkingDateTime>();
//Сюда мы попали если в списке нестандартных дат, не оказалось нашего промежутка!
WebClient client = new WebClient();
try
{
string json = client.DownloadString("http://basicdata.ru/api/json/calend/");
var j_object = JObject.Parse(json)["data"].ToObject<JObject>();
var listYear = j_object.Properties().Select(x => x.Name).ToList();
foreach (string year in listYear)
{
var listMonth = j_object[year].ToObject<JObject>().Properties().Select(x => x.Name).ToList();
foreach (string month in listMonth)
{
var listDay = j_object[year][month].ToObject<JObject>().Properties().Select(x => x.Name).ToList();
foreach (string day in listDay)
{
int isWorking = j_object[year][month][day]["isWorking"].Value<int>();
string monthIndex = month.Length == 2 ? month : ("0" + month);
string dayIndex = day.Length == 2 ? day : ("0" + day);
DateTime date = Convert.ToDateTime($"{year}-{monthIndex}-{dayIndex}");
bool IsWorkDay = isWorking == 0 ? true : false;
bool IsWeekend = isWorking == 2 ? true : false;
bool IsHalfDay = isWorking == 3 ? true : false;
listDateTimeApi.Add(new WorkingDateTime(date, IsWorkDay, IsWeekend, IsHalfDay));
/*
0 — рабочий день;
2 — праздничный/нерабочий день;
3 — сокращенный на 1 час рабочий день.
*/
}
}
}
}
catch { }
var listDateTimeApiYear = listDateTimeApi.Select(x => x.date.Year).Distinct().ToList();
int startYear = listDateTimeApiYear.First();
int endYear = listDateTimeApiYear.Last() + 1;
if (listDateTimeApiYear.Contains(startDate.Year) != true || listDateTimeApiYear.Contains(endDate.Year) != true)
{
try
{
//Если первого сервиса не достаточно
//Он не выдал календарь рабочего времени за интересующие нас года, то тогда воспользуемся вторым сервсом!
//Сперва следует достать все года, которые нас интересуют!
List<int> listYear = new List<int>();
startYear = startDate.Year;
endYear = endDate.Year;
for (int i = startYear; i <= endYear; i++)
listYear.Add(i);
listYear = listYear.Where(x => listDateTimeApiYear.Contains(x) != true).ToList();
foreach (int year in listYear)
{
XmlDocument document = new XmlDocument();
document.Load($"http://xmlcalendar.ru/data/ru/{year}/calendar.xml");
var listDay = document.GetElementsByTagName("*").Cast<XmlNode>().Where(x => (x.Name ?? "").Trim() == "day").ToList();
foreach (XmlNode day in listDay)
{
//<day d="01.01" t="1" h="1" />
string d = day.Attributes.Cast<XmlAttribute>().Where(x => (x.Name ?? "").Trim() == "d").Where(x => !String.IsNullOrWhiteSpace(x.Value)).Select(x => x.Value).FirstOrDefault();
string t = day.Attributes.Cast<XmlAttribute>().Where(x => (x.Name ?? "").Trim() == "t").Where(x => !String.IsNullOrWhiteSpace(x.Value)).Select(x => x.Value).FirstOrDefault();
if (String.IsNullOrWhiteSpace(d))
continue;
if (String.IsNullOrWhiteSpace(t))
continue;
DateTime date = new DateTime();
if (DateTime.TryParse($"{year}-" + d.Replace(".", "-"), out date) != true)
continue;
bool IsWorkDay = t == "3" ? true : false;
bool IsWeekend = t == "1" ? true : false;
bool IsHalfDay = t == "2" ? true : false;
listDateTimeApi.Add(new WorkingDateTime(date, IsWorkDay, IsWeekend, IsHalfDay));
}
/*
t - тип дня:
1 - выходной день,
2 - рабочий и сокращенный (может быть использован для любого дня недели),
3 - рабочий день (суббота/воскресенье)
*/
}
}
catch { }
}
listDateTimeApiYear = listDateTimeApi.Select(x => x.date.Year).Distinct().ToList();
//В listDateTimeApi у нас собраны только нестандартные даты. Теперь сформируем массив где будут обсалютно все даты тех лет что есть в listDateTimeApi
List<WorkingDateTime> listDateTime = new List<WorkingDateTime>();
startYear = listDateTimeApiYear.Min();
endYear = listDateTimeApiYear.Max() + 1;
DateTime startForDate = Convert.ToDateTime($"{startYear}-01-01");
DateTime endForDate = Convert.ToDateTime($"{endYear}-01-01");
for (DateTime date = startForDate; date < endForDate; date = date.AddDays(1))
{
var workingDate = listDateTimeApi.Where(x => x.date == date).FirstOrDefault();
if (workingDate != null)
{
listDateTime.Add(workingDate);
continue;
}
bool IsWorkDay = date.DayOfWeek == DayOfWeek.Saturday || date.DayOfWeek == DayOfWeek.Sunday ? false : true;
bool IsWeekend = date.DayOfWeek == DayOfWeek.Saturday || date.DayOfWeek == DayOfWeek.Sunday ? true : false;
bool IsHalfDay = false;
listDateTime.Add(new WorkingDateTime(date, IsWorkDay, IsWeekend, IsHalfDay));
}
lock (listWorkingDateTime)
{
listWorkingDateTime.AddRange(listDateTime.Where(x => listWorkingDateTime.Select(z => z.date).Contains(x.date) != true));
//Если мы только что обратились к API сервисам и все интересующие нас даты были подгружены от туда!
listDateTime = listWorkingDateTime.Where(x => x.date >= startDate && x.date <= endDate).ToList();
if (listWorkingDateTime.Select(x => x.date).Contains(startDate) && listWorkingDateTime.Select(x => x.date).Contains(endDate))
return listDateTime;
}
//Сюда мы попали если те даты, что нам нужны не удалось найти в сервисах календарей рабочего времени
//В этом случии недостающие даты следует брать из стандартного правила: ( счуббота и воскресение это выходной а все другие дни это рабочие дни )
var listCurrentDateTime = listDateTime.Select(x => x.date).ToList();
for (DateTime date = startDate; date <= endDate; date = date.AddDays(1))
{
if (listCurrentDateTime.Contains(date))
continue;
bool IsWorkDay = date.DayOfWeek == DayOfWeek.Saturday || date.DayOfWeek == DayOfWeek.Sunday ? false : true;
bool IsWeekend = date.DayOfWeek == DayOfWeek.Saturday || date.DayOfWeek == DayOfWeek.Sunday ? true : false;
bool IsHalfDay = false;
listDateTime.Add(new WorkingDateTime(date, IsWorkDay, IsWeekend, IsHalfDay));
}
return listDateTime;
}
}