Get Number of Months and Days Between Dates - sql

In PL/SQL I have 2 dates and I need to find out the number of months between them and the days as well. For example date 1 is 1/10/2022 and date 2 is 2/12/2022 that would be 1 month and 2 days. I'm pretty secure in obtaining the number of months, but the days number has been a thorn in my side. Sometimes it comes out correct, sometimes it comes out short and other times it comes out too far. I would imagine it is because of the different number of days in the months, but I can't prove that just yet. Any help is appreciated.

Oracle provides a months_between function to do the calculation.
That isn't a good idea as the number of days in a month varies, it's not exactly known what the decimal part of the number represents.
select months_between(date '2022-04-03', date '2022-01-01') from dual;
MONTHS_BETWEEN(DATE'2022-04-03',DATE'2022-01-01')
3.06451612903225806451612903225806451613
If you assume every month has 30 days, then comparisons over larger date ranges (years) will be out by more and more days the larger the difference gets.
However, if you combine methods, using months_between to get the months, and then assume 30 days for a month to get the days part from the remainder, it's more consistent over longer periods…
with dates as (select date '2022-01-01' as date_from, date '2022-04-03' as date_to from dual)
select months_between(date_to, date_from) ,trunc(months_between(date_to, date_from)) as months ,round(mod(months_between(date_to, date_from),1)*30) as days
from dates
MONTHS_BETWEEN(DATE_TO,DATE_FROM) MONTHS DAYS
3.06451612903225806451612903225806451613 3 2

Related

Return the number of months between now and datetime value SQL

