How to convert an Interval to a LocalDate range in NodaTime? - c#

I'm running into a scenario where I need to convert an Interval value to Enumerable collection of LocalDate in NodaTime. How can I do that?
Below is the code
Interval invl = obj.Interval;
//Here is the Interval value i.e.,{2016-10-20T00:00:00Z/2016-11-03T00:00:00Z}
How can I form a Date range between these intervals?
Thanks in advance.

A slightly alternative approach to the one given by Niyoko:
Convert both Instant values into LocalDate
Implement a range between them
I'm assuming that the interval is exclusive - so if the end point represents exactly midnight in the target time zone, you exclude that day, otherwise you include it.
So the method below includes every date which is covered within the interval, in the given time zone.
public IEnumerable<LocalDate> DatesInInterval(Interval interval, DateTimeZone zone)
{
LocalDate start = interval.Start.InZone(zone).Date;
ZonedDateTime endZonedDateTime = interval.End.InZone(zone);
LocalDate end = endLocalDateTime.Date;
if (endLocalDateTime.TimeOfDay == LocalTime.Midnight)
{
end = end.PlusDays(-1);
}
for (LocalDate date = start; date <= end; date = date.PlusDays(1))
{
yield return date;
}
}

Use this code:
var l = Enumerable.Range(0, int.MaxValue)
.Select(x => Period.FromDays(x))
.Select(x => LocalDate.Add(interval.Start.InZone(localZone).Date, x))
.TakeWhile(x => x.CompareTo(interval.End.InZone(localZone).Date) <= 0);
Example:
var localZone = DateTimeZone.ForOffset(Offset.FromHours(7));
var start = Instant.FromDateTimeOffset(new DateTimeOffset(new DateTime(2016, 10, 1)));
var end = Instant.FromDateTimeOffset(new DateTimeOffset(new DateTime(2016, 10, 25)));
var interval = new Interval(start, end);
var l = Enumerable.Range(0, int.MaxValue)
.Select(x => Period.FromDays(x))
.Select(x => LocalDate.Add(interval.Start.InZone(localZone).Date, x))
.TakeWhile(x => x.CompareTo(interval.End.InZone(localZone).Date) <= 0);
foreach (var localDate in l)
{
Console.WriteLine(localDate);
}

Related

.net core how to get week datetime list by datetime range

I hope get week datetime list by datetime range,I tried the following code get number of weeks per month.
var start = new DateTime(2021, 6, 09);
var end = new DateTime(2021, 7, 01);
end = new DateTime(end.Year, end.Month, DateTime.DaysInMonth(end.Year, end.Month));
var diff = Enumerable.Range(0, Int32.MaxValue)
.Select(e => start.AddMonths(e))
.TakeWhile(e => e <= end)
.Select(e => Convert.ToDateTime(e.ToString("yyyy-MM")));
foreach (var item in diff)
{
DateTime dateTime = item;
Calendar calendar = CultureInfo.CurrentCulture.Calendar;
IEnumerable<int> daysInMonth = Enumerable.Range(1, calendar.GetDaysInMonth(dateTime.Year, dateTime.Month));
List<Tuple<DateTime, DateTime>> weeks = daysInMonth.Select(day => new DateTime(dateTime.Year, dateTime.Month, day))
.GroupBy(d => calendar.GetWeekOfYear(d, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday))
.Select(g => new Tuple<DateTime, DateTime>(g.First(), g.Last()))
.ToList();
}
Executing the above code I got the following result,get all the weeks of each month。
2021-06-01 2021-06-06
......
2021-07-26 2021-07-31
I want to count the week from my start date 2021-06-09 to the end date 2021-07-01, like this.
2021-06-09 2021-06-13
2021-06-14 2021-06-20
2021-06-21 2021-06-27
2021-06-28 2021-07-01
how to changed my code
This will produce the desired output:
var start = new DateTime(2021, 6, 09);
var end = new DateTime(2021, 7, 01);
// If you want to get the first week complete, add this line:
//DateTime currDate = start.AddDays(1-(int)start.DayOfWeek);
// Otherwise, use this one
DateTime currDate = start;
while(currDate <= end){
var dayOfWeek = (int)currDate.DayOfWeek;
var endOfWeek = currDate.AddDays(7 - dayOfWeek);
//If you want the complete last week, omit this if
if(endOfWeek > end)
{
endOfWeek = end;
}
Console.WriteLine($"{currDate:yyyy-MM-dd} {endOfWeek:yyyy-MM-dd}");
currDate = endOfWeek.AddDays(1);
}
output:
2021-06-09 2021-06-13
2021-06-14 2021-06-20
2021-06-21 2021-06-27
2021-06-28 2021-07-01

