Compare two dates without a year - c#

I would like to compare two dates excluding years.
Ex.
Input: FromDate: 01 March, ToDate: 05 March
then all records between these two dates should be come whether there is any year. It does not matter.
So please anyone can help me in this issue.
Thanks in advance.

If you are using LINQ and you want to create a list from querying the db you could do this?
public IEnumerable<Item> WithinTimeRange(DateTime begin, DateTime end)
{
var items = from a in context.Items
where a.Timestamp.Month.Equals(begin.Month) && a.Timestamp.Day
>= begin.Day && a.Timestamp.Month.Equals(end.Month) && a.Timestamp.Day <= end.Day
select a;
return items.ToList();
}
Personally I would create this method in your repository.

Whether you don't specify language and place where it will be used, I just give ju a hint.
Convert every datetime to a integer as: 10000 + 100 * month + day e.g.: 10306 as today.
Then you can ask for every data between 10301 and 10305 from your question.

Related

Check specific days exist in a set range of given weeks and add to list

What would be the best choice in getting and returning a list of specific dates between a 3 week range?
My intent is to create delivery dates based on a delivery centre's given days they are available
public List<DayOfWeek> DeliveryDays { get; set; }
DeliveryDays contains set values from 0-6 (0 being Sunday, 1 Monday, etc.)
I want to get those values, pass them through 3 weeks worth of following dates, and return those delivery days in a list (so only those centre's can order on select days).
Here's what I have so far:
public List<DateTime> CalculateAvailableDeliveryDates()
{
//Loop through 3 weeks of days
DateTime today = DateTime.Today; //Specify today's date
DateTime totalDateCount = today.AddDays(1); //Plus one day on each time counted
var dates = Enumerable.Range(0, 21).Select(days => totalDateCount.AddDays(days)).ToList(); //Count from 0 to 21 (3 weeks worth of days). On each count, run totalDateCount
//if exists in deliveryDayList
//add to dates via dates.Add func
if (DeliveryDays.Contains(DayOfWeek.Monday))
{
//action
} //and so on for each day
//return specific dates from date range
return dates;
}
currently I get a readout of 21 days. The if statement does nothing and is only serving as an example of my logic.
Would the best method be: rather than getting a list first, to do a check and nest if/case statements based on the DeliveryDates per centre and then return them into a list?
Thanks in advance.
Given a list of DayOfWeek, you can select all dates in the next 21 days that match one of those days of the week using System.Linq. The Enumerable.Range selects a range of numbers, Select will then select a bunch of DateTime objects representing Today plus some number of days, and Where is used to filter the results, comparing the DayOfWeek for each date to see if it exists in DeliveryDays:
List<DayOfWeek> DeliveryDays = new List<DayOfWeek>();
public List<DateTime> GetAvailableDeliveryDates()
{
// 1. Get a range of numbers representing the days to add
// to today, which will make up our range of dates
// 2. Select a date using Today.AddDays for each number
// 3. Filter on only days which are contained in DeliveryDays
return Enumerable.Range(0, 21) // Define the range
.Select(i => DateTime.Today.AddDays(i)) // Select the range
.Where(date => DeliveryDays.Contains(date.DayOfWeek)) // Filter the range
.ToList();
}

Issue with DateTime

I could swear this was working two days ago, now it throws an exception...
I am checking against some data in a DataTable. I'm basically counting how many times a certain eventID is found within the last 15 minutes. Here's that code:
int startevents = trackingData
.Select("RHEventID = 3 AND RHDateEvent > #" + now + "#" ).Length;
I'm defining the 'now' variable just before that - looks like this:
DateTime now = DateTime.Now.AddMinutes(-15);
However this throws a String was not recognized as a valid DateTime exception. Here is an example of the data in the datatable, in the column for RHDateEvent:
2017-02-14 13:58:27 PM
(edit - yes this is only one date, not two, in the column)
So what am I doing wrong? Do I need to be converting this DateTime somehow?
I'd really recommend to use Linq-To-DataTable instead of the old and limited Select method:
DateTime in15minutes = DateTime.Now.AddMinutes(15);
var matchingRows = from row in trackingData.AsEnumerable()
where row.Field<int>("RHEventID) == 3
&& row.Field<DateTime>("RHDateEvent") > in15minutes
select row;
if you now just need the count use:
int matchingRowCount = matchingRows.Count();
This is more readable, powerful and supports compile time safety.
If your column is a not a DateTime- but a string-column you need to parse it:
...
&& DateTime.Parse(row.Field<string>("RHDateEvent"), CultureInfo.InvariantCulture) > in15minutes
It looks like the date time is duplicated...
2017-02-14 13:58:27 PM 2017-02-14 13:57:27 PM
instead of
2017-02-14 13:58:27 PM
If it's linq to entities use
var startevents = trackingData.Where(e => e.RHEventId = 3 && e.RHDateEvent >= DateTime.Now.AddMinutes(-15)).Count();

Get Month of out System Datetime

I have data in my database that contains the following filed.
Id | name | RegDate
1 John 2014-09-05
2 mike 2014-09-05
3 Duke 2014-10-14
I'm performing a query to count the number of values where the reg date is equal 09. 09 is the month of the date.
I'm trying to convert the date I store in db in a month format then get a new month of a system date to get the result.
Here is my query in linq but it keeps on giving the wrong count. please I need your help. thanks.
var CountPassengers = (from c in db.CountPassengerManifestViews where c.DepartureDate.Month.ToString()== DateTime.Now.AddMonths(-1).ToString("MM") select c).Count();
I would strongly recommend that you get rid of all the string manipulation. Your query doesn't conceptually have anything to do with strings, so why are you introducing them into the code?
You can write your query as:
int currentMonth = DateTime.Today.AddMonths(-1).Month;
var passengerCount = db.CountPassengerManifestViews
.Count(c => c.DepartureDate.Month == currentMonth);
However, that will only filter by month - it won't filter by month and year, so if you have data from 2013 that would be included too. It's more likely that you want something like:
DateTime oneMonthAgo = DateTime.Today.AddMonths(-1);
DateTime start = oneMonthAgo.AddDays(1 - oneMonthAgo.Day);
DateTime end = start.AddMonths(1);
var passengerCount = db.CountPassengerManifestViews
.Count(c => c.DepartureDate >= start &&
c.DepartureDate < end);
That way you're expressing a range of dates, rather than just extracting the month part.
where c.DepartureDate.Month == DateTime.Now.AddMonths(-1).Month
You don't compare string representation, because it's already converted into DateTime object, so it doesn't make sense to do it your way. This simple change should be enough.
I am not sure why you are doing the string manipulation but if you only want to compare the month part of the two dates then do the following:
where c.DepartureDate.Month== DateTime.Now.AddMonths(-1).Month
I think your code compares Month.ToString() that gives "9" with ToString("MM") that gives "09".
You could also improve by removing ".ToString()":
int lastMonth = DateTime.Now.AddMonths(-1).Month;
var CountPassengers = (from c in db.CountPassengerManifestViews where c.DepartureDate.Month == lastMonth select c).Count();
Regards
Try this
var CountPassengers = (from c in db.CountPassengerManifestViews
where c.DepartureDate.Month.ToString("MM")== DateTime.Now.AddMonths(-1).ToString("MM")
select c).Count();
var month = DateTime.Now.AddMonths(-1).Month;
var CountPassengers = db.CountPassengerManifestViews.Count(c => c.DepartureDate.Month == month);

Linq datetime compare in where clause

I have a table with a couple of columns called Key and Value.
One of the Keys is called RequestedOn and the value is a timestamp saved as a string.
Now in my linq query I would like to compare this timestamp, for example
var startDate = DateTime.Now.AddDays(-7);
var endDate = DateTime.Now;
var query = (from ep in db.ExtendedProperties
where
ep.Key == "RequestedOn" && ep.Value >= startDate && ep.Value <= endDate
select ep).ToList();
Now I know I cannot compare ep.Value (string) against startDate or endDate, and I cannot convert ep.Value to a DateTime as it couldn't make sense. Any ideas on a solution?
Thanks in advance?
if its saved as string you must parse it to DateTime and then compare
You can either:
Convert the DateTime to string
Convert the string to DateTime
Write a method that compares the 2 directly
Something else
Using LINQ for something that does not have a type and contains different data is not a good option. The whole point of LINQ is to have types.
That being said one solution to your problem is to save the date in a format that is comparable as string such as 201405231801 (being 23.05.2014 18:01) and just compare strings.
Of course you care about timezones and daylight saving time you are guaranteed to get it wrong.
If you save your strings right you can actually do a comparison:
For example: '20131201125959': year, month, date, hours, minutes, seconds.

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