linq query with time zones groupby - c#

I have a linq-to-sql query that works by grouping the data it retrieve in days for a particular month:
var Output = from c ....
where .... // this is the month parameter
group c by c.TheTime.Date into daygroups
select new MyModel(){
Prop1 = (from x in daygroups
where....
select x.ID).Count()
}.ToList();
The problem is that this groups by datetime in terms of server time. I'd like to group them by interval of times so that if we're looking at the result with California time, we're really looking at a list of days that starts at midnight PST.
The query returns a count. The solution I've figured out for now would be to return all the raw data between the beginning and the end of the month in a certain timezone, and then rearranging the raw data in days with the correct timezone, and only then do the count.
Is there a better way to do this?

Try grouping by c.TheTime.Date.AddHours(-8).
However, I'm not sure whether that will work correctly.

Related

DateTime comparison in LINQ not returning correct results

I have the following LINQ to query the database and retreive deleted products from a particular date.
return _myDbEntities.Log
.Where(p => p.Action.Equals("Deleted") &&
(p.ActionDate > fromDate))
.Select(p => new DeletedProduct()
{
ProductId = p.ProductId,
ActionDate = p.ActionDate
}).ToList();
However, the query is retreiving values like product.ActionDate.Value = {12/8/2016 11:41:00 AM} when the fromDate was fromDate = {12/8/2016 11:41:00 AM}
The query clearly says GREATER THAN. What is happening here?
There are fractions of a second to each of your properties. Most likely, your record wasn't created at an exact second, whereas any user-created time would be set as such.
Another possibility is the difference between datetime and datetime2 in SQL Server.
The DateTime type stores time at much higher precision than seconds. They could be differing at millisecond or even tick (100 nanoseconds) level.
If you want to compare on a higher level, try this:
(p.ActionDate.Ticks / 10000000) > (fromDate.Ticks / 10000000)
Where 10000000 is the number of ticks in a second. Since the /is an integer division that does truncate the fraction, you turn ticks into full seconds.
UPDATE:
It seems like you are using entity framework. The comparison above will possibly not work there. The solution is to run your original query against the database, do a ToList and then filter the results again in a LINQ2Objects query using the logic above.

How to add empty groups to a Linq query result set?

I have a very simple query which selects items from a table based on matching the month and then grouping by day. These groups are then used as a data source for a repeater which outputs the group elements as entries "per day".
The problem is that days that don't exist (i.e. there's no group for) will naturally not be displayed, so things for the 6th and 8th, when there's nothing for the 7th, will be seen directly next to each other (think of a calendar view). The question is, given my query below, how could I insert groups with no elements, even when there's no entry for that day?
IQueryable events =
Events
.Where(i => i.Date.Month == date.Month)
.GroupBy(i => i.Date.Day);
I can do this figuring out after the fact, but can I account for it to get the result set at once? Or can a previous tried & tested approach be recommended?
Create your result set like this:
var date = ...;
var events = Enumerable.Range(1, DateTime.DaysInMonth(date.Year, date.Month))
.ToDictionary(
day => new DateTime(date.Year, date.Month, day),
day => new List<Event>());
Then insert into it like this:
var query = Events
.Where(e => e.Date.Year == date.Year)
.Where(e => e.Date.Month == date.Month);
foreach (var e in query)
events[e.Date].Add(e);
If you really want to do this server-side as part of the query, you'll either need to (A) send the list of dates you're interested in as part of the query, or (B) use DBMS-specific functions to construct the set of days you're interested in server-side.
Specific to (B) and SQL, there are things like this: Get the first and last date of next month in MySQL
I personally would just do this client-side. The database query gets whatever data your implementation needs to extract from the database; the user gets whatever information your view needs. To query the database for the data you need to create your view, you don't actually need to know the list of dates in your month, so it really shouldn't be part of the query.

Set time to zeroes in LINQ-to-Entities query which includes datetime column

I'm not sure if it's possible but I've been trying for half a day to use only date for filtering records in MS SQL database and I get to this question. I'm using Repository pattern so I get all records for my entity like this :
var rows = DocumentsRepository.All();
The table Documents has column Date of type datetime, I need to keep the time in the database but when I prepare it for filtering I want to use only the date and if possible to set the hours, minutes, seconds and millisecs to zeroes.
Is it possible and how to do it inside a LINQ?
I would guess EntityFunctions.TruncateTime(datetimeObj) does the trick if you are using EF in your repository.
IQueryable<Entity> query = query.Where(x => EntityFunctions.TruncateTime(x.CreatedAt) == DateTime.Today);
var someList = query.ToList();

How do I perform date-part comparison in EF

i heard people saying date time comparison do not work just due to time part because datetime has time part.
in sql i always compare datetime like this way and it works fine
select * from employee
where convert(varchar,dob,112) > '20111201' // this yyyymmdd format.
how could i simulate this in a LINQ query?
If you're using .NET 4 or above, just use the EntityFunctions.TruncateTime helper method. This will translate this type of datetime-to-date conversion to SQL for you.
from e in EfEmployeeContext
where EntityFunctions.TruncateTime(e.DOB) > new DateTime(2011,12,01);
The one thing to keep in mind is that operations on DateTime structs that represent database columns don't translate to SQL. So, you cannot write a query like:
from e in EfEmployeeContext
where e.DOB.Date > new DateTime(2011,12,01);
... because e.DOB represents the DOB column in the database, and EF won't know how to translate the Date sub-property.
However, there's an easy workaround depending on what dates you want:
If you want to include all employees that have a DOB on 12/01/2011 as well as those born after that date, then simply query:
from e in EfEmployeeContext
where e.DOB > new DateTime(2011,12,01);
If you want to include only employees born after 12/01/2011, then query:
from e in EfEmployeeContext
where e.DOB >= new DateTime(2011,12,02);
In short, the criteria, meaning a constant or literal DateTime you're comparing against, can be set up however you want. You just can't make radical modifications to properties that represent DB columns within the where predicate. That means you can't compare one DateTime column to a projection of another DateTime column, for instance:
//get all employees that were hired in the first six months of the year
from e in EfEmployeeContext
where e.HireDate < new DateTime(e.HireDate.Year, 7, 1);

Select most recent entry from database using LINQ to Entities

I need to select the most recent date from my database table and store it in a variable.
I'm not very familiar with linq to entities but I gave it a go myself however I only got so far.
This is how far I got:
IQueryable<DateTime> date = from ftp in ctn.FTPRuns
orderby ftp.LastRun descending
select ftp.LastRun;
Can anyone tell me how I can modify this query to just select the most recent entry. I have tried "select ftp.LastRun.First();" however this is not an option in intellisense for me.
any help would be appreciated.
thanks.
The result of what you have there (date) is an ordered IQueryable. You can just call date.First() to get the first one in that sequence.
Otherwise if you want to cut a step, wrap your query in brackets and call.First on it to just get the date.
DateTime date = (from ftp in ctn.FTPRuns
orderby ftp.LastRun descending
select ftp.LastRun).First();
You could otherwise use lambdas:
DateTime date = ctn.FTPRuns.OrderByDescending(f => f.LastRun).First().LastRun;
IQueryable<DateTime> dates = from ftp in ctn.FTPRuns
orderby ftp.LastRun descending
select ftp.LastRun;
DateTime date = dates.First();

Categories