Rounding artefacts when converting Double Precision column to Date - firebird

In a table dates are being saved as datatype DOUBLE PRECISION. Trying to convert it into date format but incorrect dates coming up when timestamp is greater than 12PM.(i.e gives date for next day if timestamp is greater or equal to 12:00:00.000)
This is what I've tried
dateColumn + CAST ('30.12.1899' AS DATE)
DATE'1899-12-30' + dateColumn
Example
SELECT po.DELIVERYDATE as DOUBLE_FORMAT,
po.DELIVERYDATE + CAST ('30.12.1899' AS TIMESTAMP) as DATE_TIMESTAMP_FORMAT,
po.DELIVERYDATE + CAST ('30.12.1899' AS DATE) as DATE_FORMAT_1,
DATE'1899-12-30' + po.DELIVERYDATE as DATE_FORMAT_2
FROM PURCHASE_ORDER po
Result
DOUBLE_FORMAT DATE_TIMESTAMP_FORMAT DATE_FORMAT_1 DATE_FORMAT_2
------------- ------------------------ ------------- -------------
41485.421586 30.07.2013, 10:07:05.000 30.07.2013 30.07.2013
41488.487419 02.08.2013, 11:41:53.000 02.08.2013 02.08.2013
41488.489792 02.08.2013, 11:45:18.000 02.08.2013 02.08.2013
41506.630035 20.08.2013, 15:07:15.000 21.08.2013 21.08.2013 //<-- Incorrect
41516.514479 30.08.2013, 12:20:51.000 31.08.2013 31.08.2013 //<-- Incorrect
41521.402963 04.09.2013, 09:40:16.000 04.09.2013 04.09.2013
41520.511030 03.09.2013, 12:15:53.000 04.09.2013 04.09.2013 //<-- Incorrect

That's arithmetic: when you are rounding a floating point to integer, then 2.5 is rounded to 3 not to 2.
So you have to
either, explicitly convert float to integer in the direction you want before offsetting the base date
or, since your data is both date and time - then convert it to TIMESTAMP first and only after that conversion do apply the rounding to DATE
Example:
select
41516.514479, -- 41516,514479
cast( 41516.514479 as integer ), -- 41517
round( 41516.514479 ), -- 41517
41516.514479 + DATE '1899-12-30', -- 31.08.2013
floor( 41516.514479 ), -- 41516
floor( 41516.514479 ) + DATE '1899-12-30', -- 30.08.2013
41516.514479 + timestamp '1899-12-30', -- 12:20 30.08.2013
cast(41516.514479 + timestamp '1899-12-30' as DATE) -- 30.08.2013
from rdb$database

Related

Add to DATE hour - TSQL

