MS SQL how to record negative time - c#

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

Related

SQL: .. contains an unresolved reference to an object

Full message
Parameter: [DbName].[SpName].#timeout contains an unresolved reference to an object. Either the object does not exist or the reference is ambiguous because it could refer to any of the following objects: [dbo].[TIME]
I know, there is couple of Question already exists with this message. But this one in my example happens especially because of TIME Sql type.
I Have StoredProcedure ( in Visual Studio Sql Database project ) which is looks like this.
CREATE PROCEDURE [dbo].[my_sp]
#name VARCHAR(255),
#timeout TIME
AS
...
I have no any table with name TIME. When I change the type TIME with other, it stars work correctly, other way it shows this message in TIME type and compile time error.
TIME I trying to use as a SQL alternative for C#'s TimeSpan.
You can't use time with SQL Server 2005, since it didn't exist until SQL Server 2008.
Instead, consider storing a numeric representation of the time interval (which is, ultimately, what time is anyway - just: you'd be doing it explicitly rather than automatically). Typical examples would be to store, as an int, the number of seconds or milliseconds represented by your time interval.
Conveniently, TimeSpan has a TotalSeconds and TotalMilliseconds property that maps to this (just: convert it to an integer), and has FromSeconds(...) and FromMilliseconds(...) methods for going the other direction.
From comments, it sounds like you also need features to combine (add) times to dates; this is also easy:
DATEADD(second, {interval as seconds}, {some datetime})
or
DATEADD(millisecond, {interval as milliseconds}, {some datetime})

How to save and show elapsed time correctly in datagridview?

I want to save elapsed time in a form into sql table
timer started at form load event and when I click the save button try to save it with
cmd.Parameters.AddWithValue("#duration", textBox3.Text);
in sql table and duration column data saved like this: 00:22
and this absolutely correct for my job
but in datagridview's duration column time showed like this:03/16/2015 12:22pm
Why data in datagridview converted to a full date data instead of original elapsed time?
Well, you didn't give us enough information about your problem but I try my best..
first time it was a float data type but i changed it to nvarchar(255)
for better performance in saving data from c# program
Based on your data (which is 00:22) neither float not nvarchar are seem the right type in your database.
If this is a time interval, time type can be the right type since it is a time of a day. But this time type can't hold bigger than 24:00 values. You will get an error when you try to insert it a bigger value.
If this data can be more bigger than 24:00, I would suggest to parse it to TimeSpan first and save it's Ticks property to bigint typed column in your database.
Looks like your program takes your 00:22 and parse it to DateTime in somehow like DateTime.Parse("00:22"), that's why it generates a today's date with parsed time of day as a DateTime in your datagridview.
By the way, don't use AddWithValue method as a best practice. It may unexpected results sometimes. Use .Add() method overloads to specify your SqlDbType and it's size.
Further reading:
Bad habits to kick : choosing the wrong data type
Can we stop using AddWithValue() already?

.NET DataRowComparer DateTime Comparison To T-SQL DateTime

I have learned that SQL Server stores DateTime differently than the .NET Framework. This is very unfortunate in the following circumstance: Suppose I have a DataRow filled from my object properties - some of which are DateTime - and a second DataRow filled from data for that object as persisted in SQL Server:
DataRow drFromObj = new DataRow(itemArrayOfObjProps);
DataRow drFromSQL = // blah select from SQL Server
Using the DataRowComparer on these two DataRows will give an unexpected result:
// This gives false about 100% of the time because SQL Server truncated the more precise
// DateTime to the less precise SQL Server DateTime
DataRowComparer.Default.Equals(drFromObj, drFromSQL);
My question was going to be, 'How do other people deal with reality in a safe and sane manner?' I was also going to rule out converting to strings or writing my own DataRowComparer. I was going to offer that, in absence of better advice, I would change the 'set' on all of my DateTime properties to convert to a System.Data.SqlTypes.SqlDateTime and back upon storage thusly:
public Nullable<DateTime> InsertDate
{
get
{
if (_InsDate.HasValue)
return _InsDate;
else
return null;
}
set
{
if (!object.ReferenceEquals(null, value) && value.HasValue)
_InsDate = (DateTime)(new System.Data.SqlTypes.SqlDateTime(value));
}
}
I know full well that this would probably get screwed up as I used the _InsDate variable directly somewhere rather than going through the property. So my other suggestion was going to be simply using System.Data.SqlTypes.SqlDateTime for all properties where I might want a DateTime type to round trip to SQL Server (and, happily, SqlDateTime is nullable). This post changed my mind, however, and seemed to fix my immediate problem. My new question is, 'What are the caveats or real world experiences using the SQL Server datetime2(7) data type rather than the good, old datetime data type?'
TL;DR: Comparing dates is actually hard, even though it looks easy because you get away with it most of the time.
You have to be aware of this issue and round both values yourself to the desired precision.
This is essentially the same issue as comparing floating point numbers. If two times differ by four nanoseconds, does it make sense for your application to consider them different, or the same?
For example, if two servers have logged the same event, searching for corresponding records, you wouldn't say "no that can't be the correct event because the time is wrong by 200 nanoseconds". Clocks can differ by that amount on two servers no matter how hard they try to keep their time synchronised. You might accept that an event seen on server A and logged with a time a couple of seconds after the time on server B might have been actually seen simultaneously or the other way around.
Note:
If you are comparing data which is supposed to have made some sort of round-trip out of the database, you may find it has been truncated to the second or minute. (For example if it has been through Excel or an old VB application, or been written to a file and parsed back in.)
Data originating from external sources is generally rounded to the day, the minute, or the second. (except sometimes logfiles, eventlogs or electronic dataloggers, which may have milliseconds or better)
If the data has come from SQL Server, and you are comparing it back to itself (for example to detect changes), you may not encounter any issues as they will be implicitly truncated to the same precision.
Daylight savings and timezones introduce additional problems.
If searching for dates, use a date range. And make sure you write the query in such a way that any index can be used.
Somewhat related:
Why doesn't this sql query return any results comparing floating point numbers?
Identity increments. Sort by Identity and you get insert order. You (can) control insert order.
I seriously doubt output would ever by out of order but if you don't trust it you can use #SeeMeSorted
DECLARE #SeeMeSort TABLE
( [ID] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](20) NOT NULL);
DECLARE #SeeMeSorted TABLE
( [ID] [int] primary key NOT NULL,
[Name] [nvarchar](20) NOT NULL);
insert into #SeeMeSort ([Name])
OUTPUT INSERTED.[ID], INSERTED.[name]
values ('fff'), ('hhh'), ('ggg');
insert into #SeeMeSort ([Name])
OUTPUT INSERTED.[ID], INSERTED.[name]
into #SeeMeSorted
values ('xxx'), ('aaa'), ('ddd');
select * from #SeeMeSorted order by [ID];

