Battling Datediff in SQL - sql

I am writing a little query in SQL and am butting heads with an issue that it seems like someone must have run into before. I am trying to find the number of months between two dates. I am using an expression like ...
DATEDIFF(m,{firstdate},{seconddate})
However I notice that this function is tallying the times the date crosses the monthly threshold. In example...
DATEDIFF(m,3/31/2011,4/1/2011) will yield 1
DATEDIFF(m,4/1/2011,4/30/2011) will yield 0
DATEDIFF(m,3/1/2011,4/30/2011) will yield 1
Does anyone know how to find the months between two dates more-so based upon time passed then times passed the monthly threshold?

If you want to find some notional number of months, why not find the difference in days, then divide by 30 (cast to FLOAT as required). Or 30.5-ish perhaps - depends on how you want to handle the variable month length throughout the year. But perhaps that's not a factor in your particular case.

The following statements have the same startdate and the same endate. Those dates are adjacent and differ in time by .0000001 second. The difference between the startdate and endate in each statement crosses one calendar or time boundary of its datepart. Each statement returns 1. ...
SELECT DATEDIFF(month, '2005-12-31 23:59:59.9999999'
, '2006-01-01 00:00:00.0000000'); ....
(from DATEDIFF, section datepart Boundaries ). If you are not satisfied by it, you probably need to use days as unit as proposed by martin clayton

DATEDIFF(m,{firstdate},ISNULL({seconddate},GETDATE())) - CASE
WHEN DATEPART(d,{firstdate}) >= DATEPART(d,ISNULL({seconddate},GETDATE()))
THEN 1
ELSE 0

DATEDIFF is like this by design. When evaluating a particular time measurement (like months, or days, etc.), it considers only that measurement and higher values -- ignoring smaller ones. You'll run into this behavior with any time measurement. For example, if you used DATEDIFF to calculate days, and had one date a few seconds before midnight, and another date a few seconds after midnight, you'd get a "1" day difference, even though the two dates were only a few seconds apart.
DATEDIFF is meant to give a rough answer to questions, like this:
Question: how many years old are you?
Answer: some integer. You don't say "I'm 59 years, 4 months, 17 days, 5 hours, 35 minutes and 27 seconds old". You just say "I'm 59 years old". That's DATEDIFF's approach too.
If you want an answer that's tailored to some contextual meaning (like your son who says "I'm not 8! I'm 8 and 3-quarters!, or I'm almost 9!), then you should look at the next-smallest measurement and approximate with it. So if it's months you're after, then do a DATEDIFF on days or hours instead, and try to approximate months however it seems most relevant to your situation (maybe you want answers like 1-1/2 months, or 1.2 months, etc.) using CASE / IF-THEN kinds of logic.

Related

Trying to accommodate relative defined date, such as 5 days ago, into my fixed date condition in PostgreSQL

I'm trying to condition my WHERE clause to accommodate relatively defined dates into my date filter. I'm pretty confused what type I need to use, if it's CONVERT or TO_DATE function, or if I need to put a CASE WHEN statement into my code.
This is the code that I have written so far:
WHERE event_create_verified_user_success.created_at_utc_date
BETWEEN DATE '2021-11-29' AND DATE '2021-12-05'
And this is the condition of the activity I need to finish:
If the desired date-period is not set manually using fixed dates like from “2021-11-29”
to “2021-12-05”, how would you change the where-clause to consider all data from relative
defined dates: “consider messages created between 10 days and 5 days ago (inclusive)”
I've only started PostgreSQL yesterday and the last time I've handle SQL was probably 4 years ago so I'm pretty confused at how much SQL has changed since then.
Thank you so much for helping!
The basic syntax hasn't really changed in the last 4 years (or even 15 years).
You can use current_date to obtain "today's date". You can subtract days from that
where ... between current_date - 10 and current_date - 5
If created_at_utc_date is a timestamp (= date and time) rather than a date (=date without time) it's better to use a range query though:
where created_at_utc_date >= current_date - 10
and created_at_utc_date < current_date - 4
Note the < combined with the next day you want to compare with.

sql Teradata difference in months