I have a column type time(7).
What i want is to add in time column to date.
i manage to get the only date using GETDATE() function but i fail to add the time part next to date.
Query:
SELECT [Compay]
,[Time]
,CAST(GETDATE() AS DATE) AS Today
,CAST(CAST(GETDATE() AS DATE) AS NVARCHAR) AS Today_AS_Nvarchar
,CAST([Time] AS NVARCHAR) AS Time_AS_Nvarchar
,CAST(CAST(GETDATE() AS DATE) AS NVARCHAR) + ' ' + CAST([Time] AS NVARCHAR) AS Today_Time_AS_Nvarchar
,CONVERT(datetime,CAST(CAST(GETDATE() AS DATE) AS NVARCHAR) + ' ' + CAST([Time] AS NVARCHAR),103)
FROM [Testing_Env].[dbo].[Com_CD_Test]
Error:
Conversion failed when converting date and/or time from character string.
The error arise on CONVERT(datetime,CAST(CAST(GETDATE() AS DATE) AS NVARCHAR) + ' ' + CAST([Time] AS NVARCHAR),103)
is there any easier/orthodox way to achieve it?
You can't add the new date and time data types together like you can the old data types; personally I think this is also better as it stop people treating dates and times like a numerical value.
Assuming you have a date column and a time column you have a few of options. The first is to CAST/CONVERT both to a datetime and then "add" them together. Because the "old" data types work more like numerical values this works, however, you will lose accuracy of your time value if it has a precision of 3 or higher (as datetime is only accurate to 1/300 seconds):
DECLARE #TimeValue time(7) = '17:52:12.1234567',
#DateValue date = '20211016';
SELECT CONVERT(datetime, #DateValue) + CONVERT(datetime, #TimeValue);
If loosing accuracy isn't an option, then you could to use conversion on the date value and use DATEDIFF and DATEADD. For a time(7) you'll want to be using nanoseconds (as microseconds isn't accurate enough). Unfortunately this poses another problem; DATEADD can't handle bigint values (still) and there is no DATEADD_BIG (like there is DATEDIFF_BIG), so this becomes overly complex. You need to first get the difference in milliseconds, and then add the remainder in nanoseconds to still be accurate to 1/1000000 of a second:
DECLARE #TimeValue time(7) = '17:52:12.1234567',
#DateValue date = '20211016';
SELECT DATEADD(NANOSECOND,DATEDIFF_BIG(NANOSECOND,'00:00:00', #TimeValue) % 1000000,DATEADD(MILLISECOND, DATEDIFF_BIG(MILLISECOND,'00:00:00', #TimeValue), CONVERT(datetime2(7),#DateValue)));
Finally, yes, you can convert to values to strings, and then to a datetime2 value; this is probably the easiest methiod. You just need to ensure you use style codes:
DECLARE #TimeValue time(7) = '17:52:12.1234567',
#DateValue date = '20211016';
SELECT CONVERT(datetime2(7),CONVERT(varchar(10), #DateValue, 23) + 'T' + CONVERT(varchar(17), #TimeValue, 114),126);

Converting Integer values to Date in Presto SQL

Below is a script i am trying to run in Presto; Subtracting today's date from an integer field I am attempting to convert to date. To get the exacts days between. Unfortunately, it seems the highlighted block does not always convert the date correctly and my final answer is not correct. Please does anyone know another way around this or a standard method on presto of converting integer values to date.
Interger value in the column is in the format '20191123' for year-month-date
select ms, activ_dt, current_date, date_diff('day',act_dt,current_date) from
(
select ms,activ_dt, **CAST(parse_datetime(CAST(activ_dt AS varchar), 'YYYYMMDD') AS date) as act_dt**, nov19
from h.A_Subs_1 where msisdn_key=23480320012
) limit 19
You can convert "date as a number" (eg. 20180527 for May 27, 2018) using the following:
cast to varchar
parse_datetime with appropriate format
cast to date (since parse_datetime returns a timestamp)
Example:
presto> SELECT CAST(parse_datetime(CAST(20180527 AS varchar), 'yyyyMMdd') AS date);
_col0
------------
2018-05-27
You can use below sample query for your requirement:
select date_diff('day', date_parse('20191209', '%Y%m%d'), current_timestamp);

Convert Time format(hh:mm) to Decimal format

I am getting hours by subtracting time fields in the format hh:mm(00:21)
by using this
rtrim(char(TIMESTAMPDIFF(8,char(LABTRANS.finishtime - LABTRANS.starttime)))) || ':'|| rtrim(char(mod(int(TIMESTAMPDIFF(4,char(LABTRANS.finishtime - LABTRANS.starttime))),60))) as total_time,
), but i have to show in decimal value ( 0.3500 ). How can i achieve it.
see my sample table :
-->create table labtrans(starttime TIME,finishtime TIME)
-->insert into labtrans(starttime , finishtime )
values( '08:02 Am','08:42 Am'),
( '07:02 Am','08:42 Am'),
( '01:02 pm','09:02 PM'),
( '06:02 Am','08:00 Am')
When you subtract TIME columns in Db2, there result is DEC(6,0) in the following format: HHMMSS (time duration).
See the Time arithmetic topic for details.
So, if you need to express time duration in the HH+MM/60 format, then you may use the following:
select
starttime, finishtime
, finishtime-starttime hhmmss
, int(finishtime-starttime)/10000
+ dec(mod((finishtime-starttime)/100, 100), 27)/60 as "hh+mm/60"
from labtrans
The result is:
STARTTIME FINISHTIME HHMMSS hh+mm/60
--------- ---------- ------ --------
08:02:00 08:42:00 4000 0.6666
07:02:00 08:42:00 14000 1.6666
13:02:00 21:02:00 80000 8.0000
06:02:00 08:00:00 15800 1.9666
does this help at all?
values hour(current time) + .01 * minute(current time)
returns
1
----------------
10.14
1 record(s) selected.

How to convert a column in seconds to dateformat in Teradata?

I have a column which is of bigint datatype(in seconds) which should be added to a date, so i need to convert this column into dateformat.
The arithmetic must be done against a timestamp data type in Teradata. The date data type does not have a time element associated with it. The following SQL should help point you in the right direction:
SELECT CAST(CAST(1234 AS BIGINT) AS INTERVAL SECOND(4)) AS Seconds_
, CURRENT_TIMESTAMP(0) AS CurrentTimestamp_
, CURRENT_TIMESTAMP + Seconds_ AS NewTimeStamp
If the number of seconds is less than 864000000 you can simply use interval arithmetic:
CAST(col AS TIMESTAMP) + (bigintcol * INTERVAL '0000 00:00:01' DAY TO SECOND)
Based on your other question your input is a Unixtime, those are two functions for converting them from/to Teradata timestamps:
/**********
Converting Unix/POSIX time to a Timestamp
Unix time: Number of seconds since 1970-01-01 00:00:00 UTC not counting leap seconds (currently 24 in 2011)
Also working for negative numbers.
The maximum range of Timestamps is based on the range of INTEGERs:
1901-12-13 20:45:52 (-2147483648) to 2038-01-19 03:14:07 (2147483647)
Can be changed to use BIGINT instead of INTEGER
20101211 initial version - Dieter Noeth
**********/
REPLACE FUNCTION UnixTime_to_TimeStamp (UnixTime INT)
RETURNS TimeStamp(0)
LANGUAGE SQL
CONTAINS SQL
DETERMINISTIC
SQL SECURITY DEFINER
COLLATION INVOKER
INLINE TYPE 1
RETURN
CAST(DATE '1970-01-01' + (UnixTime / 86400) AS TIMESTAMP(0))
+ ((UnixTime MOD 86400) * INTERVAL '00:00:01' HOUR TO SECOND)
;
SELECT
UnixTime_to_TimeStamp(-2147483648)
,UnixTime_to_TimeStamp(0)
,UnixTime_to_TimeStamp(2147483647)
;
/**********
Converting a Timestamp to Unix/POSIX time
Unix time: Number of seconds since 1970-01-01 00:00:00 UTC not counting leap seconds (currently 24 in 2011)
The maximum range of Timestamps is based on the range of INTEGERs:
1901-12-13 20:45:52 (-2147483648) to 2038-01-19 03:14:07 (2147483647)
Can be changed to use BIGINT instead of INTEGER
20101211 initial version - Dieter Noeth
**********/
REPLACE FUNCTION TimeStamp_to_UnixTime (ts TimeStamp(6))
RETURNS INTEGER
LANGUAGE SQL
CONTAINS SQL
DETERMINISTIC
SQL SECURITY DEFINER
COLLATION INVOKER
INLINE TYPE 1
RETURN
(CAST(ts AS DATE) - DATE '1970-01-01') * 86400
+ (EXTRACT(HOUR FROM ts) * 3600)
+ (EXTRACT(MINUTE FROM ts) * 60)
+ (EXTRACT(SECOND FROM ts))
;
SELECT
TimeStamp_to_UnixTime(TIMESTAMP '1901-12-13 20:45:52')
,TimeStamp_to_UnixTime(CURRENT_TIMESTAMP)
,TimeStamp_to_UnixTime(TIMESTAMP '2038-01-19 03:14:07')
;

TSQL update Datetime with Random Value between 2 Dates

What's the easiest way to update a table that contains a DATETIME column on TSQL with RANDOM value between 2 dates?
I see various post related to that but their Random values are really sequential when you ORDER BY DATE after the update.
Assumptions
First assume that you have a database containing a table with a start datetime column and a end datetime column, which together define a datetime range:
CREATE DATABASE StackOverflow11387226;
GO
USE StackOverflow11387226;
GO
CREATE TABLE DateTimeRanges (
StartDateTime DATETIME NOT NULL,
EndDateTime DATETIME NOT NULL
);
GO
ALTER TABLE DateTimeRanges
ADD CONSTRAINT CK_PositiveRange CHECK (EndDateTime > StartDateTime);
And assume that the table contains some data:
INSERT INTO DateTimeRanges (
StartDateTime,
EndDateTime
)
VALUES
('2012-07-09 00:30', '2012-07-09 01:30'),
('2012-01-01 00:00', '2013-01-01 00:00'),
('1988-07-25 22:30', '2012-07-09 00:30');
GO
Method
The following SELECT statement returns the start datetime, the end datetime, and a pseudorandom datetime with minute precision greater than or equal to the start datetime and less than the second datetime:
SELECT
StartDateTime,
EndDateTime,
DATEADD(
MINUTE,
ABS(CHECKSUM(NEWID())) % DATEDIFF(MINUTE, StartDateTime, EndDateTime) + DATEDIFF(MINUTE, 0, StartDateTime),
0
) AS RandomDateTime
FROM DateTimeRanges;
Result
Because the NEWID() function is nondeterministic, this will return a different result set for every execution. Here is the result set I generated just now:
StartDateTime EndDateTime RandomDateTime
----------------------- ----------------------- -----------------------
2012-07-09 00:30:00.000 2012-07-09 01:30:00.000 2012-07-09 00:44:00.000
2012-01-01 00:00:00.000 2013-01-01 00:00:00.000 2012-09-08 20:41:00.000
1988-07-25 22:30:00.000 2012-07-09 00:30:00.000 1996-01-05 23:48:00.000
All the values in the column RandomDateTime lie between the values in columns StartDateTime and EndDateTime.
Explanation
This technique for generating random values is due to Jeff Moden. He wrote a great article on SQL Server Central about data generation. Read it for a more thorough explanation. Registration is required, but it's well worth it.
The idea is to generate a random offset from the start datetime, and add the offset to the start datetime to get a new datetime in between the start datetime and the end datetime.
The expression DATEDIFF(MINUTE, StartDateTime, EndDateTime) represents the total number of minutes between the start datetime and the end datetime. The offset must be less than or equal to this value.
The expression ABS(CHECKSUM(NEWID())) generates an independent random positive integer for every row. The expression can have any value from 0 to 2,147,483,647. This expression mod the first expression gives a valid offset in minutes.
The epxression DATEDIFF(MINUTE, 0, StartDateTime) represents the total number of minutes between the start datetime and a reference datetime of 0, which is shorthand for '1900-01-01 00:00:00.000'. The value of the reference datetime does not matter, but it matters that the same reference date is used in the whole expression. Add this to the offset to get the total number of minutes between the reference datetime.
The ecapsulating DATEADD function converts this to a datetime value by adding the number of minutes produced by the previous expression to the reference datetime.
You can use RAND for this:
select cast(cast(RAND()*100000 as int) as datetime)
from here
Sql-Fiddle looks quite good: http://sqlfiddle.com/#!3/b9e44/2/0