Check if selected date is within three days of a predefined holiday - c#

This is for a program at work. I don't have access to the code right now, but I really want to figure this out, so I wrote a quick program at home that is a mimic of my work project.
I need to know if that date is within 3 working days of a "holiday". If it is, then the selected date must be incremented by one to skip over the holiday. Example:
If there is a holiday on "01/19/2018" and a user selects "01/16/2018", then the program must skip the 19th and then set the closing date as "01/20/2018". Now if I do pure if/then statements, I can get it to work as expected, but the problem then becomes: "what if both 01/19/2018 AND 01/20/2018 are holidays?" This is where I'm stuck.
At work, I'm using a SQL table that already has a column for dates in "MM/dd/yyyy" format (so those dates are my list source that I am checking against.) The user opens a calendar and selects a date. I'm actually parsing an XML file that is created by another method that actually touches the database then using XElement for an iteration that puts all those dates in a string list.)
This is the code in my pseudo work program:
private void button1_Click(object sender, EventArgs e)
{
DateTime dt = DateTime.Now;
txtLog.Text = dt.ToString("MM/dd/yy") + Environment.NewLine;
List<string> allexemptdays = new List<string>();
string[] days = { "11/19/2018", "11/20/2018" };
foreach (string a in days)
{
allexemptdays.Add(a);
}
foreach (string a in allexemptdays)
{
ToLog(a);
}
DateTime eq = DateTime.Parse(txtDate.Text);
string thefrustrationisreal = eq.ToString("MM/dd/yy");
if (Math.Abs(DateTime.Now.Subtract(eq).Days) <= 3)
{
MessageBox.Show("Date exemption found.");
}
}
private void ToLog(string a)
{
txtLog.Text += ("Array value to list: " + a + Environment.NewLine);
}
private void monthCalendar1_DateSelected(object sender, DateRangeEventArgs e)
{
txtDate.Text = monthCalendar1.SelectionStart.ToString("MM/dd/yy");
}
Obviously I understand "DateTime.Now" doesn't reflect what I require, but I was just playing more with the DateTime class.
So in short: I'm creating an array with the dates (similar to my real program)
Iterating through them, adding them to a list. Now I need to check if the selected date falls within 3 days of the predefined date from a returned value from my sql table.
If a date is found, move the closing date up a day; however, if holidays in a row are found, then skip those two dates altogether. I can do this on a one by one basis (using if/then) but this doesn't work well if two holidays are back to back of each other.
As a side note, I want to be able to tell if the selected date is within 3 days AND moves over to another month, but I think I can handle that with DateTime, checking the days in a month and incrementing when needed (or I'm sure DateTime could do that for me actually.) I'm not too worried about this concern though at this point.
I did accept Mike's answer as it does work as intended, but! I now have a different issue
Now the "days.count()" holds a persistent number after the user selects a date beyond the holidays. Example: Selecting January 21 2017 returns "Janurary 26 2017" as the closing date because it's still counting the 20th and 21st as holidays affected by the range, when it should just set the closing date now at "Janurary 24th 2017"
I've played around with the code provided; I can't find a good way to fix it. I was thinking something along the lines of:
If(selectedDate.AddDays(3) >= holidaydate) then do a check for another day through the datetime list, but I'd still be making that way more complicated than it should be (I think.)
Last entry I'll do to this post (I'm considering this post solved now):
Matt's answer I selected does work to an extent and I appreciate his help. Problem is, the .Count() never resets, so if you go past the holiday(s) dates, it always holds onto the skipped days (so instead of going to 3 days ahead of the selected date, it'll go (3+the total number of days counted))
In the event someone else comes across a situation like this, here's what I ended up doing:
Downloaded the "WorkingDaysManagement" reference, instructions from:
https://github.com/Opturne/WorkingDaysManagement
the code I ultimately used is:
private void button1_Click(object sender, EventArgs e)
{
txtLog.Text = null;
DateTime dt = DateTime.Now;
var sd = (DateTime.Parse(txtDate.Text));
Console.WriteLine(sd.ToShortDateString());
var listHolidays = new List<DateTime>
{
new DateTime(2017, 12, 24),
new DateTime(2017, 12, 25)
};
var listWeekEnd = new List<DayOfWeek>
{
DayOfWeek.Saturday,
DayOfWeek.Sunday
};
var helper = new WorkingDayHelper(listHolidays,listWeekEnd);
foreach(DateTime s in helper.GetSpanDates(sd,3))
{
Console.WriteLine("Current iteration date: "+s.ToShortDateString());
}
var nextworkday = (helper.GetSpanDates(sd, 3).Last().ToString());
txtLog.Text += ("Next working day available: " + nextworkday + Environment.NewLine);
if(helper.IsWorkingDay(sd)==true)
{
txtLog.Text += ("It is a working a day." + Environment.NewLine);
}
else
{
txtLog.Text += ("NOT a working day!" + Environment.NewLine);
}
txtEndDate.Text = nextworkday;
}
The author of the plugin was gracious enough to put his work under the MIT license as well.