I need to get the difference between dates, but I just need to get the whole months that have passed. So for example between "1990-05-24" and "1990-05-27" it should say 0. It would also be 0 for "1990-05-02" and "1990-05-29" because the month has not finished.
I already got the difference in months using MONTHS_BETWEEN(), but I get months with decimals, and ROUNDing is not an option since sometimes it should be up and sometimes down.
I thought about setting al dates to day 01. In both colums Closing_date and Opening_date. But can't figure out how to do it.
I think you want to count boundaries between months. If so, you can use months_between() after truncating to the first of the month:
months_between(trunc(date1, 'MON'), trunc(date2, 'MON')

sql statement - would like to subtract 1 date from another and get the days hours and mins inbetween

I would like to subtract 1 date from another and get the days hours and mins in-between.
I know there is a DateDiff function, however it does not work with all 3 time values; days hours and mins. I would like this doable in an SQL statement. Currently I have the following.
SELECT id, pickupdateandtime, GETDATE() AS CurrentTime,
(DATEDIFF(day,GETDATE(),pickupdateandtime)) AS Days,
(DATEDIFF(hour,GETDATE(),pickupdateandtime)) AS Hours,
(DATEDIFF(minute,GETDATE(),pickupdateandtime)) AS Mins FROM orders
And it shows up like this:
If we can stick it all in 1 column that's fine too.
I agree with #AndyMcLaughlin about the use of the mod operator % here. It's very handy for this sort of thing. However, I have a general distrust of DATEDIFF. That function does not count the whole number of years (say) between two dates, but the number of year boundaries between them.
So DATEDIFF "thinks" the difference in years between 01-Jan-2000 and 01-Jan-2001 is the same as that between 31-Dec-2000 and 01-Jan-2001.
This is why #Michael saw a need to subtract 1 from #AndyMcLaughlin's results. Unfortunately, that doesn't always work, it will depend on the individual case.
As a rule, DATEDIFF works well when it's used against the smallest interval you are interested in. So if you are interested in years and simply want to separate one calendar year from another, it'll serve you well.
I think the smallest interval we are interested in here is minutes. So we can use DATEDIFF for that, but have to work upwards from there to hours and days:
select
mf.id,
mf.pickupdateandtime,
mf.CurrentTime,
--The divisions in the following lines simply
--truncate since all the numbers are integers
--but that works in our favour here
(mf.MinutesFull/(60*24)) as Days,
(mf.MinutesFull/60) % 24 as Hours,
mf.MinutesFull % 60 as Minutes
from
(
select
id,
pickupdateandtime,
getdate() as CurrentTime,
datediff(minute, getdate(), pickupdateandtime) as MinutesFull
from #orders
) mf
You need to use the mod operator % to remove whole days from hours and whole hours from minutes.
So you can do something like:
SELECT
id,
pickupdateandtime,
GETDATE() AS CurrentTime,
(DATEDIFF(day,GETDATE(),pickupdateandtime)) AS Days,
(DATEDIFF(hour,GETDATE(),pickupdateandtime) % 24) AS Hours,
(DATEDIFF(minute,GETDATE(),pickupdateandtime) % 60) AS Mins FROM orders

Cannot convert number to date

I have problem converting number column to date, I did the following
SELECT to_date('12-30-1899 1:00:00','MM-DD-YYYY HH24:Mi:SS') + (createDate/1440)
FROM table_A;
and got the query result
10/17/5826 17:18
The month and date including hours and seconds is right but the year is different I got 5826. Its also the same for the other rows i got different results for year. I did follow some examples on this here. But still got wrong result. Can anyone help on this thanks.
The samples below are createDate column values:
1300844909778
1302831103113
1303210978316
1396963615616
Date arithmetic in Oracle assumes days. As it stands you are dividing a very large number by 1440 and adding that number of days to your starting date. That's why you're getting results in the far future.
So what value does createdate represent? It's clearly not an actual date. Your choice of 1440 as denominator suggests you think it's meant to be "number of minutes" but if the dates are so far out of expectation that is not it either.
I thought could be values represented in the Unix epoch because the numbers start with 13. Except that they're way too big. Current Unix timestamps should be ten digits. You've got thirteen digits.
Could they be Unix epoch plus milliseconds?
I have created a SQLfiddle to test this theory. Treating the first ten digits of your createdate values as seconds and adding that number to the Unix date produces sensible dates. Check it out.
So the theory holds water. But I doesn't help with your query. Adding two dates together doesn't make any sense. What are you actually trying to achieve? If your're looking for an interval you need to subtract the earlier date from the later one.
The createDate could be the number of milliseconds. It is just a guess. If so, then maybe this helps:
SELECT to_date('12-30-1899 1:00:00','MM-DD-YYYY HH24:Mi:SS') + (1300844909778/(1000*60*60*24))
FROM dual
/
3/21/1941 2:48:30 AM

Does DateDiff Round up?

I found a place in our old code where the original programmer tried to calculate whether an employee had been hired for a certain number of years. The calculation used the difference in days between the date hired and today divided by 364. This didn't make sense to me so I changed it to the difference in years. This also seemed to give an incorrect answer. Does DateDiff round up to the nearest year? Running this formula in the immediate window gives 15 as the answer. I was hoping it would give 14.
?datediff("yyyy",#3/1/1999#,#2/19/2014#)
Would it be better to use.
?datediff("m",#3/1/1999#,#2/19/2014#)/12
DateDiff for years only considers the year parts of the dates you supply. And it does not return what you might want as "how many years" ...
For example, the last day of 2013 to the first day of 2014 would be one year as far as DateDiff("yyyy" is concerned.
? DateDiff("yyyy", #2013-12-31#, #2014-1-1#)
1
DateDiff rounds off to the very next year if the year difference is like x years and y months.
For example:
if a person's age is 18 years and 1 months, datediff(yy,DDOB,GetDate()) will give result as '19'.
In case you dont want this rounding off, you can
Get difference in days between two dates after casting them in
INTEGER
Divide the difference with 365.25
Use FLOOR to ignore the the decimal part (don't round off as the
next number):
FLOOR((CAST (GetDate() AS INTEGER) - CASR(YourDate AS INTEGER)) / 356.25)
You can do the combination of IIf,DateDiff and DateAdd, like this:
=IIf(DateDiff("m";DateAdd("yyyy";DateDiff("yyyy";[DDOB];Date());[DDOB]);Date())<0;
DateDiff("yyyy";[DDOB];Date())-1;
DateDiff("yyyy";[DDOB];Date()))
So, firstly you calculate months between DDOB plus DateDiff years and Date(), and if integer form DateDiff "m" are in minus, then IIf will reduce the value for the year for one.