select a day from a period - reccurrence - c#

I am trying to implement a recurrence pattern for my Calendar Application.
I want it to work the same way Outlook does when you set an appointment with reccurrence.
public async Task<ValidationResponse<ReccurrenceModel>> ApplyReccurrencePeriod (string userName, ReccurrenceModel value)
{
var user = await repository.FindByUserName(userName);
var fromDateUTC = DateTime.SpecifyKind(value.FromDate, DateTimeKind.Utc);
var toDateUTC = DateTime.SpecifyKind(value.ToDate, DateTimeKind.Utc);
var dates = new List<DateTime>();
var weeklyReccurrence = value.weeklyReccurrence;
if (value.IsMonday == true)
{
var fromDate = value.FromDate;
var toDate = value.ToDate;
for (var dt = fromDate; dt < toDate; dt = dt.AddDays(1))
{
dates.Add(dt);
}
var savedDates = dates.Where(x => x.DayOfWeek == DayOfWeek.Monday).Select(x => x.Date);
}
// I do the same code to verify every week day
var test = dates.Where(x => x.DayOfWeek == DayOfWeek.Friday).Select(x => x.Date);
}
foreach (var date in savedDates) {
var x = user.Holidays.FirstOrDefault(kvp => kvp.Key == date
&& kvp.Value.StateVal == value.State.StateVal);
var dateUTC = DateTime.SpecifyKind(date, DateTimeKind.Utc);
user.Holidays[dateUTC] = value.State;
}
// save
var updatedUser = await repository.UpdateEmployee(user);
return await Task.FromResult(new ValidationResponse<HolidayModel>()
{
IsValid = true,
Result = updatedUser.Holidays.ContainsKey(dateUTC) ? new HolidayModel() { Date = dateUTC, State = updatedUser.Holidays[dateUTC] } : null
});
}
}
The problem with my code is that it works only if I have weekly reccurrence. I need to make it work in order to have 2, 3, ... n weeks reccurrence.
How can I make it skip some weeks?
public class ReccurrenceModel
{
public DateTime FromDate { get; set; }
public DateTime ToDate { get; set; }
public int WeeklyReccurrence { get; set; }
public State State { get; set; }
public bool IsMonday { get; set; }
public bool IsTuesday { get; set; }
public bool IsWednesday { get; set; }
public bool IsThursday { get; set; }
public bool IsFriday { get; set; }
public DateTime FromDateToReturn { get; set; }
public DateTime ToDateToReturn { get; set; }
}

The code is a bit convoluted, there are a lot of lines that do nothing at all.
Here I provide a sample of code that, albeit not elegant at all, provides you with the behaviour you need, the following code will create a list of days that are recurrent every 2, 3, whatever you need weeks you define in its call.
This method also accepts a list of DayOfWeek for which you want the recurrence to be created
private static void GetRecurrentDays(DateTime fromDate, DateTime untilDate, uint weeklyRecurrence, List<DayOfWeek> recurrenceDays)
{
var recurrenceDates = new List<DateTime>();
for (var dt = fromDate; dt < untilDate; dt = dt.AddDays(1))
{
if (recurrenceDays.Any(day => day.Equals(dt.DayOfWeek)))
{
var lastDate =
recurrenceDates
.LastOrDefault(date => date.DayOfWeek.Equals(dt.DayOfWeek));
// We multiply 7 days (a week) with weeklyRecurrence to
// calculate the appropiate date in which to add another day,
// calling with either 0 or 1 will calculate a weekly
// schedule
if (lastDate.Equals(DateTime.MinValue)
|| weeklyRecurrence.Equals(0)
|| ((dt - lastDate).Days % (7 * weeklyRecurrence)).Equals(0) )
{
recurrenceDates.Add(dt);
}
}
}
}
you can embed this code in yours in order to obtain the days with weekly recurrence and then, consume them further in your code

Related