Let's say you have parsed all the date strings from the database into a List<DateTime> namely holidays. Then you can do something like
// Parsed holidays in a list, we will use LINQ against it.
var holidays = new List<DateTime> {
new DateTime(2017, 1, 19),
new DateTime(2017, 1, 20),
};
// Selected Date. In your case it would be: DateTime.Parse(txtDate.Text);
var selectedDate = new DateTime(2017, 1, 16);
// Count how many holidays there are within 3 days from the selcted date.
var count = holidays.Count(holiday => holiday - selectedDate <= TimeSpan.FromDays(3));
// Then add the count and 3 to the selected date
var closingDate = selectedDate.AddDays(count + 3);
// Now we have to make sure the closing date is not a holiday.
if (count > 0)
{
int skipDays = 0;
while (holidays.Any(holiday => holiday == closingDate.AddDays(skipDays)))
{
// holidays list contains the date. Skip it.
skipDays++;
}
closingDate = closingDate.AddDays(skipDays);
}

Related

How to compare int date with string by Month

I have the value DPIYRMO type: Int
My goal is to take this value and create an if statement where it compares the current month, to the month that the user sets DPIYRMO to.
Example, the user sets DPIYRMO to November, if this happens, I will have a messagebox that lets them know that their DPIYRMO is set to that month and not the current month.
This if statement will be placed in here:
private void OnPostCertificate()
{
if (TaxCertificateList.Where(c => c.IsSelected).Count() == 0)
return;
bw = new BackgroundWorker();
bw.WorkerReportsProgress = true;
bw.WorkerSupportsCancellation = true;
bw.DoWork += new DoWorkEventHandler(bw_DoPost);
bw.RunWorkerCompleted += BwOnRunPostCompleted;
bw.RunWorkerAsync();
}
I believe I may have to use substrings, however, I am not sure where to start.
Don't you simply want something like that?
if (obj.DPIYRMO != DateTime.Now.Month)
{
string dpiyrmoMonth = new DateTime(1970, obj.DPIYRMO, 1).ToString("MMMM");
Console.WriteLine(dpiyrmoMonth + " does not match the current month.");
// prints March does not match the current month.
}
DateTime.Now returns the current date and time, and the Month property returns the month as an integer: 1 for January, 2 for February... So you can compare it to your integer variable.
new DateTime(1970, obj.DPIYRMO, 1) returns a date with the month part equals to the one stored in your integer variable. Note that the year 1970 and the 1st day of the month are arbitrary values for the use we do, because ToString("MMMM") returns the month part formatted in a human-readable string. See the format you can use.

how to enable/disable specific dates in DateTimePicker winforms c#

