Date difference in mvc view with current date / sql server - c#

I get date from my model and it is displayed in view
#Html.DisplayFor(modelItem => item.UpdateDate)
UpdateDate is datetime.(Format 2017-01-12 17:16:32.013)
What I want to do is, compare it with current date and show difference in time.
If the difference between current datetime and UpdatedDate is less
than 60 min then it should say "'X' Minues ago" (where 'X' is
difference in minutes)
If the difference between current datetime and UpdatedDate is more
than 60 min and less than 24 hours then it should say " 'Y' Hours 'X'
Minues ago" (where 'X' is difference in minutes and 'Y' is hours)
If the difference between current datetime and UpdatedDate is more than 24 hours then it should say " 'Z' days 'Y' Hours 'X' Minues ago" (where 'X' is difference in minutes and 'Y' is hours and 'Z' is days)
I want to do this in view. Your help is really appreciated.
Thanks
Here is how I am doing this,
TimeSpan diff = DateTime.Now - DateTime1;
string formatted = string.Format(
CultureInfo.CurrentCulture,
"{0} days, {1} hours, {2} minutes, {3} seconds",
diff.Days,
diff.Hours,
diff.Minutes,
diff.Seconds);
This works but it will prroduce o/p like
0 days 2 hours 28min (o/p needs to be 2 hours 28min)
or
0 days 0 hours 33 min ( o/p needs to be 33 min)
How do I enhance this without putting if else to check for '0' and get expected output
Well can we write a user defined function in sql server for desired format?

