I have a linq-to-sql query that groups results by DateTime, something like this:
var TheQuery = from ....
where ....
group a by a.TheDateTime.Date in TheGroups
The problem is that this groups by actual dates that are stored in UTC in the DB. Let's say that I want to group by dates based on the user's timezone. So for instance, if he's in the PST timezone, group by "UTC minus 8 hours", or whatever other offset.
Thanks for your suggestions.
If you're getting all the information back anyway, I'd frankly bring it back to the client and do the grouping in LINQ to Objects. That way you can concentrate on using one platform's date and time API - it's hard enough using one API correctly when it comes to time zones, let alone two.
(As an aside and a plug, it also means you can use whatever .NET API you like for this - such as Noda Time ;)
So I'd put all the filtering and projection you can do before the grouping, then use AsEnumerable() to force the rest of the execution to occur locally.
Don't forget that you almost certainly can't just add or subtract 8 hours, unless the user is really in a time zone which doesn't use daylight saving time (and hasn't historically). Are you also sure that it's appropriate to apply the same time zone to all the data? (It may well - just checking.)
Related
Hopefully not a repost of another... a rather simple question, but I think I'm fundamentally confused about how dates/times with timezones are handled between Postgres and c#.
Simple situation, at one point in the program I call DateTime.Now and save to a variable 'now'. This is inserted into a Postgres DB.
cmd.Parameters.AddWithValue("createdat", now);
Great. The column that this is inserted into is of type "timestamp with time zone". When I view the result from something like DataGrip or DBeaver the raw data is exactly what I want (I think).
2021-03-09 15:07:51
Later on I query this table in a rather simple way.
SELECT createdat FROM mytable WHERE mycondition;
I cast it as a c# DateTime type and populate a class with it.
while (reader.Read())
{
myClass.createdAt = (DateTime) reader["createdat"];
}
However, the value is populated as the following:
3/9/2021 10:07:51 AM
Something is not working here. First, if the column in the DB is of timestamp with time zone, where is the time zone information? Second, if the time zone is working, since it is being both populated and queried from the same computer, why is there a discrepancy? Third, and the pressing issue, how do I solve this? Must I explicitly define the time zone? I'm confused as to why it is returning different data... Hopefully, someone can help me out.
I think Dbeaver is changing the time zone, but the data inserted is the same you get on c#. Try to check directly on the server using commandline because maybe dbeaver is changing it to diplay on your pc
I have an entity with a DateTimeOffset (since .NET doesn't have a Date class) that is supposed to store a date (no time).
The problem is that, when I set the date to, for example, "2017-9-1" in the database it's saved as "2017-08-31 22:00:00+00" (2 hours less)
I think it applies the offset of my time zone to UTC.
I would like to store like to store "2017-9-1" in the database. The first thing I thought is to add 2 hours to every DateTimeOffet, but it feels bogus.
Is there a better way to work with dates than this?
I'm not quite sure, but add "0:" before the date on the format string, I think that should put it to your current time, otherwise it will default to UTC.
Like this:
[DisplayFormat(DataFormatString = "{0:yyyy/dd/MM}")]
If you are using MS Sql, you can use the Date variable to store just date. You can annotate the entities DateTimeOffset property database type.
[Column(TypeName="date")]
Consider this scenario with two applications whose data is synced
Application 1 | Application 2
Data from application1 is inserted/updated into application2 based on last modified date of records.
How can we make sure that the last modified date is not dependent on time zones.
I would use a rowversion column in both applications. To decide what to sync you can have a query or a merge statement and in the where clause you can compare the rows table1.RowVersion > table2.RowVersion. (table1 is from application1 and table2 is from application2)
This might help: ToUniversalTime
Convert the times to universal times, these take into account the time zone, daylight savings, etc. If you convert both times before adding the records, you should be able to get the correct last modified date.
I have a column in the MS SQL database with type “TIME”. I need to record a negative value in it. It isn't a range between two certain times or dates. It’s an abstract value of time that is used in calculations. In the entity framework it is treated as a TimeSpan, which MetaData.tt does automatically with all TIME defined columns in the database.
For example, I might have an arbitrary calendar with events at 5AM and 8PM on Monday, one at 4PM on Tuesday, and one at 3AM on the Sunday after that. I could add the value to these times and get a time either before (in case of negative time), or after (in case of positive time) the beginning of the event.
When I try to write down a negative value, the database refuses it.
The recording of entity to database goes by direct bind of post attributes in the controller, so if it needs to be translated into ticks, is it reliable to do so in Javascript? How would I go about the input textbox for it? It looks like I cannot separate the value from the content in a text box. And if I have to turn it into an INT, I cannot use #EditorFor on it anymore, creating another point of fault where code becomes less flexible.
It almost feels like I should create new columns to denote the negativity of these values and use a dropdown list with hidden inputs instead of a textbox.
EDIT:
Why avoid non-time types:
Consider this code:
var typeName = _code.Escape(edmType.MetadataProperties.Where(…).FirstOrDefault());
If the EDM property has the type int, the generated code will be the type int.
The EDM property comes from the database itself, so if it is not a type that translates directly into a time, then there will need to be a new method (somewhere in a helper, perhaps), which translates this into a time. This new method will have to be maintained (by other people on the team), which means a weak point, because if someone changes the column name, now the code will not just get properly generated again.
Errors may also not be available through the error log, since most properties also tend to be referenced in javascript at some point (which is often also generated, and now can't be for this column because it is a special case). I'm also talking about some 20 columns suffering from this, so this has a very good potential to quickly turn into a deeply tangled ball of spaghetti.
It really seems like you are trying to store a duration, not a time. TIME is used for storing a point in time, not an amount of time. I would choose some subdivision of time (second, millisecond, etc), and store that as an int (or bigint if necessary). Then in SQL Server you could use DATEADD(SECOND,#storedValue,#dateToChange) to calculate the true time or DateTime.Add.Milliseconds(storedValue) or DateTime.Add.Seconds(storedValue), so on, in C# when trying to calculate the time you want.
Let me know if I'm missing something.
In these cases I think I would store both Begin and End times and have another Computed Column to store the difference (with INT datatype) using DATEDIFF:
CREATE TABLE dbo.MyTable
(
Time1 time
Time2 time
timedifference AS DATEDIFF(Second, Time1,Time2)
);
Then you can convert the Seconds into a time of day like this:
SELECT CONVERT(varchar, DATEADD(ms, timedifference * 1000, 0), 114)
Here is a working sample of what you will get:
SELECT CONVERT(varchar, DATEADD(ms, DATEDIFF(Second, CAST('12:24:18.3500000' as time),CAST('11:24:18.3500000' as time)) * 1000, 0), 114)
SELECT CONVERT(varchar, DATEADD(ms, DATEDIFF(Second, CAST('11:24:18.3500000' as time),CAST('12:24:18.3500000' as time)) * 1000, 0), 114)
Database type time does not support negative values. The acceptable range is 00:00:00.0000000 through 23:59:59.9999999
https://msdn.microsoft.com/en-us/library/bb677243.aspx
I have a winform client and wcf service that together display historical data. the data stored in the db with utc timestamps. If two clients in different time zones want to look at a most recent day's worth of data based on their local time, can it be possible that they would be looking at different sets of data?
That depends.
If "a day's worth" means "the last 24 hours", then they will both see the same data.
If "a day's worth" means "00:00-23:59 of (current date - 1) in the user's local time zone", then they might see different data.
Example:
event 1 event 2 +---- service request
| | v
|---------------|---------------|- days in Central Europe
--------|-----------------|------- days in the US (Pacific time)
---------------|---------------|-- UTC day boundaries
In case 1, you just go back 24 hours from the time of the service request. It's easy to see that both customers, the one in the US and the one in Europe, will get the same list of events.
In case 2, it's more difficult: With respect to US time, events 1 and 2 happen on the same day. With respect to Europe, both events happen on different days, so the results will be different for the client in the US and the client in Europe.
Without further details the answer is both.
If a day is defined in the local time zone then changed to the UTC format before the request to the db is made they will have different data sets.
if the query is somthing like
select * from dbTable where TimeStamp >= '9/22/2010' and TimeStamp < '9/23/2010'
or
select * from dbTable where TimeStamp >= GetDate() - '24:00:00' and TimeStamp < GetDate()
then they will return the same set of data for both time zones.
It is certainly possible - it is one of the common issues with globalization/localization.
The important thing to do is to convert all requests to UTC time before making the query. If the queries are all UTC-based, then the data returned to the local machines should match, as the UTC times will match.