I have a doubt related to using datetimeoffset in SQL server 2008 r2.
Suppose I have a web application, the db server in Spain and the client is in Canada. I don't know the time zone between Spain and Canada but suppose its 5 hours more in Spain.
So user in Canada wants to add a new Employee at 23:00 PM, when clicks save, it calls a stored procedure that inside call the function SYSDATETIMEOFFSET() to fill the column CreatedDate that has a datatype datetimeoffset(7).
In this case, what will be the datetime saved in the database? and How should I do to show the right datetime to the user in Canada that wants to check the CreatedDate? Is there any good example to check this?
According to MSDN:
The data is stored in the database and processed, compared, sorted, and indexed in the server as in UTC. The time zone offset will be preserved in the database for retrieval.
In your example, the data will be stored in a binary format that can be translated to 14 Nov 2013 23:00 -5:00, which means the date and time that is local plus the time offset of -5 hours to UTC (let's suppose this is the offset for Canada).
When you store this type of value, you have to provide the offset yourself, the system doesn't do it automatically.
Because the data is stored as UTC time, it makes comparison, sorting, etc. of data easy, while you can always retrieve the original time offset.
You should generally store client's local time with offset when storing information about events that need to be compared across time zones.
More on datetimeoffset on MSDN.
Example
Create a table and insert data
create table dto (dto datetimeoffset(7))
insert into dto values (GETDATE()) -- inserts date and time with 0 offset
insert into dto values (SYSDATETIMEOFFSET()) -- current date time and offset
insert into dto values ('20131114 08:54:00 +10:00') -- manual way
When I select the data, I get
2013-11-14 07:56:17.2300000 +00:00 -- current time, no offset so useless in this case
2013-11-14 07:56:17.2338125 +11:00 -- current time with my local offset (in Australia)
2013-11-14 08:54:00.0000000 +10:00 -- manually inserted data
You can simply store the UTC date in your DB
Select GetUTCDate()
For Example, DB Server is in Spain and a client in CANADA
adds a new Employee Joining date in System. (UTC Date) 14 Nov 2013 23:00
so if you want to show the right DateTime to the user in Canada you need to add/subtract your current time zone offset like if in Canada it's UTC-4 so
Select Cast('14 Nov 2013 23:00' as Datetime) as [UTC TIME]
Select DateAdd(hour,+2,Cast('14 Nov 2013 23:00' as Datetime)) as [Time In Spain]
Select DateAdd(hour,-4,Cast('14 Nov 2013 23:00' as Datetime)) as [Time In Canada]
Result
14 Nov 2013 23:00
15 Nov 2013 01:00
14 Nov 2013 19:00
you can make some function to do this...
Related
I have a cronjob that looks at load previous day data sourcing another table that gets refreshed on a daily basis. I am looking to update the job to source from origination table that holds entire year of data. However I am just looking to capture and load previous 1 day of data from the origination table. The origination table has a date updated field which is in timestamptz format (ex - 2022-08-01 20:20:20.736+00). Any recommendation on what function to place where the job picks up:
last_updated from >= 2022-08-01 10:00:00 and last_updated from <= 2022-08-02 10:00:00. Assuming I am running this on 2022-08-02 11:00:00.
Thanks,
Let's say I have a table with date-timestamp column in a table and every time I pass a date and time to it, I want to get the data for last 24 hours from that timestamp.
say, on querying for TIMESTAMP 23/03/2019 18:00:00
it should filter out and give results for the following period:
22/03/2019 18:00:01 to 23/03/2019 18:00:00
You may use an Interval expression to go back 1 day.
where timestamp_column > :v_timestamp - INTERVAL '1' DAY
AND timestamp_column <= :v_timestamp --The date you want to pass.
I have this issue databases: on Oracle and Netezza.
ISSUE: I have a string: 16101211213. This string means: YYMMDDHH24MMSS. I need to convert it to date format YYYY-MM-DD HH24:MM:SS. So on the way I need to add the two digits (in front of the string). I know that dates are for XXI century. So I need to 20 at the begining.So in result I should get 2016-10-12 21:12:13
Can anybody help me with it? I have tried many options (mainly on Netezza) but could not figure it out.
Thanks a lot in advance!
RR might be your savior.
SQL> alter session set nls_date_format = 'dd.mm.yyyy hh24:mi:ss';
Session altered.
SQL> with test as (select '16101211213' datum from dual)
2 select to_date(datum, 'rrmmddhh24miss') result
3 from test;
RESULT
-------------------
12.10.2016 11:21:03
SQL>
Oh, and - be careful! You used wrong format mask for minutes; it is "MI", not "MM" (which is a month).
[EDIT: displaying result using a different format mask]
SQL> with test as (select '16101211213' datum from dual)
2 select
3 to_date(datum, 'rrmmddhh24miss') result_1,
4 to_char(to_date(datum, 'rrmmddhh24miss'), 'mm/dd/yyyy hh:mi:ss am') result_2
5 from test;
RESULT_1 RESULT_2
------------------- ----------------------
12.10.2016 11:21:03 10/12/2016 11:21:03 AM
SQL>
You can either reply on Oracle inferring the year by converting with the YY or RR format model elements, or concatenate the century value and use YYYY.
If you are really sure that the dates are all in the 21st century then using concatenation and YYYY:
to_date('20' || tistamp, 'yyyymmddhh24miss')
will behave the same as using YY (which uses the current date to decide the century):
to_date(tistamp, 'yymmddhh24miss')
and if all the years are below 50 then RR (which uses the current date's century or the last century depending on the supplied 2-digit year) will also get the same result:
to_date(tistamp, 'rrmmddhh24miss')
But if any of the values are 50 or above RR and YY/YYYY behave differently. As these seem to be event timestamps it's unlikely they will be in the future, but the difference may still matter one day. (But then, eventually, assuming 21st century might not be valid either...)
Quick demo of the difference, using your sample value and a couple of others, supplied via a CTE:
alter session set nls_date_format = 'YYYY-MM-DD HH24:MI:SS';
with your_table(tistamp) as (
select '16101211213' from dual
union all select '491231235959' from dual
union all select '500101000000' from dual
)
select to_date('20' || tistamp, 'yyyymmddhh24miss') as yyyy,
to_date(tistamp, 'yymmddhh24miss') as yy,
to_date(tistamp, 'rrmmddhh24miss') as rr
from your_table;
YYYY YY RR
------------------- ------------------- -------------------
2016-10-12 11:21:03 2016-10-12 11:21:03 2016-10-12 11:21:03
2049-12-31 23:59:59 2049-12-31 23:59:59 2049-12-31 23:59:59
2050-01-01 00:00:00 2050-01-01 00:00:00 1950-01-01 00:00:00
All of these would also work with to_timestamp() of course; as you don't have fractional seconds or time zone info using dates should be fine as long as your client knows that Oracle dates have a time component.
I am trying to find submitted data based on the start and end range entered.
Suppose i have submitted the data today, 30th june
When I give the range as start date, 1 june and end date, 30th june I dont get today's submitted data. When i give start date, 1 june and end date, 1st july I get today's submitted data. How to include start and end date too in the where clause?
AS
BEGIN
#Year navchar(200) = null
#Rtype navchar(200) = = null
SELECT *
FROM ProjectDetails
where SubmittedDate Between #Year and #Rtype
END
This is because you're misunderstanding how dates work. This is further evidenced by the fact that you're passing and using your dates as strings
First off, dates internally to sql server are expressed as numbers of days since a certain date (midnight on 1/1/1900)
This means a date of 2 jan 1900 is internally expressed by sqlserver as 1.0. A date of 1800 hours on 2 jan 1900 is expressed internally as 1.75 - because there have been 1.75 days since midnight on the first. 6pm is three quarters the way through a 24 hour day hence the .75 part in the internal representation
With me so far?
it is the decimal point part that is defeating your logic
Let's see an example
Lets say you want records between 1 jan 1900 and 10 jan 1900, so really, you want records that have a time anything up to 23:59:59 (and 999999... milliseconds) on 10 jan 1900
This means you want records that are between 0.0 and 9.999999999 days after midnight on 1 jan....
But when you're running your query, you're just asking for:
BETWEEN #1 jan 1900# and #10 jan 1900#
In SQL terms this is
BETWEEN 0.0 and 9.0
And not what you want:
BETWEEN 0.0 and 9.9999999999999999999999999....
Ultimately, midnight is the very first thing that happens on a day. You won't get any records for 6am on the 10th jan because that is WELL AFTER midnight, it is a decimal number like 9.25
I'm sure you can appreciate that 9.25 is NOT BETWEEN 0.0 and 9.0
You will however get records that occurred exactly bang on midnight on the 10th, because they would internally be represented as 9.0, and 9.0 is between 0.0 and 9.0
So you need to alter the way you are doing your query:
date >= startdate AND date < enddate_plus_one_day
i.e. in internal date representation tersm if you want yo get the dates that are 6am, i.e. the 9.25 days after 1 jan 1900, then you need to be querying date >= 0.0 and date < 10.0 - this will return the records all the way up to and including 23:59:59
I also complained at your querying style - youre passing dates as strings and hoping that sqlserver will figure you out. Don't do this. Be explicit:
SELECT *
FROM ProjectDetails
where SubmittedDate >= CONVERT(datetime, #Year, 112)--pass date as string in yyyymmdd
AND SubmittedDate < (CONVERT(datetime, #Rtype, 112)+1.0) --pass date as a string in yyyymmdd
- --Convert The Date And check The Result Output
DECLARE
#Year NVARCHAR(200) = null,
#Rtype NVARCHAR(200) = null
SELECT *
FROM ProjectDetails
WHERE CONVERT(NVARCHAR, SubmittedDate,111) >= CONVERT(NVARCHAR,#Year,111) AND CONVERT(NVARCHAR,
SubmittedDate,111)<= CONVERT(NVARCHAR,#Rtype,111)
I want to fetch some data from DB by giving multiple date ranges. Example,in February I want to get weekly report from a table in this order Feb 01 to 07, Feb 07 to 14, Feb 14 to 21, Feb 21 to 28 and Feb 28 to Mar 01. In DB the records are stored in a daily wise not in weekly wise. I want to cluster it as weekly wise and calculate sum then show the result. Please help me if you know this case.
For clear cut view, consider 3 tables & its columns.
Table A:id,timestamp (comment-data is inserted daily)
Table B:id,fruits
Table C:id,fruits_type
Result:
fruits_type count(id) timestamp
apple 3 01-02-2016 to 07-02-2016
orange 5 01-02-2016 to 07-02-2016
pineapple 8 01-02-2016 to 07-02-2016
apple 4 07-02-2016 to 14-02-2016
orange 5 07-02-2016 to 14-02-2016
Conditions:id should match among 3 tables;fetch data by providing group by fruits_type and timestamp should be in weekly wise.
Please help if you know this
To get the sum of all values between two dates you would do it like this:
SELECT SUM(Column1)
FROM Table1
WHERE Date1 BETWEEN '2/1/2016' AND Date1 <'2/7/2016'
If you want to make it more flexible and have the query get the last week's sum you can use the DATEADD function to lag by one week:
SELECT SUM(Column1)
FROM Table1
WHERE Date1 BETWEEN DATEADD(week, -1, GETDATE()) AND Date1 < GETDATE()
If you want the result set to include a row for each week, you can use UNION to merge the queries.