String reference not set to an instance of a String. Parameter name: input ASP.Net MVC [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 1 year ago.
Why am I seeing this error prnt.sc/11btyns . This happens only when I change mostRecentMonday TO lastWeekMonday, and weekEnd TO lastWeekSunday.
var mostRecentMonday = DateTime.Now.AddDays(-7).StartOfWeek(DayOfWeek.Monday);
var weekEnd = mostRecentMonday.AddDays(7).AddSeconds(-1);
var lastWeekMonday = mostRecentMonday.AddDays(-7).StartOfWeek(DayOfWeek.Monday);
var lastWeekSunday = lastWeekMonday.AddDays(7).AddSeconds(-1);
Model class
public DateTime? FeedbackDateTime { get; set; }
public DateTime? FeedbackSharedDateTime { get; set; }
public string AuditorAHT { get; set; }
ReportVM To Group Data and display in the View
public string FeedbackSharedBy { get; set; }
public int AuditCount { get; set; }
public string AudtAht { get; set; }
Controller that saves the action perform by auditor as duration in
public string AuditorAHT { get; set; }
dto.FeedbackSharedDateTime = DateTime.Now;
string ahtString = string.Format("{0:hh\\:mm\\:ss}", dto.FeedbackSharedDateTime - dto.FeedbackDateTime);
dto.AuditorAHT = ahtString;
db.SaveChanges();
Below Action should display Auditors Name, Count, and Average Time spent.
var audtName = db.Chats.Where(x => System.Data.Entity.DbFunctions.TruncateTime(x.MSTChatCreatedDateTime) >= mostRecentMonday
&& System.Data.Entity.DbFunctions.TruncateTime(x.MSTChatCreatedDateTime) <= weekEnd && x.Feedback != null && x.FeedbackSharedBy != null).Select(x => new {
x.FeedbackSharedBy,
x.AuditorAHT
}).ToList() // this hits the database
// We need to do grouping in the code (rather than the db)
// because timespans are stored as strings
.GroupBy(e => e.FeedbackSharedBy)
.Select(g => new ReportVM
{
FeedbackSharedBy = g.Key,
AuditCount = g.Count(),
AudtAht = TimeSpan.FromSeconds(g.Sum(t => TimeSpan.Parse(t.AuditorAHT).TotalSeconds / g.Count())).ToString()
})
.OrderByDescending(s => s.AuditCount).ToList();
ViewBag.AudtReport = audtName;
DateTime Extn
public static class DateTimeExtensions
{
public static DateTime StartOfWeek(this DateTime dt, DayOfWeek startOfWeek)
{
int diff = (7 + (dt.DayOfWeek - startOfWeek)) % 7;
return dt.AddDays(-1 * diff).Date;
}
static GregorianCalendar _gc = new GregorianCalendar();
public static int GetWeekOfMonth(this DateTime time)
{
DateTime first = new DateTime(time.Year, time.Month, 1);
return time.GetWeekOfYear() - first.GetWeekOfYear() + 1;
}
static int GetWeekOfYear(this DateTime time)
{
return _gc.GetWeekOfYear(time, CalendarWeekRule.FirstDay, DayOfWeek.Sunday);
}
static DateTime ToCleanDateTime(this DateTime dt)
{
return new DateTime(dt.Year, dt.Month, dt.Day, 0, 0, 0, 0);
}
public static DateTime ToCleanDateTime(this DateTime? dt)
{
if (dt.HasValue)
{
return dt.Value.ToCleanDateTime();
}
return DateTime.Now; // if dt doesn't have value, return current DateTime.
}
}
Kindly suggest
Was able to resolve this by simply making 2 changes
Following property public string AuditorAHT { get; set; } = "00:00:00";. Updated so default NULL value is stored with 00:00:00 instead of saying NULL.
All past data had to be updated as 00:00:00, hence ran SQL query
Update Chats
Set AuditorAHT = '00:00:00'
Where AuditorAHT IS NULL;
Build the Project and wallaa code started to respond.
Thank you!

Format date and Filter by range

Hello I am trying to format a date
that is in a csv in the format dd / mm / yyyy
and would need to put it for ddmmyyyy in a json
filtered by a range, example from 01012019 until 31012019
Can anyone give me a suggestion?
Serialization
static void Main(string[] args)
{
using (var reader = new StreamReader("../database.csv"))
using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{
csv.Configuration.Delimiter = ",";
var records = csv.GetRecords<Tabela>().ToList();
// JSON writing
var json = JsonConvert.SerializeObject(records);
File.WriteAllText("../database.json", json);
System.Console.WriteLine(records);
}
}
Model
class Tabela
{
public DateTime date { get; set; }
public String media { get; set; }
public String client_id { get; set; }
public String client_name { get; set; }
public String campaign_id { get; set; }
public String campaign_name { get; set; }
public int clicks { get; set; }
public int impressions { get; set; }
public Double investment { get; set; }
}
This should be work:
var validFrom = DateTime.TryParseExact("01012019", "ddMMyyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime from);
var validTo = DateTime.TryParseExact("31012019", "ddMMyyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime to);
if (validFrom && validTo)
{
var records = csv.GetRecords<Tabela>()
.Where(x => x.date >= from && x.date <= to)
.Select(x => new {
date = $"{x.date:ddMMyyyy}",
// ...
// the rest of the properties
// or selected
})
.ToList();
}
example of how are the dates writen into json file:
File.WriteAllText("../../../dates.json", $"{{\n\t\"date\": \"{DateTime.Now:ddMMyyyy}\"\n}}");

Linq: Selecting current month Data but checking if anything needs carrying over from previous months

I currently have this linq:
var filterdForecastRevenue = filteredWonSales
.Where(x => x.ProjectStartDate.Month.Equals(month.Month)
&& x.ProjectStartDate.Year.Equals(month.Year));
foreach (var rev in filterdForecastRevenue)
{
if (rev.ProjectDurationMonths > 0)
{
rev.ForecastSell = rev.ForecastSell / rev.ProjectDurationMonths;
}
}
var forecastRevenueTotal = (filterdForecastRevenue.Any())
? filterdForecastRevenue.Sum(x => x.ForecastSell) : 0;
My Class:
public class WonSaleView
{
[Key]
public Guid Id { get; set; }
public string Jobnumber { get; set; }
public double ForecastSell { get; set; }
public DateTime ProjectStartDate { get; set; }
public int ProjectDurationMonths { get; set; }
}
This works, but what i need is:
Values need to carry over from previous months i.e. If ProjectStartDate Is in July but runs for 3 months (ProjectDurationMonths) i need to carry over the calculate ForecastSell in August and September as well.
I tried for 3 hours trying to figure out such a simple task, any help is fantastic.
You are converting a DateTime to intergers (month, year). It is better to use the DateTime Object. See code below :
DateTime now = DateTime.Now;
DateTime firstOfMonth = new DateTime(now.Year, now.Month, 1);
var filterdForecastRevenue = filteredWonSales
.Where(x => (x.ProjectStartDate >= firstOfMonth)
|| ((x.ProjectStartDate.AddMonths(rev.ProjectDurationMonths) >= firstOfMonth));
If understand correctly you need project which are "active" during given month.
Quickly can come up only with two queries
var now = DateTime.Now();
var startMonth = new DateTime(now.Year, now.Month, 1);
var endMonth = startMonth.AddMonths(1).AddSeconds(-1);
var fullyOverlaping =
filteredWonSales.Where(sale => sale.ProjectStartDate < startMonth)
.Where(sale => sale.ProjectStartDate.AddMonths(rev.ProjectDurationMonths) > endMonth);
var withinMonth =
filteredWonSales.Where(sale => (sale.ProjectStartDate >= startMonth && sale.ProjectStartDate <= endMonth) ||
(sale.ProjectStartDate.AddMonths(rev.ProjectDurationMonths) >= startMonth && sale.ProjectStartDate.AddMonths(rev.ProjectDurationMonths) <= endMonth));
var all = withinMonth.Concat(fullyOverlaping);

Data grouping by date and converting DateTime to Double

can anyone help me with this, I'm getting the result at the moment:
I want the data in the Stunden column to convert to Double and sort by date
At the end result to be 01.03.2017 = 9.0;
13.12.2017 = 8.5;
this is my current code
q.ZPZ_LPE_ID = userID;
if (db.State == ConnectionState.Closed)
db.Open();
string query = "SELECT zei.ZPZ_Von, zei.ZPZ_Bis, per.LPE_Nr, zei.ZPZ_LPE_ID, zei.ZPZ_Datum, SUM (zei.ZPZ_Std100) AS ZPZ_Std100" +
" FROM DB.dbo.Z_PRAESENZZEIT zei INNER JOIN DB.dbo.A_PERSONAL per ON zei.ZPZ_LPE_ID = per.LPE_ID" +
$" WHERE zei.ZPZ_Datum BETWEEN '{dtFromDate.Value}' AND '{dtToDate.Value}' AND zei.ZPZ_LPE_ID='{userID.ToString()}' GROUP BY per.LPE_Nr, zei.ZPZ_LPE_ID, zei.ZPZ_Datum, zei.ZPZ_Von, zei.ZPZ_Bis ORDER BY zei.ZPZ_Datum, per.LPE_Nr;";
using (SqlCommand cmd = new SqlCommand(query, db))
{
using (SqlDataAdapter da = new SqlDataAdapter(cmd))
{
using (SqlDataReader dr = cmd.ExecuteReader())
{
var items = new BindingList<PRAESENZZEIT>();
while (dr.Read())
{
PRAESENZZEIT pra = new PRAESENZZEIT();
pra.ZPZ_Datum = Convert.ToDateTime(dr["ZPZ_Datum"]);
pra.ZPZ_Von = Convert.ToDateTime(dr["ZPZ_Von"]);
if (pra.ZPZ_Von.TimeOfDay < new TimeSpan(8, 5, 0))
pra.ZPZ_Von = new DateTime(pra.ZPZ_Von.Year, pra.ZPZ_Von.Month, pra.ZPZ_Von.Day, 8, 0, 0);
// DateTime gehen = DateTime.Now;
pra.ZPZ_Bis = Convert.ToDateTime(dr["ZPZ_Bis"]);
pra.arbeitszeit = pra.ZPZ_Bis - pra.ZPZ_Von;
// Convert.ToString(Convert.ToInt32(arbeitszeit));
items.Add(pra);
}
pRAESENZZEITBindingSource.DataSource = items;
}
}
}
}
this is the PRAESENZEIT class
public class PRAESENZZEIT
{
public int LPE_Nr { get; set; }
public DateTime ZPZ_Datum { get; set; }
public double ZPZ_Std100 { get; set; }
public int ZPZ_LPE_ID { get; set; }
public DateTime ZPZ_Von { get; set; }
public DateTime ZPZ_Bis { get; set; }
public DateTime ZPZ_Std { get; set; }
public int ZPZ_ID { get; set; }
public int ZPZ_Jahr { get; set; }
public int ZPZ_Monat { get; set; }
public int ZPZ_Tag { get; set; }
public DateTime ZPZ_ERFDAT { get; set; }
public string ZPZ_ERFUSER { get; set; }
public DateTime ZPZ_MUTDAT { get; set; }
public string ZPZ_MUTUSER { get; set; }
public TimeSpan arbeitszeit { get; set; }
}
Thank you all for help
mysql query result
If Studen is a TimeSpan you can sum it that way.
var dataSource = new List<grdata> {
// StartDate , EndDate
new grdata("01/03/2017 04:00","01/03/2017 08:00"),
new grdata("01/03/2017 09:00","01/03/2017 14:00"),
new grdata("13/12/2017 04:30","13/12/2017 09:00"),
new grdata("13/12/2017 10:00","13/12/2017 14:00")
};
var opdata = dataSource.Select(x => new
{
date = DateTime.Parse(x.start.ToShortDateString()) ,
time = x.end-x.start
});
var result = opdata.GroupBy(x => x.date)
.Select(g => new
{
date = g.Key,
sumTime = new TimeSpan(g.Sum(y => y.time.Ticks))
});
var totalSum = new TimeSpan(opdata.Sum(y => y.time.Ticks));
Result:
{ date = {01/03/2017 00:00:00}, sumTime = {00:09:00} }
{ date = {13/12/2017 00:00:00}, sumTime = {00:08:30} }
I guess you want to group by day. You can check if you already added the day and add the time to arbeitszeit. However then the fields 'von' and 'bis' are useless. This is basically because the class design is quite bad. You could have a class ArbeitsTag which contains a property List<Anwesenheit> and a property Gesamtzeit aka Totaltime where you sum up all the times. But that's a different story ;-)
var items = new BindingList<PRAESENZZEIT>();
while (dr.Read())
{
PRAESENZZEIT pra = null;
DateTime datum = Convert.ToDateTime(dr["ZPZ_Datum"]);
//calculate parse from and to. Don't store it to Präsenzzeit as it will be accumulated. Therefore it will always be wrong. possible solution would be to store each "phase" separatly and calculate a Total time from there...
DateTime von = Convert.ToDateTime(dr["ZPZ_Von"]);
if (von.TimeOfDay < new TimeSpan(8, 5, 0))
von = new DateTime(von.Year, von.Month, von.Day, 8, 0, 0);
DateTime bis = Convert.ToDateTime(dr["ZPZ_Bis"]);
pra = items.FirstOrDefault(x => x.ZPZ_Datum == datum);
//check if day was already added
if (pra != null)
{
pra.arbeitszeit = pra.arbeitszeit + (bis - von);
}
else
{
pra = new PRAESENZZEIT();
pra.ZPZ_Datum = datum;
// DateTime gehen = DateTime.Now;
pra.arbeitszeit = bis - von;
// Convert.ToString(Convert.ToInt32(arbeitszeit));
items.Add(pra);
}
}

Group by day, time and id in one LINQ

I have a list of Example class elements:
public class Example
{
public long Id { get; set; }
public string Name { get; set; }
public DateTime SomeDate { get; set; }
}
Now I want to group it using ONE LINQ to make the following hierarchy:
public class GroupedByDay
{
public List<GroupedByTime> TimeGroup { get; set; }
}
public class GroupedByTime
{
public List<GroupedById> IdGroup { get; set; }
}
public class GroupedById
{
public string Name { get; set; }
}
So, the result is a list of type List<GroupedByDay> with the Examples grouped by days, hours (timespans?) within these days and finally by ids.
Can anyone help me with it?
[edit]
This is what I tried to group by Ids, but I think I should start from the other side maybe?
var result =
examples
.GroupBy(e => e.Id, e => new GroupedById
{
Name = e.Name
});
If you just want to group for displaying purposes, you don't need the classes GroupedByDay, GroupedByTime and GroupedById
Considering examples is an IEnumerable<Example>
var groupedExamples = from example in examples
group example by new {
example.SomeDate.Date, //Day
example.SomeDate.Hour, // Hour
example.Id // Id
} into g
select g;
Then you'll have an IEnumerable<IGrouping<,Example>> with the desired grouping:
foreach(var g in groupedExample){
Console.WriteLine(String.Format("Day {0} at hour {1} with id {2}", g.Key.Date, g.Key.Hour, g.Key.Id));
foreach(var example in g)
Console.WriteLine(" - " + example.Name);
}
I Usually write these code
public static DateTime GetDateByWeekDay(DateTime startDate, int week, Int32 day)
{
int Year = Getyear(startDate);
DateTime jan1 = new DateTime(Year, 1, 1);
int daysOffset = DayOfWeek.Monday - jan1.DayOfWeek;
DateTime firstMonday = jan1.AddDays(daysOffset);
var cal = CultureInfo.CurrentCulture.Calendar;
int firstWeek = cal.GetWeekOfYear(firstMonday, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
var weekNum = week;
if (firstWeek <= 1)
{
weekNum -= 1;}
var result = firstMonday.AddDays(weekNum * 7);
return result.AddDays(day);
}

Categories

Resources