SQLite limiting and ordering to page on iPhone

I have an iPhone app, built in Xamarin, that stores objects to a local SQLite database. As it takes a long time to load all of the data, I am loading it 20 records at a time, and loading more as the user scrolls.
I am paging by CreatedDate, and this is stored as an Integer field by its DateTime.Ticks property (the number of 100 nanoseconds since DateTime.MinValue). I always pass the oldest loaded CreatedDate to the read function.
Integer column: 8 bytes signed
DateTime.Ticks: 8 bytes signed
The code to write the CreatedDate is as follows:
var param = cmd.CreateParameter();
param.ParameterName = "#date";
param.Value = myObject.DateCreated.Value.Ticks;
cmd.Parameters.Add(param);
And the code to read the next page is as follows:
cmd.CommandText = "SELECT * FROM MyTable WHERE CreatedDate < " +
(offset.HasValue ? offset.Value.Ticks : DateTime.MaxValue.Ticks) +
" ORDER BY CreatedDate DESC LIMIT " + pageSize;
I can tell that the dates are correct, because my sections in my UITableView are based on their CreatedDates.
So here's all the weird behavior (i.e. my question).
I started off in the simulator. At first, I was using DESC and it was returning the oldest objects. Then I switched it to ASC and it was returning the newest objects. This seems backwards. Then, it magically started working correctly with DESC. Paging began working in the simulator, and still works.
Then I switched to a real iPhone. The DESC and ASC issue showed up again, but this time has not fixed itself (ASC returns the most recent objects). Either way, when I scroll to the bottom of the UITableView, the load gets called again with the correct offset, but it gets no data back (and therefore all paging stops).
Things I know.
All of the data is in the table, because if I SELECT * I get everything with the correct dates back. I have also written all of the dates to the console to be sure.
My newest date is 635194634041230000
My oldest date is 635166796800000000
The offset date that returns no rows is 635193909600000000
Note. I'm OK with constructive criticism on how I'm doing this. I'll upvote if I like it enough. But if you post an answer with that information in it, please also try to address the current issue I'm having.
I'm not in front of a computer, so I can't really debug your code atm, however, I thought I'd link to some generic code I wrote for MonoTouch to dynamically page data from SQLite:
https://github.com/jstedfast/MonoTouch.SQLite/blob/master/MonoTouch.SQLite/SQLiteTableModel.cs
This code uses SQLite-net and not System.Data, but it may still help.
The core logic for paging in and out is in GetItem().
When you created your Database, what datatype did you set for the CreateData column? If you used Integer then Ticks should be ok.
1.2 Date and Time Datatype
SQLite does not have a storage class set aside for storing dates
and/or times. Instead, the built-in Date And Time Functions of SQLite
are capable of storing dates and times as TEXT, REAL, or INTEGER
values:
TEXT as ISO8601 strings ("YYYY-MM-DD HH:MM:SS.SSS"). REAL as Julian
day numbers, the number of days since noon in Greenwich on November
24, 4714 B.C. according to the proleptic Gregorian calendar. INTEGER
as Unix Time, the number of seconds since 1970-01-01 00:00:00 UTC.
Sadly, I did not post the relevant code. If the record didn't exist yet, I was writing DateTime.Now to the column. So depending on what order the WCF service returned the results (descending or ascending by date), my ordering could be backwards. I'm not quite sure why it was refusing to page, but I'm guessing it had something to do with precision or whether the database was persisting on the device. Both problems are fixed.