I am programming a C# Windows application for a clinic and i stored days of works for every doctor for example
Dr.John works every Monday and Tuesday how i can enable dates in DateTimePicker for dates that only match the specific days and disable other days .
I don't know what are the methods and functions can help in that
Instead of the DateTimePicker you can
create a form on the fly
add a MonthCalendar to it
add either valid or invalid dates to the BoldDates collection
code the DateChanged event
test to see if a valid date was selected
add it to the list of dates picked
Details depend on what you want: A single date or a range, etc.
Make sure to trim the time portion, mabe like this for adding dates:
List<DateTime> bold = new List<DateTime>();
for (int i = 0; i < 3; i++)
bold.Add(DateTime.Now.AddDays(i*3).Date);
monthCalendar1.BoldedDates = bold.ToArray();
To select only valid dates maybe code like this:
List<DateTime> selected = new List<DateTime>();
private void monthCalendar1_DateSelected(object sender, DateRangeEventArgs e)
{
for (DateTime dt = monthCalendar1.SelectionStart.Date;
dt.Date <= monthCalendar1.SelectionEnd.Date;
dt = dt.AddDays(1))
{
if (!monthCalendar1.BoldedDates.Contains(dt)
&& !selected.Contains(dt)) selected.Add(dt.Date);
}
}
Unfortunately the options to set any stylings are limited to bolding dates. No colors or other visual clues seem to be possible.
So for anything really nice you will have to build a date picker yourself..

Display box at this time on the side

it is such that I am preparing my website for it to appear in the box in a best time by Danish,
this is how it should show example from today and then 2-3 days ahead. and then it must not show box more.
I've tried like this but I keep the error page who do that it will not display the date
string dato = DateTime("01-02-2015");
string datoend = DateTime("03-02-2015");
//skal vise i beste tidspunkt..
if(dato => datoend)
{
PanelMedlemskab.Visible = true;
}
else
{
PanelMedlemskab.Visible = false;
}
The problem is that it in no way want to work with me and I have tried to look at Microsoft dateformat about how to set it up but it just will not as I will when I write the dates on the way.
Try initializating DateTime objects with it's (year, month, day) constructor:
DateTime dato = new DateTime(2015, 2, 1);
DateTime datoend = new DateTime(2015, 2, 3);
PanelMedlemskab.Visible = dato >= datoend;
Or if you are using string, provide exact format for them using DateTime.ParseExact method.

How can I determine if the first or third Wednesday of the month has yet to arrive, and if so, which one is nearest to the current date? [duplicate]

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Getting specific days in a month
I've touched on this problem once before, in How to find the 3rd Friday in a month with C#? But since I did not explain my problem well then, I must try again:
My goal here is simple: upon the press of a button (referred to here as "Button1"), I must determine whether today's date is prior to either the first, or the third Wednesday of the month. If this is the case, I must then set the text of a label (referred to here as "lblDate") to the date of whichever of these future Wednesdays is nearest to the current date.
So far, I've written this:
protected void Button1_Click(object sender, EventArgs e)
{
DateTime Now = DateTime.Today;
DateTime TempDate = new DateTime(Now.Year, Now.Month, 1);
if (TempDate.DayOfWeek != DayOfWeek.Wednesday)
{
TempDate = TempDate.AddDays(1);
string date = TempDate.ToString();
lblDate.Text = date;
}
if (TempDate == TempDate.AddDays(1))
{
TempDate = TempDate.AddDays(14);
string date = TempDate.ToString();
lblDate.Text = date;
}
}
As you can see, something is missing. I would greatly appreciate any assistance in filling that in...
You could also try it like this:
protected DateTime getFirstWednesdayOfMonth(DateTime seedDate)
{
DateTime wed1 = new DateTime(seedDate.Year, seedDate.Month, 1); //1st Wednesday can start on the 1st of the month
while (wed1.DayOfWeek != DayOfWeek.Wednesday)
{
wed1 = wed1.AddDays(1);
}
return wed1;
}
protected DateTime getThirdWednesdayOfMonth(DateTime seedDate)
{
DateTime wed3 = new DateTime(seedDate.Year, seedDate.Month, 15); //3rd Wednesday cannot start prior to the 15th of the month
while (wed3.DayOfWeek != DayOfWeek.Wednesday)
{
wed3 = wed3.AddDays(1);
}
return wed3;
}
protected void Button1_Click(object sender, EventArgs e)
{
DateTime Now = DateTime.Today;
DateTime wed1 = getFirstWednesdayOfMonth(Now);
DateTime wed3 = getThirdWednesdayOfMonth(Now);
if (Now < wed1)
{
lblDate.Text = wed1.ToString();
}
else if (Now < wed3)
{
lblDate.Text = wed3.ToString();
}
}
Well I'm not entirely sure this will answer your question but it might get you on the right track. You can figure out the day of the week from the DateTime feature. Just use something similar to:
DateTime dateValue = new DateTime(2008, 6, 11);
Console.WriteLine((int) dateValue.DayOfWeek); // Displays 3
Use that in conjunction with the actual date say something like:
if((int) dateValue.DayOfWeek == 3) //which is Wednesday
if(date < 7 && date > 1)
week == 1st Weds of month
else(date < 21 && date > 14)
week == 3rd Weds of month
That's not exact code obviously but perhaps something along those lines would help out a little. And you will have to adjust the parameters a bit in order to adjust for the 1st not falling exactly on a monday. Since there is only seven days in a week and even if the first falls on a tuesday it just fall within the range of 1 and 7, likewise for 14 and 21. But just play around with that and you should figure the answer out soon enough.