I apologize, I am new at SQL. I am using BigQuery. I have a field called "last_engaged_date", this field is a datetime value (2021-12-12 00:00:00 UTC). I am trying to perform a count on the number of records that were "engaged" 12 months ago, 18 months ago, and 24 months ago based on this field. At first, to make it simple for myself, I was just trying to get a count of the number of records per year, something like:
Select count(id), year(last_engaged_date) as last_engaged_year
from xyz
group by last_engaged_year
order by last_engaged_year asc
I know that there are a lot of things wrong with this query but primarily, BQ says that "Year" is not a valid function? Either way, What I really need is something like:
Date() - last_engaged_date = int(# of months)
count if <= 12 months as "12_months_count" (# of records where now - last engaged date is less than or equal to 12 months)
count if <= 18 months as "18_months_count"
count if <= 24 months as "24_months_count"
So that I have a count of how many records for each last_engaged_date period there are.
I hope this makes sense. Thank you so much for any ideas
[How to] Return the number of months between now and datetime value [in BigQuery] SQL
The simples way is just to use DATE_DIFF function as in below example
date_diff(current_date(), date(last_engaged_date), month)

Why is Redshift datediff giving different weeks when it is the same number of day difference?

I'm trying to find the number of weeks between two days. When the difference is 8 days, I should be getting 1 or 2 weeks, depending on how the function works in Redshift (rounds up or down). However, it should be consistent whichever way it chooses.
I realize that I could simply take the number of days and then divide by 7 and do either a ROUND or a CEIL, but I am simply trying to understand why DATEDIFF(weeks, date1, date2) provides either 1 or 2 when I have the two dates different by 8 days.
SELECT
DATEDIFF(weeks, '2019-03-17', '2019-03-25') AS week_difference1,
DATEDIFF(days, '2019-03-17', '2019-03-25') AS day_difference1,
DATEDIFF(weeks, '2019-03-16', '2019-03-24') AS week_difference2,
DATEDIFF(days, '2019-03-16', '2019-03-24') AS day_difference2
Result:
week_difference1 = 1
day_difference1 = 8
week_difference2 = 2
day_difference2 = 8
As with many software products from the US, the first day of the week in Redshift (at least far as DATEDIFF is concerned) is Sunday, and not the ISO standard of Monday. Therefore when calculating the number of weeks between two dates the boundary is Saturday/Sunday.
In your example, the eight days between the 16th March 2019 and 24th March 2019 crosses two week boundaries (one on 16/17 March and one on 23/24 March), so the resulting DATEDIFF value is 2 (two week boundaries crossed).
However, the eight days between the 17th March and 25th March only crosses one week boundary (23/24 March) so the resulting DATEDIFF value is 1.

SQLite - Determine average sales made for each day of week

I am trying to produce a query in SQLite where I can determine the average sales made each weekday in the year.
As an example, I'd say like to say
"The average sales for Monday are $400.50 in 2017"
I have a sales table - each row represents a sale you made. You can have multiple sales for the same day. Columns that would be of interest here:
Id, SalesTotal, DayCreated, MonthCreated, YearCreated, CreationDate, PeriodOfTheDay
Day/Month/Year are integers that represent the day/month/year of the week. DateCreated is a unix timestamp that represents the date/time it was created too (and is obviously equal to day/month/year).
PeriodOfTheDay is 0, or 1 (day, or night). You can have multiple records for a given day (typically you can have at most 2 but some people like to add all of their sales in individually, so you could have 5 or more for a day).
Where I am stuck
Because you can have two records on the same day (i.e. a day sales, and a night sales, or multiple of each) I can't just group by day of the week (i.e. group all records by Saturday).
This is because the number of sales you made does not equal the number of days you worked (i.e. I could have worked 10 saturdays, but had 30 sales, so grouping by 'saturday' would produce 30 sales since 30 records exist for saturday (some just happen to share the same day)
Furthermore, if I group by daycreated,monthcreated,yearcreated it works in the sense it produces x rows (where x is the number of days you worked) however that now means I need to return this resultset to the back end and do a row count. I'd rather do this in the query so I can take the sales and divide it by the number of days you worked.
Would anyone be able to assist?
Thanks!
UPDATE
I think I got it - I would love someone to tell me if I'm right:
SELECT COUNT(DISTINCT CAST(( julianday((datetime(CreationDate / 1000, 'unixepoch', 'localtime'))) ) / 7 AS INT))
FROM Sales
WHERE strftime('%w', datetime(CreationDate / 1000, 'unixepoch'), 'localtime') = '6'
AND YearCreated = 2017
This would produce the number for saturday, and then I'd just put this in as an inner query, dividing the sale total by this number of days.
Buddy,
You can group your query by getting the day of week and week number of day created or creation date.
In MSSQL
DATEPART(WEEK,'2017-08-14') // Will give you week 33
DATEPART(WEEKDAY,'2017-08-14') // Will give you day 2
In MYSQL
WEEK('2017-08-14') // Will give you week 33
DAYOFWEEK('2017-08-14') // Will give you day 2
See this figures..
Day of Week
1-Sunday, 2- Monday, 3-Tuesday, 4-Wednesday, 5-Thursday, 6-Saturday
Week Number
1 - 53 Weeks in a year
This will be the key so that you will have a separate Saturday's in every month.
Hope this can help in building your query.

Calculate year from date difference in Oracle

I want to calculate the number of years between two dates.
eg :- Select to_date('30-OCT-2013') - TO_date('30-SEP-2014') FROM DUAL;
This would result to 335 days. I want to show this in years, which will be .97 years.
Simply do this(divide by 365.242199):
Select (to_date('30-SEPT-2014') - TO_date('30-OCT-2013'))/365.242199 FROM DUAL;
1 YEAR = 365.242199 days
OR
Try something like this using MONTHS_BETWEEN:-
select floor(months_between(date '2014-10-10', date '2013-10-10') /12) from dual;
or you may also try this:-
SELECT EXTRACT(YEAR FROM date1) - EXTRACT(YEAR FROM date2) FROM DUAL;
On a side note:-
335/365.242199 = 0.917199603 and not .97
I don't know how you figure that's .97 years. Here's what I get:
SQL> SELECT ( TO_date('30-SEP-2014') - to_date('30-OCT-2013')) /
(ADD_MONTHS(DATE '2013-10-30',12) - DATE '2013-10-30') "Year Fraction"
FROM DUAL;
Year Fraction
-------------
0.91780821917
You're going to have to pick a date to base your year calculation on. This is one way to do it. I chose to make a year be the number of days between 10/30/2013 and 10/30/2014. You could also make it a year between 9/30/2013 and 9/30/2014.
As an aside, if you're only interested in 2 decimal places, 365 is pretty much as good as 366.
UPDATE: Used ADD_MONTHS in calculating the denominator. That way you can use the same date for the entire calculation of the number of days in a year.
None of the methods proposed in the other answers give exactly the same answer, look:
with dates as ( select to_date('2013-10-01', 'YYYY-MM-DD') as date1, to_date('2014-09-01', 'YYYY-MM-DD') as date2 from dual)
select months_between(date2, date1)/12 as years_between, 'months_between(date1, date2)' as method from dates
union
select (date2 - date1)/365.242199, '(date2 - date1) / 365.242199' from dates
union
select extract(year from date2) - extract(year from date1), 'extract(year) from date2 - extract(year from date1)' from dates
union
select (date2 - date1) / (ADD_MONTHS(date1 ,12) - date1), '(nb days between date1 and date2) / (nb days in 1 year starting at date1)' from dates
;
gives
YEARS_BETWEEN METHOD
0.9166666666666666666666666666666666666667 months_between(date1, date2)
0.9171996032145234127231831719422979380321 (date2 - date1) / 365.242199
0.9178082191780821917808219178082191780822 nb days date2-date1 / (nb days in 1 year starting at date1)
1 extract(year) from date2 - extract(year from date1)
Why? Because they are all answering slightly different questions.
MONTHS_BETWEEN gives the number of whole months between the 2 dates, and calculates the fractional part as the remainder in days divided by 31.
dividing by 365.242199 assumes that you want the number of solar years between 00:00 on the first date and 00:00 on the second date, to 9 significant figures.
the third method assumes you want to calculate how many calendar days between the two dates, relative to the number of calendar days in the specific year that started on the first date (so the same number of calendar days will give you a different number of years, depending on whether there's a leap day between date1 and the same date on the following year).
the extract(year) approach assumes you want know the difference in whole numbers between the calendar year of the first date and the calendar year of the second date
It's not possible to answer the question perfectly, without knowing which kind of year we are talking about. Do we mean a solar year, or a calendar year, and if we mean a calendar year, do we we want to calculate by months (as if all months were the same length, which they aren't) or by the actual number of days between those dates and in that specific year?
Indeed, if we're talking about calendar years, it's not possible to calculate a fractional number of years in a consistent way at all, since the concept "calendar year" doesn't correspond to a fixed number of days.
The good news is that (aside from the fourth method) all the approaches give the same answer to the first 2 significant figures, as DCookie said. So you can save worrying about what you mean when you say "year", and instead start to think of other concerns such as performance, portability, readability... which also are quite different between these approaches.
I do think though, that whenever a non-programmer asks for something like "the fractional number of years between two dates," they should be punished by being given a detailed explanation of the different ways to calculate it, and why and how they are different, until they agree that it would be better expressed in number of weeks (which at least have the benefit of containing a fixed number of days).

Determining if a leap day falls between two days with DB2 SQL

I have a table with two dates, "Start_Date" and "End_Date". In DB2 SQL, is there a way to determine if a leap day falls between these two dates?
Thank you!
Sure, you can do this using some date math and the DAYS function, by comparing the number of days between the the start and end date to the number of days between the start date and end date when they've both been shifted by 1 year.
If the number of days between the two dates is the same in both cases, then no leap day has occurred. If the number of days differs, then there has been at least 1 leap day.
This expression will return the number of leap days:
select
( DAYS(end_date + 1 year) - DAYS(start_date + 1 year) ) -
( DAYS(end_date) - DAYS(start_date) )
from
sysibm.sysdummy1
This should work as long as end_date >= start_date.
It's trivial to encapsulate this into a scalar User Defined Function.