Get the number of hours between time Period

I have run in a scenario where i need to find the total number of hours that falls on a current period. I Have a Time in and TimeOut datetime which i want to get the hours where the employee worked between 10pm-4am the following day. How would i get the output of hours worked.
I Created an Extension method like this:
public static decimal GetNightDifferentialValue(this DailyTime dtr, Employee201 employee, PayrollSettings settings, IEnumerable<Holidays> holidays)
{
//know if the time out is greater than 10pm of the dtr
//07-26-2016 14:00 - 07-27-2016 03:00
//if time out i
var days = Enumerable.Range(0, (int)(dtr.TimeOut - dtr.TimeIn).TotalHours + 1)
.Select(i => dtr.TimeIn.AddHours(i))
.Where(date => !(date.Hour >= 22)).Count();
return days* employee.Rate;
}
my problem is in the Where Method how can i Filter the hours that only fall on my category
public static decimal GetNightDifferentialValue(this DailyTime dtr, Employee201 employee, PayrollSettings settings, IEnumerable<Holidays> holidays)
{
//know if the time out is greater than 10pm of the dtr
//07-26-2016 14:00 - 07-27-2016 03:00
//if time out i
DateTime dayIn10pm = new DateTime(dtr.TimeIn.Year, dtr.TimeIn.Month, dtr.TimeIn.Day, 22, 0, 0);
DateTime dayAfter04am = dayIn10pm.Add(new TimeSpan(6,0,0));
var hours = Enumerable.Range(0, (int)(dtr.TimeOut - dtr.TimeIn).TotalHours + 1)
.Select(i => dtr.TimeIn.AddHours(i))
.Where(date => (date > dayIn10pm && date <= dayAfter04am)).Count();
return hours;
}
I see the problem is only with filtering, I would suggest compare Date part to determine is it next Date, if it is next date Look for TimeOfDay to compare Time
var t = TimeSpan.ParseExact("04:00:00", #"hh\:mm\:ss", CultureInfo.InvariantCulture);
var days = Enumerable.Range(0, (int)(dtr.TimeOut - dtr.TimeIn).TotalHours + 1)
.Select(i => dtr.TimeIn.AddHours(i))
.Where(date => (date.Date == TimeOut.Date && date.TimeOfDay <= t) || date.Hour >= 22)
.Count();
Check this Demo
I think this does what you want:
if (timeOut.Hour > 4)
{
timeOut = timeOut.Date.AddHours(4);
}
if (timeIn.Hour < 22)
{
timeIn = timeIn.Date.AddHours(22);
}
if (timeIn > timeOut)
{
// No overnight time
return 0;
}
var difference = timeOut - timeIn;
return difference.TotalHours;
Basically, we first normalize the dates:
If the employee got here before 10PM, consider he was there at 10PM
If the employee left after 4AM, consider he left at 4AM
From there, we just have to subtract the two dates, and handle the special case where the new timeIn is greater than the new timeOut (if, for instance, he worked from 2PM to 5PM). In which case it means there's no time between 10PM and 4AM, so we just return 0.
Note that this algorithm doesn't handle the case where the employee works more than 24 hours straight.
private void CalculateTotalHour(string dtstartTime, string dtendTime)
{
DateTime d1 = new DateTime();
d1 = Convert.ToDateTime(dtstartTime); DateTime d2 = new DateTime();
d2 = Convert.ToDateTime(dtendTime);
if (d1.Hour >= 12)
{
d1 = d1.AddDays(-1);
}
else if (d2.Hour >= 12)
{
d2 = d2.AddDays(1);
}
// if (d2 < d1)
// MessageBox.Show("shift end time is lesser than shift start time", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Stop);
TimeSpan ts = d2.Subtract(d1).Duration();
// ts.ToString(#"hh\:mm")//total dur
}
Get what I want but is not that good looking solution here is my solution:
var timeIn = new DateTime(2016, 7, 25, 14, 0, 0);
var timeOut = new DateTime(2016, 7, 26, 5, 0, 0);
if ((timeOut.Date - timeIn.Date).TotalDays >= 1)
{
var hrs12to4am = Enumerable.Range(0, (int)(timeOut - timeIn).TotalHours + 1)
.Select(i => timeIn.AddHours(i)).Where(a => a.Hour < 4 && a.Date > timeIn).ToList();
var hrsOverTen = Enumerable.Range(0, (int)(timeOut - timeIn).TotalHours + 1)
.Select(i => timeIn.AddHours(i)).Where(a => a.Hour > 22).ToList();
}
else
{
var hrsOverTen = Enumerable.Range(0, (int)(timeOut - timeIn).TotalHours + 1)
.Select(i => timeIn.AddHours(i)).Where(a => a.Hour > 22).ToList();
}
here is the demo Demo
i think this is your answer
int hours = (int)(dt2 - dt1).TotalHours;

Get nearest dates

List<DateTime>
"2015-03-21 13:00:00"
"2015-05-15 13:00:00"
"2015-05-24 13:00:00"
"2015-05-27 13:00:00"
"2015-06-14 13:00:00"
I am having start date (2015-05-21 13:00:00) and end date (2015-06-09 22:00:00)
Actually I need to get the two dates from the above array which are closer or equal to start date and end date.
Note additionally that the date that is closest to the start date should be equal to or before start date and the date that is closest to the end date should be equal to or after the end date. In other words, given the list of dates, find the smallest date range that encloses start and end date.
In this case, the output will be "2015-05-15 13:00:00" and "2015-06-14 13:00:00".
How to acheive this in c#?
void Main()
{
var dates = new string[]
{
"2015-03-21 13:00:00",
"2015-05-15 13:00:00",
"2015-05-24 13:00:00",
"2015-05-27 13:00:00",
"2015-06-14 13:00:00"
}
.Select(x => DateTime.Parse(x))
.ToList();
var start = DateTime.Parse("2015-05-21 13:00:00");
var end = DateTime.Parse("2015-06-09 22:00:00");
Console.WriteLine(dates
.Where(x => x <= start)
.OrderByDescending(x => x)
.FirstOrDefault());
Console.WriteLine(dates
.Where(x => x >= end)
.OrderBy(x => x)
.FirstOrDefault());
}
// the date must be outside of boundary, so this is no longer good...
//public static DateTime GetClosestDate(IEnumerable<DateTime> source, DateTime date)
//{
// return source
// .OrderBy(x => Math.Abs((x.Date - date).TotalSeconds))
// .First();
//}
Result:
GetClosestDate:
2015-05-24 13:00:00
2015-06-14 13:00:00
Where OrderBy[Descending] FirstOrDefault:
2015-05-15 13:00:00
2015-06-14 13:00:00
public DateTime? GetClosest(List<DateTime> dates, DateTime dateToCompare)
{
DateTime? closestDate = null;
int min = int.MaxValue;
foreach (DateTime date in dates)
{
if (Math.Abs(date.Ticks - dateToCompare.Ticks) < min)
{
min = date.Ticks - dateToCompare.Ticks;
closestDate = date;
}
}
return closestDate;
}
Simple search on google relates to this

Convert only date to Date and Time format in c#

I want to count data of each day from database using the for loop. Here, I don't know to get the begining of day (start from 12 am) and end of that day ( 12 pm) from value of only date. In below code startDate and endDate have only date value e.g. 2/11/2012.
for (DateTime dates = startDate; dates <= endDate; dates.AddDays(1))
{
DateTime BeginingOfDay = begining of value variable dates; // 2/2/2012 00:00:00
DateTime EndOfDay = at end of value variable dates; // 2/2/2012 23:59:59
int count = (from u in db.CDRs where (u.StartTime >= BeginingOfDay && u.StartTime <= EndOfDay) select u).Count();;
dictionary.Add(dates.ToString("MM/dd/yyyy"), count);
}
The best way to deal with this is to use the right combination of lessthan/greaterthan operators with midnight on day n, and midnight on day n+1
so given a day, eg
var date = new Date(2012,8,24); // today
get midnight on that day (start of the day)
var start = new Date(date.Year, date.Month, date.Day, 0,0,0); // could also be date.Date
and to get midnight on the next day just add 1 day
var end = start.AddDays(1);
now use greater-than-or-equal-to for the start, and less-than for the end:
var inRange = x.StartTime>=start && x.EndTime<end
Put together into your example becomes:
for (DateTime dates = startDate; dates <= endDate; dates.AddDays(1))
{
DateTime BeginingOfDay = new DateTime(dates.Year,dates.Month,dates.Day,0,0,0);
DateTime EndOfDay = BeginingOfDay.AddDays(1);
int count = (from u in db.CDRs where (u.StartTime >= BeginingOfDay && u.StartTime < EndOfDay) select u).Count();;
dictionary.Add(dates.ToString("MM/dd/yyyy"), count);
}
This should get you the results you want:
using(var dataContext = new YourDataContext())
{
var dictionary = dataContext.CDRs.GroupBy(u => new
{
u.StartTime.Year,
u.StartTime.Month,
u.StartTime.Day
})
.Select(g => new{ Date = g.Key, Count = g.Count() })
.ToDictionary(g => new DateTime(g.Key.Year, g.Key.Month, g.Key.Day), g=>g.Count);
return dictionary;
}

Get List of weeks by giving year and month as parameter C#

I need list of weeks with starting and ending dates by giving int year and int month,
Example Result,
Week1 = 7/1/2012 to 7/1/2012
Week2 = 7/2/2012 to 7/8/2012
Week3 = 7/9/2012 to 7/15/2012
Week4 = 7/16/2012 to 7/22/2012
Week5 = 7/23/2012 to 7/29/2012
Week6 = 7/30/2012 to 7/31/2012
Something like this should work:
// using System.Globalization;
var calendar = CultureInfo.CurrentCulture.Calendar;
var firstDayOfWeek = CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek;
var weekPeriods =
Enumerable.Range(1, calendar.GetDaysInMonth(year, month))
.Select(d =>
{
var date = new DateTime(year, month, d);
var weekNumInYear = calendar.GetWeekOfYear(date, CalendarWeekRule.FirstDay, firstDayOfWeek);
return new { date, weekNumInYear };
})
.GroupBy(x => x.weekNumInYear)
.Select(x => new { DateFrom = x.First().date, To = x.Last().date })
.ToList();
Of course you can change the Culture (here I have used the CurrentCulture).
check this one and edit according to your need
// Get the weeks in a month
DateTime date = DateTime.Today;
// first generate all dates in the month of 'date'
var dates = Enumerable.Range(1, DateTime.DaysInMonth(date.Year, date.Month)).Select(n => new DateTime(date.Year, date.Month, n));
// then filter the only the start of weeks
var weekends = (from d in dates
where d.DayOfWeek == DayOfWeek.Monday
select d).ToList();
foreach (var d in weekends)
{
Console.WriteLine(d);
}
Console.Write(weekends);
Console.ReadLine();
hope it help you.
you can also take a look here for other stuff HERE

Categories