Create FUNCTION GetDateDiff
(
#a datetime
)
RETURNS varchar(100)
AS
BEGIN
Declare #Return varchar(100)
Set #Return = '';
if(Convert(int,(DATEDIFF(day, #a, getdate()))) >= 1)
Begin
Set #Return += Convert(varchar(10),(DATEDIFF(day, #a, getdate()))) + ' Day ';
End
if(Convert(int,(DATEDIFF(HOUR, #a, getdate()))) >= 1)
Begin
Set #Return += Convert(varchar(10),(DATEDIFF(HOUR, #a, getdate()))) + ' Hour ';
End
if(Convert(int,(DATEDIFF(MINUTE, #a, getdate()))) >= 1)
Begin
Set #Return += Convert(varchar(10),(DATEDIFF(MINUTE, #a, getdate()))) + ' Minute ';
End
return #Return
END
So I am writing this function in sql, any suggestions on improvement?
Further when day difference in greater than 1, the string should be 'days' (same for hours and minutes)

Related

Timeformat bigger then 24 hours [duplicate]

I am trying to store a .Net TimeSpan in SQL server 2008 R2.
EF Code First seems to be suggesting it should be stored as a Time(7) in SQL.
However TimeSpan in .Net can handle longer periods than 24 hours.
What is the best way to handle storing .Net TimeSpan in SQL server?
I'd store it in the database as a BIGINT and I'd store the number of ticks (eg. TimeSpan.Ticks property).
That way, if I wanted to get a TimeSpan object when I retrieve it, I could just do TimeSpan.FromTicks(value) which would be easy.
Thanks for the advice. As there is no equivalent in SQL server. I simply created a 2nd field which converted the TimeSpan to ticks and stored that in the DB. I then prevented storing the TimeSpan
public Int64 ValidityPeriodTicks { get; set; }
[NotMapped]
public TimeSpan ValidityPeriod
{
get { return TimeSpan.FromTicks(ValidityPeriodTicks); }
set { ValidityPeriodTicks = value.Ticks; }
}
If you don't have to store more than 24 hours you can just store time, since SQL Server 2008 and later the mapping is
time (SQL Server) <-> TimeSpan(.NET)
No conversions needed if you only need to store 24 hours or less.
Source: http://msdn.microsoft.com/en-us/library/cc716729(v=vs.110).aspx
But, if you want to store more than 24h, you are going to need to store it in ticks, retrieve the data and then convert to TimeSpan. For example
int timeData = yourContext.yourTable.FirstOrDefault();
TimeSpan ts = TimeSpan.FromMilliseconds(timeData);
There isn't a direct equivalent. Just store it numerically, e.g. number of seconds or something appropriate to your required accuracy.
There are multiple ways how to present a timespan in the database.
time
This datatype is supported since SQL Server 2008 and is the prefered way to store a TimeSpan. There is no mapping needed. It also works well with SQL code.
public TimeSpan ValidityPeriod { get; set; }
However, as stated in the original question, this datatype is limited to 24 hours.
datetimeoffset
The datetimeoffset datatype maps directly to System.DateTimeOffset. It's used to express the offset between a datetime/datetime2 to UTC, but you can also use it for TimeSpan.
However, since the datatype suggests a very specific semantic, so you should also consider other options.
datetime / datetime2
One approach might be to use the datetime or datetime2 types. This is best in scenarios where you need to process the values in the database directly, ie. for views, stored procedures, or reports. The drawback is that you need to substract the value DateTime(1900,01,01,00,00,00) from the date to get back the timespan in your business logic.
public DateTime ValidityPeriod { get; set; }
[NotMapped]
public TimeSpan ValidityPeriodTimeSpan
{
get { return ValidityPeriod - DateTime(1900,01,01,00,00,00); }
set { ValidityPeriod = DateTime(1900,01,01,00,00,00) + value; }
}
bigint
Another approach might be to convert the TimeSpan into ticks and use the bigint datatype. However, this approach has the drawback that it's cumbersome to use in SQL queries.
public long ValidityPeriod { get; set; }
[NotMapped]
public TimeSpan ValidityPeriodTimeSpan
{
get { return TimeSpan.FromTicks(ValidityPeriod); }
set { ValidityPeriod = value.Ticks; }
}
varchar(N)
This is best for cases where the value should be readable by humans. You might also use this format in SQL queries by utilizing the CONVERT(datetime, ValidityPeriod) function. Dependent on the required precision, you will need between 8 and 25 characters.
public string ValidityPeriod { get; set; }
[NotMapped]
public TimeSpan ValidityPeriodTimeSpan
{
get { return TimeSpan.Parse(ValidityPeriod); }
set { ValidityPeriod = value.ToString("HH:mm:ss"); }
}
Bonus: Period and Duration
Using a string, you can also store NodaTime datatypes, especially Duration and Period. The first is basically the same as a TimeSpan, while the later respects that some days and months are longer or shorter than others (ie. January has 31 days and February has 28 or 29; some days are longer or shorter because of daylight saving time). In such cases, using a TimeSpan is the wrong choice.
You can use this code to convert Periods:
using NodaTime;
using NodaTime.Serialization.JsonNet;
internal static class PeriodExtensions
{
public static Period ToPeriod(this string input)
{
var js = JsonSerializer.Create(new JsonSerializerSettings());
js.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
var quoted = string.Concat(#"""", input, #"""");
return js.Deserialize<Period>(new JsonTextReader(new StringReader(quoted)));
}
}
And then use it like
public string ValidityPeriod { get; set; }
[NotMapped]
public Period ValidityPeriodPeriod
{
get => ValidityPeriod.ToPeriod();
set => ValidityPeriod = value.ToString();
}
I really like NodaTime and it often saves me from tricky bugs and lots of headache. The drawback here is that you really can't use it in SQL queries and need to do calculations in-memory.
CLR User-Defined Type
You also have the option to use a custom datatype and support a custom TimeSpan class directly. See CLR User-Defined Types for details.
The drawback here is that the datatype might not behave well with SQL Reports. Also, some versions of SQL Server (Azure, Linux, Data Warehouse) are not supported.
Value Conversions
Starting with EntityFramework Core 2.1, you have the option to use Value Conversions.
However, when using this, EF will not be able to convert many queries into SQL, causing queries to run in-memory; potentially transfering lots and lots of data to your application.
So at least for now, it might be better not to use it, and just map the query result with Automapper.
I know this is an old question, but I wanted to make sure a couple of other options are noted.
Since you can't store a TimeSpan greater than 24 hours in a time sql datatype field; a couple of other options might be.
Use a varchar(xx) to store the ToString of the TimeSpan. The benefit of this is the precision doesn't have to be baked into the datatype or the calculation, (seconds vs milliseconds vs days vs fortnights) All you need to to is use TimeSpan.Parse/TryParse. This is what I would do.
Use a second date, datetime or datetimeoffset, that stores the result of first date + timespan. Reading from the db is a matter of TimeSpan x = SecondDate - FirstDate. Using this option will protect you for other non .NET data access libraries access the same data but not understanding TimeSpans; in case you have such an environment.
Now, with EF Core you can convert data type transparently in your AppDbContext
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// i.e. Store TimeSpan as string (custom)
modelBuilder
.Entity<YourClass>()
.Property(x => x.YourTimeSpan)
.HasConversion(
timeSpan => timeSpan.ToString(), // To DB
timeSpanString => TimeSpan.Parse(timeSpanString) // From DB
);
// i.e. Store TimeSpan as string (using TimeSpanToStringConverter)
modelBuilder
.Entity<YourClass>()
.Property(x => x.YourTimeSpan)
.HasConversion(new TimeSpanToStringConverter());
// i.e. Store TimeSpan as number of ticks (custom)
modelBuilder
.Entity<YourClass>()
.Property(x => x.YourTimeSpan)
.HasConversion(
timeSpan => timeSpan.Ticks, // To DB
timeSpanString => TimeSpan.FromTicks(timeSpanString) // From DB
);
// i.e. Store TimeSpan as number of ticks (using TimeSpanToTicksConverter)
modelBuilder
.Entity<YourClass>()
.Property(x => x.YourTimeSpan)
.HasConversion(new TimeSpanToTicksConverter());
}
To be consistent with what is probably the most likely source of generating a time span (computing the difference of 2 times or date-times), you may want to store a .NET TimeSpan as a SQL Server DateTime Type.
This is because in SQL Server, the difference of 2 DateTime's (Cast to Float's and then Cast back to a DateTime) is simply a DateTime relative to Jan. 1, 1900. Ex. A difference of +0.1 second would be January 1, 1900 00:00:00.100 and -0.1 second would be Dec. 31, 1899 23:59:59.900.
To convert a .NET TimeSpan to a SQL Server DateTime Type, you would first convert it to a .NET DateTime Type by adding it to a DateTime of Jan. 1, 1900. Of course, when you read it into .NET from SQL Server, you would first read it into a .NET DateTime and then subtract Jan. 1, 1900 from it to convert it to a .NET TimeSpan.
For use cases where the time spans are being generated from SQL Server DateTime's and within SQL Server (i.e. via T-SQL) and SQL Server is prior to 2016, depending on your range and precision needs, it may not be practical to store them as milliseconds (not to mention Ticks) because the Int Type returned by DateDiff (vs. the BigInt from SS 2016+'s DateDiff_Big) overflows after ~24 days worth of milliseconds and ~67 yrs. of seconds. Whereas, this solution will handle time spans with precision down to 0.1 seconds and from -147 to +8,099 yrs..
WARNINGS:
This would only work if the difference relative to Jan. 1, 1900 would result in a value within the range of a SQL Server DateTime Type (Jan. 1, 1753 to Dec. 31, 9999 aka -147 to +8,099 yrs.). We don't have to worry near as much on the .NET TimeSpan side, since it can hold ~29 k to +29 k yrs. I didn't mention the SQL Server DateTime2 Type (whose range, on the negative side, is much greater than SQL Server DateTime's), because: a) it cannot be converted to a numeric via a simple Cast and b) DateTime's range should suffice for the vast majority of use cases.
SQL Server DateTime differences computed via the Cast - to - Float - and - back method does not appear to be accurate beyond 0.1 seconds.
Typically, I store a TimeSpan as a bigint populated with ticks from the TimeSpan.Ticks property as previously suggested. You can also store a TimeSpan as a varchar(26) populated with the output of TimeSpan.ToString(). The four scalar functions (ConvertFromTimeSpanString, ConvertToTimeSpanString, DateAddTicks, DateDiffTicks) that I wrote are helpful for handling TimeSpan on the SQL side and avoid the hacks that would produce artificially bounded ranges. If you can store the interval in a .NET TimeSpan at all it should work with these functions also. Additionally, the functions allow you to work with TimeSpans and 100-nanosecond ticks even when using technologies that don't include the .NET Framework.
DROP FUNCTION [dbo].[DateDiffTicks]
GO
DROP FUNCTION [dbo].[DateAddTicks]
GO
DROP FUNCTION [dbo].[ConvertToTimeSpanString]
GO
DROP FUNCTION [dbo].[ConvertFromTimeSpanString]
GO
SET ANSI_NULLS OFF
GO
SET QUOTED_IDENTIFIER OFF
GO
-- =============================================
-- Author: James Coe
-- Create date: 2011-05-23
-- Description: Converts from a varchar(26) TimeSpan string to a bigint containing the number of 100 nanosecond ticks.
-- =============================================
/*
[-][d.]hh:mm:ss[.fffffff]
"-"
A minus sign, which indicates a negative time interval. No sign is included for a positive time span.
"d"
The number of days in the time interval. This element is omitted if the time interval is less than one day.
"hh"
The number of hours in the time interval, ranging from 0 to 23.
"mm"
The number of minutes in the time interval, ranging from 0 to 59.
"ss"
The number of seconds in the time interval, ranging from 0 to 59.
"fffffff"
Fractional seconds in the time interval. This element is omitted if the time interval does not include
fractional seconds. If present, fractional seconds are always expressed using seven decimal digits.
*/
CREATE FUNCTION [dbo].[ConvertFromTimeSpanString] (#timeSpan varchar(26))
RETURNS bigint
AS
BEGIN
DECLARE #hourStart int
DECLARE #minuteStart int
DECLARE #secondStart int
DECLARE #ticks bigint
DECLARE #hours bigint
DECLARE #minutes bigint
DECLARE #seconds DECIMAL(9, 7)
SET #hourStart = CHARINDEX('.', #timeSpan) + 1
SET #minuteStart = CHARINDEX(':', #timeSpan) + 1
SET #secondStart = CHARINDEX(':', #timespan, #minuteStart) + 1
SET #ticks = 0
IF (#hourStart > 1 AND #hourStart < #minuteStart)
BEGIN
SET #ticks = CONVERT(bigint, LEFT(#timespan, #hourstart - 2)) * 864000000000
END
ELSE
BEGIN
SET #hourStart = 1
END
SET #hours = CONVERT(bigint, SUBSTRING(#timespan, #hourStart, #minuteStart - #hourStart - 1))
SET #minutes = CONVERT(bigint, SUBSTRING(#timespan, #minuteStart, #secondStart - #minuteStart - 1))
SET #seconds = CONVERT(DECIMAL(9, 7), SUBSTRING(#timespan, #secondStart, LEN(#timeSpan) - #secondStart + 1))
IF (#ticks < 0)
BEGIN
SET #ticks = #ticks - #hours * 36000000000
END
ELSE
BEGIN
SET #ticks = #ticks + #hours * 36000000000
END
IF (#ticks < 0)
BEGIN
SET #ticks = #ticks - #minutes * 600000000
END
ELSE
BEGIN
SET #ticks = #ticks + #minutes * 600000000
END
IF (#ticks < 0)
BEGIN
SET #ticks = #ticks - #seconds * 10000000.0
END
ELSE
BEGIN
SET #ticks = #ticks + #seconds * 10000000.0
END
RETURN #ticks
END
GO
-- =============================================
-- Author: James Coe
-- Create date: 2011-05-23
-- Description: Converts from a bigint containing the number of 100 nanosecond ticks to a varchar(26) TimeSpan string.
-- =============================================
/*
[-][d.]hh:mm:ss[.fffffff]
"-"
A minus sign, which indicates a negative time interval. No sign is included for a positive time span.
"d"
The number of days in the time interval. This element is omitted if the time interval is less than one day.
"hh"
The number of hours in the time interval, ranging from 0 to 23.
"mm"
The number of minutes in the time interval, ranging from 0 to 59.
"ss"
The number of seconds in the time interval, ranging from 0 to 59.
"fffffff"
Fractional seconds in the time interval. This element is omitted if the time interval does not include
fractional seconds. If present, fractional seconds are always expressed using seven decimal digits.
*/
CREATE FUNCTION [dbo].[ConvertToTimeSpanString] (#ticks bigint)
RETURNS varchar(26)
AS
BEGIN
DECLARE #timeSpanString varchar(26)
IF (#ticks < 0)
BEGIN
SET #timeSpanString = '-'
END
ELSE
BEGIN
SET #timeSpanString = ''
END
-- Days
DECLARE #days bigint
SET #days = FLOOR(ABS(#ticks / 864000000000.0))
IF (#days > 0)
BEGIN
SET #timeSpanString = #timeSpanString + CONVERT(varchar(26), #days) + '.'
END
SET #ticks = ABS(#ticks % 864000000000)
-- Hours
SET #timeSpanString = #timeSpanString + RIGHT('0' + CONVERT(varchar(26), FLOOR(#ticks / 36000000000.0)), 2) + ':'
SET #ticks = #ticks % 36000000000
-- Minutes
SET #timeSpanString = #timeSpanString + RIGHT('0' + CONVERT(varchar(26), FLOOR(#ticks / 600000000.0)), 2) + ':'
SET #ticks = #ticks % 600000000
-- Seconds
SET #timeSpanString = #timeSpanString + RIGHT('0' + CONVERT(varchar(26), FLOOR(#ticks / 10000000.0)), 2)
SET #ticks = #ticks % 10000000
-- Fractional Seconds
IF (#ticks > 0)
BEGIN
SET #timeSpanString = #timeSpanString + '.' + LEFT(CONVERT(varchar(26), #ticks) + '0000000', 7)
END
RETURN #timeSpanString
END
GO
-- =============================================
-- Author: James Coe
-- Create date: 2011-05-23
-- Description: Adds the specified number of 100 nanosecond ticks to a date.
-- =============================================
CREATE FUNCTION [dbo].[DateAddTicks] (
#ticks bigint
, #starting_date datetimeoffset
)
RETURNS datetimeoffset
AS
BEGIN
DECLARE #dateTimeResult datetimeoffset
IF (#ticks < 0)
BEGIN
-- Hours
SET #dateTimeResult = DATEADD(HOUR, CEILING(#ticks / 36000000000.0), #starting_date)
SET #ticks = #ticks % 36000000000
-- Seconds
SET #dateTimeResult = DATEADD(SECOND, CEILING(#ticks / 10000000.0), #dateTimeResult)
SET #ticks = #ticks % 10000000
-- Nanoseconds
SET #dateTimeResult = DATEADD(NANOSECOND, #ticks * 100, #dateTimeResult)
END
ELSE
BEGIN
-- Hours
SET #dateTimeResult = DATEADD(HOUR, FLOOR(#ticks / 36000000000.0), #starting_date)
SET #ticks = #ticks % 36000000000
-- Seconds
SET #dateTimeResult = DATEADD(SECOND, FLOOR(#ticks / 10000000.0), #dateTimeResult)
SET #ticks = #ticks % 10000000
-- Nanoseconds
SET #dateTimeResult = DATEADD(NANOSECOND, #ticks * 100, #dateTimeResult)
END
RETURN #dateTimeResult
END
GO
-- =============================================
-- Author: James Coe
-- Create date: 2011-05-23
-- Description: Gets the difference between two dates in 100 nanosecond ticks.
-- =============================================
CREATE FUNCTION [dbo].[DateDiffTicks] (
#starting_date datetimeoffset
, #ending_date datetimeoffset
)
RETURNS bigint
AS
BEGIN
DECLARE #ticks bigint
DECLARE #days bigint
DECLARE #hours bigint
DECLARE #minutes bigint
DECLARE #seconds bigint
SET #hours = DATEDIFF(HOUR, #starting_date, #ending_date)
SET #starting_date = DATEADD(HOUR, #hours, #starting_date)
SET #ticks = #hours * 36000000000
SET #seconds = DATEDIFF(SECOND, #starting_date, #ending_date)
SET #starting_date = DATEADD(SECOND, #seconds, #starting_date)
SET #ticks = #ticks + #seconds * 10000000
SET #ticks = #ticks + CONVERT(bigint, DATEDIFF(NANOSECOND, #starting_date, #ending_date)) / 100
RETURN #ticks
END
GO
--- BEGIN Test Harness ---
SET NOCOUNT ON
DECLARE #dateTimeOffsetMinValue datetimeoffset
DECLARE #dateTimeOffsetMaxValue datetimeoffset
DECLARE #timeSpanMinValueString varchar(26)
DECLARE #timeSpanZeroString varchar(26)
DECLARE #timeSpanMaxValueString varchar(26)
DECLARE #timeSpanMinValueTicks bigint
DECLARE #timeSpanZeroTicks bigint
DECLARE #timeSpanMaxValueTicks bigint
DECLARE #dateTimeOffsetMinMaxDiffTicks bigint
DECLARE #dateTimeOffsetMaxMinDiffTicks bigint
SET #dateTimeOffsetMinValue = '0001-01-01T00:00:00.0000000+00:00'
SET #dateTimeOffsetMaxValue = '9999-12-31T23:59:59.9999999+00:00'
SET #timeSpanMinValueString = '-10675199.02:48:05.4775808'
SET #timeSpanZeroString = '00:00:00'
SET #timeSpanMaxValueString = '10675199.02:48:05.4775807'
SET #timeSpanMinValueTicks = -9223372036854775808
SET #timeSpanZeroTicks = 0
SET #timeSpanMaxValueTicks = 9223372036854775807
SET #dateTimeOffsetMinMaxDiffTicks = 3155378975999999999
SET #dateTimeOffsetMaxMinDiffTicks = -3155378975999999999
-- TimeSpan Conversion Tests
PRINT 'Testing TimeSpan conversions...'
DECLARE #convertToTimeSpanStringMinTicksResult varchar(26)
DECLARE #convertFromTimeSpanStringMinTimeSpanResult bigint
DECLARE #convertToTimeSpanStringZeroTicksResult varchar(26)
DECLARE #convertFromTimeSpanStringZeroTimeSpanResult bigint
DECLARE #convertToTimeSpanStringMaxTicksResult varchar(26)
DECLARE #convertFromTimeSpanStringMaxTimeSpanResult bigint
SET #convertToTimeSpanStringMinTicksResult = dbo.ConvertToTimeSpanString(#timeSpanMinValueTicks)
SET #convertFromTimeSpanStringMinTimeSpanResult = dbo.ConvertFromTimeSpanString(#timeSpanMinValueString)
SET #convertToTimeSpanStringZeroTicksResult = dbo.ConvertToTimeSpanString(#timeSpanZeroTicks)
SET #convertFromTimeSpanStringZeroTimeSpanResult = dbo.ConvertFromTimeSpanString(#timeSpanZeroString)
SET #convertToTimeSpanStringMaxTicksResult = dbo.ConvertToTimeSpanString(#timeSpanMaxValueTicks)
SET #convertFromTimeSpanStringMaxTimeSpanResult = dbo.ConvertFromTimeSpanString(#timeSpanMaxValueString)
-- Test Results
SELECT 'Convert to TimeSpan String from Ticks (Minimum)' AS Test
, CASE
WHEN #convertToTimeSpanStringMinTicksResult = #timeSpanMinValueString
THEN 'Pass'
ELSE 'Fail'
END AS [Test Status]
, #timeSpanMinValueTicks AS [Ticks]
, CONVERT(varchar(26), NULL) AS [TimeSpan String]
, CONVERT(varchar(26), #convertToTimeSpanStringMinTicksResult) AS [Actual Result]
, CONVERT(varchar(26), #timeSpanMinValueString) AS [Expected Result]
UNION ALL
SELECT 'Convert from TimeSpan String to Ticks (Minimum)' AS Test
, CASE
WHEN #convertFromTimeSpanStringMinTimeSpanResult = #timeSpanMinValueTicks
THEN 'Pass'
ELSE 'Fail'
END AS [Test Status]
, NULL AS [Ticks]
, #timeSpanMinValueString AS [TimeSpan String]
, CONVERT(varchar(26), #convertFromTimeSpanStringMinTimeSpanResult) AS [Actual Result]
, CONVERT(varchar(26), #timeSpanMinValueTicks) AS [Expected Result]
UNION ALL
SELECT 'Convert to TimeSpan String from Ticks (Zero)' AS Test
, CASE
WHEN #convertToTimeSpanStringZeroTicksResult = #timeSpanZeroString
THEN 'Pass'
ELSE 'Fail'
END AS [Test Status]
, #timeSpanZeroTicks AS [Ticks]
, CONVERT(varchar(26), NULL) AS [TimeSpan String]
, CONVERT(varchar(26), #convertToTimeSpanStringZeroTicksResult) AS [Actual Result]
, CONVERT(varchar(26), #timeSpanZeroString) AS [Expected Result]
UNION ALL
SELECT 'Convert from TimeSpan String to Ticks (Zero)' AS Test
, CASE
WHEN #convertFromTimeSpanStringZeroTimeSpanResult = #timeSpanZeroTicks
THEN 'Pass'
ELSE 'Fail'
END AS [Test Status]
, NULL AS [Ticks]
, #timeSpanZeroString AS [TimeSpan String]
, CONVERT(varchar(26), #convertFromTimeSpanStringZeroTimeSpanResult) AS [Actual Result]
, CONVERT(varchar(26), #timeSpanZeroTicks) AS [Expected Result]
UNION ALL
SELECT 'Convert to TimeSpan String from Ticks (Maximum)' AS Test
, CASE
WHEN #convertToTimeSpanStringMaxTicksResult = #timeSpanMaxValueString
THEN 'Pass'
ELSE 'Fail'
END AS [Test Status]
, #timeSpanMaxValueTicks AS [Ticks]
, CONVERT(varchar(26), NULL) AS [TimeSpan String]
, CONVERT(varchar(26), #convertToTimeSpanStringMaxTicksResult) AS [Actual Result]
, CONVERT(varchar(26), #timeSpanMaxValueString) AS [Expected Result]
UNION ALL
SELECT 'Convert from TimeSpan String to Ticks (Maximum)' AS Test
, CASE
WHEN #convertFromTimeSpanStringMaxTimeSpanResult = #timeSpanMaxValueTicks
THEN 'Pass'
ELSE 'Fail'
END AS [Test Status]
, NULL AS [Ticks]
, #timeSpanMaxValueString AS [TimeSpan String]
, CONVERT(varchar(26), #convertFromTimeSpanStringMaxTimeSpanResult) AS [Actual Result]
, CONVERT(varchar(26), #timeSpanMaxValueTicks) AS [Expected Result]
-- Ticks Date Add Test
PRINT 'Testing DateAddTicks...'
DECLARE #DateAddTicksPositiveTicksResult datetimeoffset
DECLARE #DateAddTicksZeroTicksResult datetimeoffset
DECLARE #DateAddTicksNegativeTicksResult datetimeoffset
SET #DateAddTicksPositiveTicksResult = dbo.DateAddTicks(#dateTimeOffsetMinMaxDiffTicks, #dateTimeOffsetMinValue)
SET #DateAddTicksZeroTicksResult = dbo.DateAddTicks(#timeSpanZeroTicks, #dateTimeOffsetMinValue)
SET #DateAddTicksNegativeTicksResult = dbo.DateAddTicks(#dateTimeOffsetMaxMinDiffTicks, #dateTimeOffsetMaxValue)
-- Test Results
SELECT 'Date Add with Ticks Test (Positive)' AS Test
, CASE
WHEN #DateAddTicksPositiveTicksResult = #dateTimeOffsetMaxValue
THEN 'Pass'
ELSE 'Fail'
END AS [Test Status]
, #dateTimeOffsetMinMaxDiffTicks AS [Ticks]
, #dateTimeOffsetMinValue AS [Starting Date]
, #DateAddTicksPositiveTicksResult AS [Actual Result]
, #dateTimeOffsetMaxValue AS [Expected Result]
UNION ALL
SELECT 'Date Add with Ticks Test (Zero)' AS Test
, CASE
WHEN #DateAddTicksZeroTicksResult = #dateTimeOffsetMinValue
THEN 'Pass'
ELSE 'Fail'
END AS [Test Status]
, #timeSpanZeroTicks AS [Ticks]
, #dateTimeOffsetMinValue AS [Starting Date]
, #DateAddTicksZeroTicksResult AS [Actual Result]
, #dateTimeOffsetMinValue AS [Expected Result]
UNION ALL
SELECT 'Date Add with Ticks Test (Negative)' AS Test
, CASE
WHEN #DateAddTicksNegativeTicksResult = #dateTimeOffsetMinValue
THEN 'Pass'
ELSE 'Fail'
END AS [Test Status]
, #dateTimeOffsetMaxMinDiffTicks AS [Ticks]
, #dateTimeOffsetMaxValue AS [Starting Date]
, #DateAddTicksNegativeTicksResult AS [Actual Result]
, #dateTimeOffsetMinValue AS [Expected Result]
-- Ticks Date Diff Test
PRINT 'Testing Date Diff Ticks...'
DECLARE #dateDiffTicksMinMaxResult bigint
DECLARE #dateDiffTicksMaxMinResult bigint
SET #dateDiffTicksMinMaxResult = dbo.DateDiffTicks(#dateTimeOffsetMinValue, #dateTimeOffsetMaxValue)
SET #dateDiffTicksMaxMinResult = dbo.DateDiffTicks(#dateTimeOffsetMaxValue, #dateTimeOffsetMinValue)
-- Test Results
SELECT 'Date Difference in Ticks Test (Min, Max)' AS Test
, CASE
WHEN #dateDiffTicksMinMaxResult = #dateTimeOffsetMinMaxDiffTicks
THEN 'Pass'
ELSE 'Fail'
END AS [Test Status]
, #dateTimeOffsetMinValue AS [Starting Date]
, #dateTimeOffsetMaxValue AS [Ending Date]
, #dateDiffTicksMinMaxResult AS [Actual Result]
, #dateTimeOffsetMinMaxDiffTicks AS [Expected Result]
UNION ALL
SELECT 'Date Difference in Ticks Test (Max, Min)' AS Test
, CASE
WHEN #dateDiffTicksMaxMinResult = #dateTimeOffsetMaxMinDiffTicks
THEN 'Pass'
ELSE 'Fail'
END AS [Test Status]
, #dateTimeOffsetMaxValue AS [Starting Date]
, #dateTimeOffsetMinValue AS [Ending Date]
, #dateDiffTicksMaxMinResult AS [Actual Result]
, #dateTimeOffsetMaxMinDiffTicks AS [Expected Result]
PRINT 'Tests Complete.'
GO
--- END Test Harness ---
I would store the timespan.TotalSeconds in a float and then retrieve it using Timespan.FromSeconds(totalSeconds).
Depending on the resolution you need you could use TotalMilliseconds, TotalMinutes, TotalDays.
You could also adjust the precision of your float in the database.
It's not an exact value... but the nice thing about this is that it's easy to read and calculate in simple queries.

Julian Date Calculator - Changing values each run

I got a simple Julian Date Calculator with the following code:
DateTime date = DateTime.UtcNow;
int month = date.Month > 2 ? date.Month : date.Month + 12;
int year = month > 2 ? date.Year : date.Year - 1;
int hour = date.Hour;
int minute = date.Minute;
int second = date.Second;
int millisecond = date.Millisecond;
double day = date.Day + hour / 24.0 + minute / 1440.0 + (second + millisecond * 1000) / 86400.0;
int isJulianCalendar = isJulianDate(year, month, date.Day) ? 0 : 2 - year + year / 100 / 4;
When I run the program, it returns a lower value than the previous one (e.g if I run now, it shows a value, but if I run in a couple of minutes, it shows another value).
From the .pdf I copied the expression, it says that the formula use UT time. Is there any relevant difference from the UTC time?
.NET has a built in JulianCalendar class, which you should probably use instead of writing your own code.
double day = date.Day + hour / 24.0 + minute / 1440.0 + (second + millisecond * 1000) / 86400.0;
The (second + millisecond * 1000) part seems intended to calculate fractional seconds, but to get that, you need to divide millisecond by 1000.0, not multiply it.
Note that as I pointed out in the comments, this only addresses the immediate problem you are asking about, it will likely not be sufficient to actually correctly calculate the Julian day. However, since you yourself have posted links to working answers showing a calculation of the Julian day without time, you should be able to get it working from here on.

Query to display +- 2 days of data but return only selected date itself

I would like to send a MySQL query where I choose a date from my C# programming comboBox e.g. 04/06/2014. Then result should show +-2days including 04/06/2014 itself. i.e. result will ended up showing data from 02/06/2014 till 06/06/2014 (a total of 5 days) in my dataGridView. My MySQL command below shows only the data for 04/06/2014, can someone kindly correct my code? Any help would be much appreciated!
Note: Assuming the 04/06/2014 will be replaced by my C# code comboBox_stockDates.SelectedItem.ToString()
SELECT Prices_Date, Prices_Time, Prices_Open
FROM tableprices
WHERE Ticker_ID = 732
AND DATE_ADD(STR_TO_DATE('04/06/2014', '%d/%m/%Y'), INTERVAL - 2 DAY)
AND DATE_ADD(STR_TO_DATE('04/06/2014', '%d/%m/%Y'), INTERVAL - 1 DAY)
AND Prices_Date = STR_TO_DATE('04/06/2014', '%d/%m/%Y')
AND DATE_ADD(STR_TO_DATE('04/06/2014', '%d/%m/%Y'), INTERVAL + 1 DAY)
AND DATE_ADD(STR_TO_DATE('04/06/2014', '%d/%m/%Y'), INTERVAL + 2 DAY)
ORDER BY Prices_Date ASC, Prices_Time ASC;
Your SELECT filters only the column Price_Date and current date. This one should work for you:
SELECT Prices_Date,
Prices_Time,
Prices_Open
FROM tableprices
WHERE Ticker_ID = 732
AND Prices_Date >= DATE_ADD (STR_TO_DATE ('04/06/2014', '%d/%m/%Y'), INTERVAL -2 DAY)
AND Prices_Date <= DATE_ADD (STR_TO_DATE ('04/06/2014', '%d/%m/%Y'), INTERVAL +2 DAY)
ORDER BY Prices_Date ASC, Prices_Time ASC;
For using the indexes of your table effectively (if there are any) it's better to convert the dates before the query as Chris suggested.
Any reason you can't do the conversion in C#? Seems cleaner.
Then it'd be a select from table where date greater than or equal and date less than or equal.
C# Code:
var dt = DateTime.ParseExact(comboBox_stockDates.SelectedItem.ToString(), "dd/MM/yyyy", System.Globalization.CultureInfo.InvariantCulture);
var start = dt.AddDays(-2);
var end = dt.AddDays(2);
Then select:
SELECT prices_date,
prices_time,
prices_open
FROM tableprices
WHERE ticker_id = 732
AND ( prices_date >= [startdate]
AND prices_date <= [enddate] )
ORDER BY prices_date ASC,
prices_time ASC;
Will this not work for you?

How to convert string to datetime in sql server

I want to count total time in hh:mm:ss format. and I have minutes in int like (465).
I made:
CONVERT(varchar, CONVERT(datetime, cast(cast(TotalMin/60 as int) as nvarchar(50)) + ' : ' + cast(TotalMin%60 as nvarchar(50))),108) AS TotalMin
but it shows below error. Not in SQL Server but when I run code in c#:
Conversion failed when converting date and/or time from character
string.
You can use this code to get the string in SQL Server. It will convert hours and minutes and add 00 for seconds as you don't have them (you're using integer value for minutes):
declare #min int = 465
select right('0' + cast(#min/60 as varchar(2)),2)
+ ':'
+ right('0' + cast((#min - (#min/60)*60) as varchar(2)),2)
+ ':00'
It will work for up to 5999 minutes (99 hours and 59 minutes).
If you need a Unicode version:
declare #min int = 465
select right(N'0' + cast(#min/60 as nvarchar(2)),2)
+ N':'
+ right(N'0' + cast((#min - (#min/60)*60) as nvarchar(2)),2)
+ N':00'
Try this:
TimeSpan t = TimeSpan.FromMinutes( TotalMin);
and see this for more
UPDATE MyTable SET MyDate = CONVERT(datetime, '2009/07/16 08:28:01', 120)
For a full discussion of CAST and CONVERT, including the different date formatting options, see the MSDN Library Link below:
http://msdn.microsoft.com/en-us/library/ms187928.aspx
This will help you
You want to multiply out to milliseconds as the fractional part is discarded.
SELECT DATEADD(ms, 121.25 * 1000, 0)
If you want it without the date portion you can use CONVERT, with style 114
SELECT CONVERT(VARCHAR, DATEADD(ms, 121.25 * 1000, 0), 114)

sql query problem

i want to compare two date and time with each other and
i want to select records that "StartTime" is greater than now time and the "StartDate" is greater than now date.
but output is not correct.thanks in advance.
my tabale'records are:
StartDate StartTime
-------------------------------
1389/07/11 11:04
1389/06/23 21:17
1389/06/23 21:32
1389/06/23 22:10
1389/06/26 12:34
1389/06/27 17:29
1389/06/27 18:13
1389/06/27 20:27
1389/06/28 09:41
1389/07/18 10:46
1389/07/05 22:00
1389/07/15 24:00
output is:
when the query is : (1)
SELECT StartDate, StartTime
FROM Proj
WHERE (StartDate < '1389/07/15 ') AND (StartTime <= '20:20 ')
StartDate StartTime
-------------------------------
1389/07/11 11:04
1389/06/26 12:34
1389/06/28 09:41
1389/07/18 10:46
output is:
when the query is: (2)
SELECT StartDate, StartTime
FROM Proj
WHERE (StartDate > '1389/07/15 ') AND (StartTime >= '20:20 ')
StartDate StartTime
-------------------------------
NULL NULL
the correct output should be:
StartDate StartTime
-------------------------------
1389/07/18 10:46
i use persian date.
Just taking what you have above and the description of your problem, the query should be:
select * from test where date>'2010/10/05' and time>='20:22'
If you post more details about your problem and the schema in which you're working we'll be able to help you more.
I want to select records that "time" is greater than now time and the "date" is greater than now date.
First off to get the current datetime (your now), you can use the SQL function GETDATE().
So if you happen to have a datetime column you could just do
SELECT * FROM Test WHERE LogDateTime >= GETDATE()
This will return every record in the table Test of which the datetime value inside the LogDateTime column is in the future.
Now, although it's a little bit more complicated, the same can be used when you have split the date and the time into separate columns.
SELECT * FROM Test
WHERE CONVERT(datetime, LogDate + ' ' + LogTime) >= GETDATE()
If LogDate or LogTime are nullable columns you could use ISNULL(<columnName>, <defaultvalue>) to be safe.
it solved:
SELECT StartDate, StartTime
FROM Proj
WHERE (StartTime < '20:20 ') AND (StartDate = '1389/07/15') OR
(StartDate > '1389/07/15')

Categories

Resources