How to group dates by week?

I am writing an Excel exporter for a bespoke application I am creating, and I have a question about LINQ grouping in C#.
Basically, this new Excel exporter class is given two dates. The class then retrieves all consignments between this date range.
As part of this exporter, I need to be able to group the dates into weeks, and get the values for that week. So for example, if I'm given 07/12/2011 and 22/12/2011 (dd/MM/yyyy format), I need to group all consignments between them ranges into weeks (each week beginning with Sunday). The ideal result using the above dates would be
Week 1: (consignments between 04/12/2011 and 10/12/2011)
Week 2: (consignments between 11/12/2011 and 17/12/2011)
Week 3: (consignments between 18/11/2011 and 24/12/2011)
Any ideas?
The fundamental question here is how to project a DateTime instance into a week of year value. This can be done using by calling Calendar.GetWeekOfYear. So define the projection:
Func<DateTime, int> weekProjector =
d => CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(
d,
CalendarWeekRule.FirstFourDayWeek,
DayOfWeek.Sunday);
You can configure exactly how the "week number" is determined by tweaking the parameters in the method call. You can also decide to define the projection as e.g. an extension method if you prefer; this does not change the essence of the code. In any case, you are then ready to group by week:
var consignmentsByWeek = from con in consignments
group con by weekProjector(con.Date);
If you also want to constrain the output to consigments between two specific dates, just add an appropriate where clause; the grouping logic does not change.
Hesitant though I am to disagree with as esteemed an answerer I believe the accepted answer here is wrong, and this is not fundamentally a question of projecting to a week of year value.
GetWeekOfYear(), and the concept in general, is about assigning index values to weeks within a year according to some agreed standard. It is not suitable for placing dates into groups of seven adjacent days as I believe the questioner requires.
Not only will use of GetWeekOfYear() as proposed result in groups of fewer than seven days at the end of many years, but worse still, as the various standards supported by GetWeekOfYear() will often apportion the first days of a year to the last week of the previous year, and yet the GetWeekOfYear() result contains only the integer week index with no reference to associated year, grouping by new { Year = date.Year, weekProjector(date) } or date.Year + "-" + weekProjector(date) in the questioner's year would see January 1st 2011 grouped in with Christmas Day through to New Year's Eve twelve months later that same year.
So I would argue that the original question is fundamentally one of projecting not to a week of year value but to a week of all time value, "week beginning y/m/d" you might say, so grouping need only be done by the first day of the week, i.e. (assuming you're happy to default to Sunday) simply:
group by date.AddDays(-(int)date.DayOfWeek)
In addition to Jon's answer you can get the date of the first day in the week then group by that date.
To get the date of the first day in the week.
you can use this code:
public static class DateTimeExtensions
{
public static DateTime StartOfWeek(this DateTime dt, DayOfWeek startOfWeek)
{
int diff = dt.DayOfWeek - startOfWeek;
if (diff < 0)
{
diff += 7;
}
return dt.AddDays(-1 * diff).Date;
}
}
then you can group by the first date of the week like this:
var consignmentsByWeek = from con in consignments
group con by con.Datedate.StartOfWeek(DayOfWeek.Monday);
I tried like this (and it's working :) )
#foreach (var years in _dateRange.GroupBy(y => y.Year))
{
<p>#years.Key</p>
foreach (var months in years.GroupBy(m => m.Month))
{
<p>#CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(months.Key)</p>
foreach (var weeks in months.GroupBy(w => w.AddDays(-(int)w.DayOfWeek)))
{
<p>#weeks.Key.ToString("dd-MMM-yy")</p>
}
}
}
I noticed that the OP has week 1, week 2, etc. in the ideal output. These are not the week of the year, but the "index" of the week being displayed based on the consignment dates. Building on some of the other answers already provided, here is my solution:
void DoExample()
{
//Load some sample data
var range = new List<DateTime>();
var curDate = DateTime.ParseExact("07/12/2011", "dd/MM/yyyy", System.Globalization.CultureInfo.InvariantCulture);
var maxDate = DateTime.ParseExact("22/12/2011", "dd/MM/yyyy", System.Globalization.CultureInfo.InvariantCulture);
while(curDate < maxDate)
{
range.Add(curDate);
curDate = curDate.AddDays(1);
}
//Run the method to get the consignments
var c = GetConsignments(range, DayOfWeek.Sunday);
//Output to match OP's "ideal" specs
foreach(var v in c)
{
Console.WriteLine($"Week {v.EntryIndex + 1} (number {v.WeekOfYear} in year): (consignments between {v.RangeStart:dd/MM/yyyy} and {v.RangeEnd:dd/MM/yyyy}). Actual date range is {v.RangeStart:dd/MM/yyyy}-{v.RangeEnd:dd/MM/yyyy} ({(v.FullWeek ? "Full" : "Partial")} week)");
}
//Most other answers place a lot of value on the week of the year, so this would include that.
// Also includes the actual date range contained in the set and whether all dates in that week are present
foreach (var v in c)
{
Console.WriteLine($"Week {v.EntryIndex + 1} (number {v.WeekOfYear} in year): (consignments between {v.RangeStart} and {v.RangeEnd})");
}
}
//Note that this lets us pass in what day of the week is the start.
// Not part of OP's requirements, but provides added flexibility
public List<ConsignmentRange> GetConsignments(IEnumerable<DateTime>consignments, DayOfWeek startOfWeek=DayOfWeek.Sunday)
{
return consignments
.OrderBy(v => v)
.GroupBy(v => v.AddDays(-(int)((7 - (int)startOfWeek) + (int)v.DayOfWeek) % 7))
.Select((v, idx) => new ConsignmentRange
{
//These are part of the OP's requirement
EntryIndex = idx,
RangeStart = v.Key, // part of requirement
RangeEnd = v.Key.AddDays(6), // part of requirement
//These are added as potentially useful
WeekOfYear = CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(
v.Key, CalendarWeekRule.FirstFourDayWeek, startOfWeek),
FirstDate = v.Min(),
LastDate = v.Max(),
FullWeek = (v.Distinct().Count() == 7)
}
)
.ToList();
}
We'll also need this class defined (or a subset of it depending on what data you want to include):
public class ConsignmentRange
{
public int EntryIndex;
public int WeekOfYear;
public bool FullWeek;
public DateTime FirstDate;
public DateTime LastDate;
public DateTime RangeStart;
public DateTime RangeEnd;
}

Categories

Resources