What is the best approach to calculate a formula which changes value each day?

I use the following columns stored in a SQL table called tb_player:
Date of Birth (Date), Times Played (Integer), Versions (Integer)
to calculate a "playvalue" (integer) in the following formula:
playvalue = (Today - Date of Birth) * Times Played * Versions
I display upto 100 of these records with the associataed playvalue on a webpage at any time.
My question is, what is the most efficient way of calculating this playvalue given it will change only once a day, due to the (today-date of birth) changing? The other values (times played & versions) remain the same.
Is there a better way than calculating this on the fly each time for the 100 records? If so, is it more efficient to do the calculation in a stored proc or in VB.NET/C#?
In a property/method on the object, in C#/VB.NET (your .NET code).
The time to execute a simple property like this is nothing compared to the time to call out-of-process to a database (to fetch the rows in the first place), or the transport time of a web-page; you'll never notice it if just using it for UI display. Plus it is on your easily-scaled-out hardware (the app server), and doesn't involve a huge update daily, and is only executed for rows that are actually displayed, and only if you actually query this property/method.
Are you finding that this is actually causing a performance problem? I don't imagine it would be very bad, since the calculation is pretty straightforward math.
However, if you are actually concerned about it, my approach would be to basically set up a "playvalue cache" column in the tb_player table. This column will store the calculated "playvalue" for each player for the current day. Set up a cronjob or scheduled task to run at midnight every day and update this column with the new day's value.
Then everything else can simply select this column instead of doing the calculation, and you only have to do the calculation once a day.

Categories

Resources