I have a list of 7 employees. I am iterating a loop of dates for the current month and want to assign two employees on each date, but on weekends they should not repeat until all employees are being assigned. For Example: I am having seven employees:
John
Sophia
Olivia
Davis
Clark
Paul
Thomas
Now my date loop is:
for (int i = 0; i < dates.Length; i++)
{
DateTime newDate = new DateTime();
newDate = dates[i];
/*if(newdate == "Saturday")
var EmpName1 = emplist[i];
var EmpName2 = emplist[i];*/
}
In the above loop I want to assign two employees each on Saturday and Sunday until all other have not been assigned previously. Something like this:
4th March: John and Sophia
5th March: Olivia and Davis
11th March: Clark and Paul
12th March: Thomas and John
and so on.... John will not be assigned till all of them are assigned. After that the list will start again. Can anyone help me on this?
Use a separate index for the person to chose every time you need to chose one.
After selecting, change the index with:
index = (index + 1) % employees.Length // Number fo employees
The % (means modulo) makes sure the counter starts at 0 again when employees.Length is reached.
So something like:
var empIndex = 0;
for (int i = 0; i < dates.Length; i++)
{
DateTime newDate = new DateTime();
newDate = dates[i];
if(newdate == "Saturday") // and Sunday, use or: || (newData == "Sunday"))
{
var EmpName1 = emplist[empIndex];
empIndex = (empIndex + 1) % empList.Length;
var EmpName2 = emplist[empIndex];
empIndex = (empIndex + 1) % empList.Length;
}
}
Seems to me that this boils down to ordering the employees by DateOfLastWeekendOnCall?
var e = Employees.OrderBy(i=>i.DateOfLastWeekendOnCall).First();
e.DateOfLastWeekendOnCall = weekendThatNeedsAssigning;
Explaination:
"dont assign the employee until all other employees have also been assigned"
is equivalent to
"assign the employee whose maximum date assigned to is the lowest of all employees (or who has never been assigned)"
So if you keep track of the last Saturday each employee was assigned to, its trivial to see which employee you should assign to the next date.
You can put in some special logic to handle the null case, or just put in MinDate as a default value
You could use a queue:
var weekendWarriors = new Queue<string>();
CheckRefreshQueue<string>(weekendWarriors, employees);
for (int i = 0; i < dates.Length; i++)
{
DateTime newDate = new DateTime();
newDate = dates[i];
if (newDate.DayOfWeek == DayOfWeek.Saturday || newDate.DayOfWeek == DayOfWeek.Sunday)
{
string emp1;
string emp2;
CheckRefreshQueue<string>(weekendWarriors, employees);
emp1 = weekendWarriors.Dequeue();
CheckRefreshQueue<string>(weekendWarriors, employees);
emp2 = weekendWarriors.Dequeue();
}
}
Here's CheckRefreshQueue:
private static void CheckRefreshQueue<T>(Queue<T> toRefresh, IEnumerable<T> fromCollection)
{
if (toRefresh.Count == 0) foreach (T item in fromCollection) toRefresh.Enqueue(item);
}
Related
I am facing a problem, logic written in my program is below
DataSet dslsip = mAE_Repo.FetchLastDayCustEmailsEquity_SIP_Content();
var ressip = (from r in dslsip.Tables[0].AsEnumerable() select r.Field<string>("emailid")).ToList();
var resdate = (from r in dslsip.Tables[0].AsEnumerable() select r.Field<DateTime>("a_confirmdatetime")).ToList();
//var datetime = DateTime.Now;
//List<string> date = new List<string>();
//List<DateTime> date = new List<DateTime>();
if (!ReferenceEquals(resdate,null) && resdate.Count>0)
{
for (int i = 0; i < resdate.Count()-1; i++)
{
if (resdate[i].Month == DateTime.Now.Month || resdate[i].Month < DateTime.Now.Month)
{
//Logic should write here
//var das = DateTime.Now.AddMonths(1).ToString("MM");
//var datet = resdate[i].AddMonths(1).ToString("MM");
}
}
}
In the above code 'resdate' variable I'm fetching the list of the dates
And the concept is I should add the month (current next month) Ex: {05-07-2021 00:00:00} I should add the (current month is 9 and next month is 10) so it should be {05-10-2021 00:00:00}
I'm not sure how to add the month only.
I'm new to coding.
Please help me in this.
Use AddMonths() function, example:
new DateTime(DateTime.Now.AddMonths(1).Year,
DateTime.Now.AddMonths(1).Month,
d.Day);
Output:
10/5/2021 12:00:00 AM
10/1/2021 12:00:00 AM
You need to change Month from date list. So, you can do it by using AddMonths() API. Used below Sample :
if (resdate[i].Month == DateTime.Now.Month || resdate[i].Month < DateTime.Now.Month)
{
//Logic should write here
var datet = new DateTime(resdate[i].Year, DateTime.Now.AddMonths(1).Month, resdate[i].Day, resdate[i].Hour, resdate[i].Minute, resdate[i].Second);
}
Here we modified only month data As you wanted.
Writing a small application to calculate interest but the rate changes yearly. Needed to break the range into smaller date ranges when ever it crosses a year boundary. I wrote a little for loop to do it but it's rather clunky. Wondering if there are any built in functions to do this in C# (possible linq). Would basically be looking to return a list of date ranges with the corresponding base year (shortened code for readability).
static void Main(string[] args)
{
var dateStart = DateTime.Parse("2/10/2018");
var dateEnd = DateTime.Parse("3/10/2021");
var years = Years(dateStart, dateEnd);
var baseYear = dateStart.Year;
Console.WriteLine(baseYear);
var loopDateStart = dateStart;
var loopDateEnd = DateTime.Now;
for (int i = 0; i < years + 1; i++)
{
if (i < years) {
loopDateEnd = DateTime.Parse("1/1/" + (baseYear + 1));
Console.WriteLine(loopDateEnd + " ... " + loopDateStart);
Console.WriteLine((loopDateEnd - loopDateStart).Days);
loopDateStart = loopDateEnd;
baseYear++;
}
else {
loopDateEnd = dateEnd;
Console.WriteLine(loopDateEnd + " ... " + loopDateStart);
Console.WriteLine((loopDateEnd - loopDateStart).Days);
}
}
}
public static int Years(DateTime start, DateTime end)
{
return (end.Year - start.Year - 1) +
(((end.Month > start.Month) ||
((end.Month == start.Month) && (end.Day >= start.Day))) ? 1 : 0);
}
Sure, we can use LINQ:
var x = Enumerable.Range(dateStart.Year, (dateEnd.Year-dateStart.Year)+1)
.Select(y => new{
F = new[]{dateStart, new DateTime(y,1,1)}.Max(),
T = new[]{dateEnd, new DateTime(y,12,31)}.Min()
});
It generates an enumerable list of objects that have an F and a T property (from and to) that are your ranges.
It works by using Enumerable.Range to make a list of years: 2018,2019,2020,2021 by starting at 2108 and proceeding for 4 years (2018 to 2018 is one year entry, 2018 to 2021 is 4 year entries)
Then we just turn them into dates using new DateTime(year,amonth,aday) - when were making start dates, amonth and aday are 1 and 1, when making end dates they're 12 and 31
Then we just ask for every year y, "which date is greater, the startdate, or the 1-Jan-y" and "which date is lesser, the enddate or the 31-Dec-y " - for the initial and final date entry it's the startdate and the enddate that are greater and lesser. For other years it's the jan/dec dates. This gives the ranges you want
foreach(var xx in x){
Console.WriteLine(xx.F +" to "+xx.T);
}
2/10/2018 12:00:00 AM to 12/31/2018 12:00:00 AM
1/1/2019 12:00:00 AM to 12/31/2019 12:00:00 AM
1/1/2020 12:00:00 AM to 12/31/2020 12:00:00 AM
1/1/2021 12:00:00 AM to 3/10/2021 12:00:00 AM
If you want to do other work like the number of days between, you can do xx.T-xx.F in the loop, to make a timespan etc
Try:
var start = DateTime.Parse("4/5/2017");
var end = DateTime.Parse("3/1/2019");
DateTime chunkEnd;
for (var chunkStart = start; chunkStart < end; chunkStart = chunkEnd.AddDays(1))
{
var lastDay = new DateTime(chunkStart.Year, 12, 31);
chunkEnd = end > lastDay ? lastDay : end;
var days = (chunkEnd - chunkStart).Days;
Console.WriteLine($"{chunkStart:d} - {chunkEnd:d}; {days} days");
}
Produces:
4/5/2017 - 12/31/2017; 270 days
1/1/2018 - 12/31/2018; 364 days
1/1/2019 - 3/1/2019; 59 days
I came up with the following:
static IEnumerable<(DateTime,DateTime)> ChunkByYear(DateTime start, DateTime end)
{
// Splits <start,end> into chunks each belonging to a different year
while(start <= end)
{
var tempEnd = new DateTime(start.Year, 12, 31);
if(tempEnd >= end ) {
yield return (start, end);
yield break;
}
yield return (start, tempEnd);
start = tempEnd.AddDays(1);
}
}
Here are some results:
4/05/2017 to 3/01/2019:
4/05/2017->31/12/2017
1/01/2018->31/12/2018
1/01/2019->3/01/2019
4/05/2017 to 4/05/2017:
4/05/2017->4/05/2017
31/12/2017 to 31/12/2019:
31/12/2017->31/12/2017
1/01/2018->31/12/2018
1/01/2019->31/12/2019
31/12/2019 to 31/12/2019:
31/12/2019->31/12/2019
31/12/2018 to 1/01/2019:
31/12/2018->31/12/2018
1/01/2019->1/01/2019
Group by years:
using System.Collections.Generic;
using System.Linq;
...
static void Main(string[] args)
{
DateTime dateStart = DateTime.Parse("2/10/2018");
DateTime dateEnd = DateTime.Parse("3/10/2021");
// Group all possible dates by year
foreach(var group in GetDates(dateStart, dateEnd).GroupBy(date => date.Year))
{
Console.WriteLine(group.Key); // The key of the group is year
Console.WriteLine($"{group.Min()} ... {group.Max()}"); // Range: From minimum to maximum, order doesn't matter.
Console.WriteLine($"{group.First()} ... {group.Last()}"); //or Range version 2: From first to last, order matters.
Console.WriteLine(group.Count()); // Count days
}
}
/// <summary>
/// Get all days blindly, might need to pay attention to days on the boundaries
/// </summary>
private static IEnumerable<DateTime> GetDates(DateTime start, DateTime end)
{
// TODO: Check start <= end;
DateTime current = start;
while(current <= end)
{
yield return current;
current = current.AddDays(1);
}
}
I have Two DatePicker in TextBox. I wants print all the dates between to range of textBox. How to insert those multiple dates in database...?
Example:
In First TextBox :- 1 July 2013
Second TextBox :- 31 December 2013
Output should be come likes :
1 July 2013
2 July 2013
3 July 2013
4 July 2013
|
|
|
30 December 2013
31 December 2013
private List<DateTime> GetRange()
{
var res = new List<DateTime>();
var start = DateTime.Parse(textBox1.Text);
var end = DateTime.Parse(textBox2.Text);
for (var date = start; date <= end; date = date.AddDays(1))
res.Add(date);
return res;
}
Firstly, convert both inputs to date object. You can use DateTime.Parse() for this.
DateTime start = DateTime.Parse("1 July 2013");
DateTime end = DateTime.Parse("31 December 2013");
Then simply loop through to the end.
while(start <= end)
{
// Output or save to DB etc
Console.WriteLine(start.ToString("d MMMMM yyyy"));
start = start.AddDays(1);
}
Why would you want to do this?
You can certainly do it, depending on the granularity with a varchar(max) field in the db and set the string to be:
string result = "";
for(int x = 0; x< (endDate - startDate).TotalDays; x++)
{
result += startDate.AddDays(x).ToDateString();
}
I can't fathom a reason why you would want this though. Store the start and end date and then use logic in the application to calculate the information as and when required would seem like it would make a lot more sense.
List<DateTime> allDates = new List<DateTime>();
int starting = startingDate.Day;
int ending = endingDate.Day;
for (int i = starting; i <= ending; i++)
{
allDates.Add(new DateTime(startingDate.Year, startingDate.Month, i));
}
using Linq:
var date1 = DateTime.Now.AddMonths(-1);
var date2 = DateTime.Now;
var dates = Enumerable
.Range(1, (int)(date2 - date1).TotalDays)
.Select(d => date1.AddDays(d).Date);
And to dump the result to a string:
var output = string.Join(Environment.NewLine, dates);
Thanks For your Response Everyone.....
but Perfect Answer for me is Combination of all above Answers...
DateTime dt = Convert.ToDateTime(TextBox1.Text);
string result = "";
for (int x = 0; x <= (Convert.ToDateTime(TextBox2.Text) - Convert.ToDateTime(TextBox1.Text)).TotalDays; x++)
{
result = dt.AddDays(x).ToString("d MMMMM yyyy");
Response.Write("<br>" + result);
}
I have a list of dates that are apart by a month in the sense that all dates are the "First Monday of the month". In some cases months are missing so I need to write a function to determine if all dates are consecutive
So for example if this was the list of dates, the function would return true as all items are the "First Friday of the month" and there are no gaps. This example below would return true.
var date = new DateTime(2013, 1, 4);
var date1 = new DateTime(2013, 2, 1);
var date2 = new DateTime(2013, 3, 1);
var date3 = new DateTime(2013, 4, 5);
var dateArray = new DateTime[]{date, date1, date2, date3};
bool isConsecutive = IsThisListConsecutive(dateArray);
where this example below would return false because, even though they are also all "First Friday of the month", its missing the March 2013 item.
var date = new DateTime(2013, 1, 4);
var date1 = new DateTime(2013, 2, 1);
var date3 = new DateTime(2013, 4, 5);
var dateArray = new DateTime[]{date, date1, date3};
bool isConsecutive = IsThisListConsecutive(dateArray);
so i am trying to figure out the right logic for the IsThisListConsecutive() method:
Here was my first try: (Note I already know upfront that all dates are same day of week and same week of month so the only thing i am looking for is a missing slot)
private bool IsThisListConsecutive(IEnumerable<DateTime> orderedSlots)
{
DateTime firstDate = orderedSlots.First();
int count = 0;
foreach (var slot in orderedSlots)
{
if (slot.Month != firstDate.AddMonths(count).Month)
{
return false;
}
count++;
}
return true;
}
This code above works exept if the list crosses over from one year to another. I wanted to get any advice on a better way to create this function and how that line could be rewritten to deal with dates that cross over years.
So to implement this we'll start with a simple helper method that takes a sequence and returns a sequence of pairs that make up each item with it's previous item.
public static IEnumerable<Tuple<T, T>> Pair<T>(this IEnumerable<T> source)
{
T previous;
using (var iterator = source.GetEnumerator())
{
if (iterator.MoveNext())
previous = iterator.Current;
else
yield break;
while(iterator.MoveNext())
{
yield return Tuple.Create(previous, iterator.Current);
previous = iterator.Current;
}
}
}
We'll also use this simple method to determine if two dates are in the same month:
public static bool AreSameMonth(DateTime first, DateTime second)
{
return first.Year == second.Year
&& first.Month == second.Month;
}
Using that, we can easily grab the month of each date and see if it's the month after the previous month. If it's true for all of the pairs, then we have consecutive months.
private static bool IsThisListConsecutive(IEnumerable<DateTime> orderedSlots)
{
return orderedSlots.Pair()
.All(pair => AreSameMonth(pair.Item1.AddMonths(1), pair.Item2));
}
Note: This is completely untested, and the date checks are probably pretty bad or somewhat redundant, but that’s the best I could come up with right now ^^
public bool AreSameWeekdayEveryMonth(IEnumerable<DateTime> dates)
{
var en = dates.GetEnumerator();
if (en.MoveNext())
{
DayOfWeek weekday = en.Current.DayOfWeek;
DateTime previous = en.Current;
while (en.MoveNext())
{
DateTime d = en.Current;
if (d.DayOfWeek != weekday || d.Day > 7)
return false;
if (d.Month != previous.Month && ((d - previous).Days == 28 || (d - previous).Days == 35))
return false;
previous = d;
}
}
return true;
}
I would recommend looking at the TimeSpan structure. Thanks to operator overload you can get a TimeSpan by substracting two dates and then receive a TimeSpan that expresses the difference between the two dates.
http://msdn.microsoft.com/en-us/library/system.timespan.aspx
okay, your code doesnt work when the years cross over becuase jan 1st may be a monday on one year and a tuesday on the next. If I was doing this, I would first check that
a) they are the same day of the week in each month (use DateTime.DayOfWeek)
b) they are the same week of the month in each month*
use extension method DayOfMonth (see link)
* Calculate week of month in .NET *
(you said you already know a & b to be true so lets go on to the third condition)
c) we have to determine if they are in consecutive months
//order the list of dates & place it into an array for ease of looping
DateTime[] orderedSlots = slots.OrderBy( t => t).ToArray<DateTime>();
//create a variable to hold the date from the previous month
DateTime temp = orderedSlots[0];
for(i= 1; index < orderedSlots.Length; index++)
{
if((orderedSlots[index].Month != temp.AddMonths(1).Month |
orderedSlots[index].Year != temp.AddMonths(1).Year)){
return false;
}
previousDate = orderedSlots[index];
}
return true;
if you need to check conditions a & b as well add change the if statement as follows
if( orderedSlots[index].Month != temp.AddMonths(1).Month |
orderedSlots[index].Year != temp.AddMonths(1).Year) |
orderedSlots[index].DayOfWeek != temp.DayOfWeek |
orderedSlots[index].GetWeekOfMonth != temp.AddMonths(1).GetWeekOfMonth){
return false;
}
remember that to use the get week of month extension method you have to include the code in
Calculate week of month in .NET
I'm sure there are typos as I did this in a text editor.
Well, here is my initial thought on how I would approach this problem.
First, is to define a function that will turn the dates into the ordinal values corresponding to the order in which they should appear.
int ToOrdinal(DateTime d, DateTime baseline) {
if (d.Day <= 7
&& d.DayInWeek == baseline.DayInWeek) {
// Since there is only one "First Friday" a month, and there are
// 12 months in year we can easily compose the ordinal.
// (As per default.kramer's comment, months normalized to [0,11].)
return d.Year * 12 + (d.Month - 1);
} else {
// Was not correct "kind" of day -
// Maybe baseline is Tuesday, but d represents Wednesday or
// maybe d wasn't in the first week ..
return 0;
}
}
var dates = ..;
var baseline = dates.FirstOrDefault();
var ordinals = dates.Select(d => ToOrdinal(d, baseline));
Then, for the dates provided, we end up with ordinal sequences like:
[24156 + 0, 24156 + 1, 24156 + 2, 24156 + 3]
And
[24156 + 0, 24156 + 1, /* !!!! */ 24156 + 3]
From here it is just a trivial matter of iterating the list and ensuring that the integers occur in sequence without gaps or stalls - that is, each item/integer is exactly one more than the previous.
I could be misinterpreting what you are trying to do, but I think this will work, assuming you don't have to handle ancient dates. See if there are any gaps in the dates converted to "total months"
int totalMonths = date.Year * 12 + (date.Month - 1);
I have this code, it failed because thisMonthSundays are empty:
public ActionResult TradeUKKPISearchesData() //show dropdownlist in the view
{
var now = DateTime.Now;
var lastMonth = now.AddMonths(-1);
var thisMonthSundays = GetDatesOfSundays(now.Year, now.Month).OrderByDescending(x => x.Date);
var lastMonthSundays = GetDatesOfSundays(lastMonth.Year, lastMonth.Month).OrderByDescending(x => x.Date); //problem here, must add some sort of check here?
var sundaysToTakeFromLastMonth = 4;
var sundays = thisMonthSundays.Concat(lastMonthSundays.Skip(Math.Max(0, lastMonthSundays.Count() - sundaysToTakeFromLastMonth)).Take(sundaysToTakeFromLastMonth));
var allSundaysInThisMonth = new SundaysInMonthViewModel
{
AllSundays = sundays.Select(x => new SelectListItem
{
Value = x.ToString("dd/MM/yyyy"),
Text = x.ToString("dd/MM/yyyy"),
})
};
var selectedSunday = new SundaysInMonthViewModel
{
SelectedSunday = thisMonthSundays.Where(x => x <= now).Last() //failed here
};
return View(allSundaysInThisMonth);
}
private IEnumerable<DateTime> GetDatesOfSundays(int year, int month)
{
var ci = CultureInfo.InvariantCulture;
for (int i=1; i <= ci.Calendar.GetDaysInMonth(year, month); i++)
{
var date = new DateTime(year, month, i);
if ((date.DayOfWeek == DayOfWeek.Sunday) && (date <= DateTime.Now))
{
yield return date; //skips all for this month
}
}
}
I need to fix this, please help with ideas?
thanks
As the Octobar month do not have SUnday so far, the variable SelectedSunday is empty....
You can use LastOrDefault() instead :
SelectedSunday = thisMonthSundays.Where(x => x <= now).LastOrDefault() ;
Note : The Default value for DateTime Type is DateTime.Min which is 1/1/0001 12:00:00 AM.
There are some mistakes in your code here.
Using var is not something you want to do everywhere.
You should never use arbitrary values in your functions. Instead of checking that the days are prior to today, you should add a limit parameter to your function and pass DateTime.Now
on the call.
Your function is already returning all the Sundays of a given month that are prior to today. Your Linq Request is just a replication of code and will return the whole collection every-time.
Since today is 10-01 and that we are Monday, there is no Sundays on October prior to today. This is why your collection is empty.