Recalculate date difference based on exact dates - postgresql

I have 2 columns in my table firstdate and lastdate
firstdate is for example today (2020-1-22).
lastday is plus 1 years minus 1 day (2021-1-21).
So my insert script is like:
INSERT INTO <table> (firstdate, lastdate)
VALUES (current_date, current_date + interval '1 year -1 day')
Ok, so far so good. Now I want to extrapolate it to use it again.
My question is based on these 2 dates. How can i return the interval back again from these 2 dates?
When I use the Postgres function age, I get the following result: 0 years 11 months 30 days.
I can't use this interval to make the right calculation because interval 0 years 11 months 30 days is not the same as interval 1 years -1 days.
So somehow I need to get back 1 years -1 days

lastdate-firstdate gives you the interval between the dates. You cannot get back the literal string you used to create the original interval.
Best regards,
Bjarni

You can store the interval instead of lastdate then derive the lastdate when needed as column interval_value. So
select firstdate,first_date+interval_value lastdate ...
or if you have version 12, define lastdate as a virtual column. Then just select normally. Either way you have the necessary interval.

Related

PostgreSQL interval subtraction

I've tried to subtract interval from timestamp, but I've got a wrong result in comparison to days via subtracting 2 dates.
E.g.:
select
(now::date - past::date) as days,
(now::date - past::date) / 365.25 as years,
justify_interval(now - past::date) as interval_test
from (
select '2020-09-17 00:00:01'::timestamp as now, '2010-09-17 00:00:01'::timestamp as past
) b;
gives results:
3653 days
10.0013 years
'10 years 1 mon 23 days' interval test
Could anyone help me to understand what is wrong with subtracting?
When I do it vice versa, it's ok:
select
(past::date + 3653)::date,
(past + interval '10 years')::date,
(past + 10*interval '1 year')::date,
(past + 10*12*interval '1 month')::date
from (
select '2020-09-17 00:00:01'::timestamp as now, '2010-09-17 00:00:01'::timestamp as past
) b;
all results give the same date '2020-09-17'
What I do wrong?
I am using PostgreSQL 10.5.
There is nothing wrong with subtracting. It is just that justify_interval doesn't do what you seem to expect. justify_interval uses 30 day months and 24 hour days. So 12 months becomes only 360 and 10 years only 3600 days. Leaving 53 days which is 1 (30 day) month and 23 days.
Edit
The justify_interval documentation on this page refers to justify_days and justify_hours which are directly above it which do mention the use of 30 days months and 24 hour days.
The justify functions do have to make these assumption because the interval type is a general length of time (it has no specific start and end). So the justify functions does not know over which specific months the interval was originally calculated.
The age function however does not take an interval it takes an end and a start so it actually knows which specific months and years are in that period.

How to get total experience in terms of date object

I have a condition here in which I will have total experience in terms of month and year. For example, two drop down will be there for asking total number of experience in month and year. So if I am working from 1 Jan 2012, then I will write total experience as 3 year and 11 months. Now I have to convert this 3 year and 11 months into date format so that I can save this into database
You could use java.util.Calendar:
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MONTH, month);
calendar.add(Calendar.YEAR, year);
Date date = calendar.getTime();
As a word of caution, the day field would be set to today's date. Check the intended behaviour if the current day is outside of the bounds for the target month. For example, setting the month to February when calendar has a day field of 30. It might be wise to set the day to a known, valid value for every month (eg: 1) before setting the month and year.
Use DATE_SUB() function:
Try this:
SELECT DATE_SUB(DATE_SUB(CURRENT_DATE(), INTERVAL 3 YEAR), INTERVAL 11 MONTH);
You can use mysql's date_sub() function or <date> - interval <expression> unit syntax to subtract an interval from a date.
select date_sub(curdate(),interval '3-11' YEAR_MONTH) as start_date
UPDATE:
Following the conversation between the OP and #eggyal, the OP need to replace the period in the incoming data with - and construct an insert statement as follows:
insert into mytable (...,join_date,...) values (...,date_sub(curdate(),interval '3-11' YEAR_MONTH),...)

how would I query 4/1/ of the 72nd birth date year > an input date

I have tried the following:
add_months(to_Date('04/01/ind.birth_dte','MM/DD/YYYY'), 864) >= to_date('&StartDt','MM/DD/YYYY')
Is there a better way to pull April first of the participant's 72nd birth date?
You could use an interval calculation instead, but not sure how you're defining 'better'. Assuming you do want April 1st of the year in which their 72 birthday falls:
trunc(ind.birth_dte, 'YYYY') + interval '72-3' year to month
The trunc() function goes to the first day of their birth year, and the interval adds 72 years and 3 months to that, which will be April 1st.
SQL Fiddle with some sample dates, including a leap day to show that isn't a problem.
Or to compare that adjusted date with a fixed date as a filter:
where trunc(ind.birth_dte, 'YYYY') + interval '72-3' year to month
> to_date('&StartDt','MM/DD/YYYY');
SQL Fiddle.
You can use the trunc() method with your version as well to save building up a string and calling to_date, adding an additional three months to the add_months call (though I'd suggest you at least need a comment indicating where '867' comes from):
where add_months(trunc(ind.birth_dte, 'YYYY'), 867)
> to_date('&StartDt','MM/DD/YYYY');

Calculate date(april) - 10 months (which would be previous year now)

Date(04-04-2013) - 10 month ( must give date which should be 06-04-2012)
I need to get data between previous 10 months to current date i.e. April.
The year will change -1, so getting problem.
I'm not really sure what your question is exactly, but I think you just want to get data from a table between now and 10 months ago. This should do it:
SELECT *
FROM your_table
WHERE your_date BETWEEN (CURRENT DATE - 10 MONTHS) AND (CURRENT DATE)
You don't have to worry about it being a different year, because the date calculation (- 10 MONTHS) will handle all of that.

SQL DateDiff Weeks - Need and alternative

The MS SQL DateDiff function counts the number of boundaries crossed when calculating the difference between two dates.
Unfortunately for me, that's not what I'm after. For instance, 1 June 2012 -> 30 June 2012 crosses 4 boundaries, but covers 5 weeks.
Is there an alternative query that I can run which will give me the number of weeks that a month intersects?
UPDATE
To try and clarify exactly what I'm after:
For any given month I need the number of weeks that intersect with that month.
Also, for the suggestion of just taking the datediff and adding one, that won't work. For instance February 2010 only intersects with 4 weeks. And the DateDiff calls returns 4, meaning that simply adding 1 would leave me the wrong number of weeks.
Beware: Proper Week calculation is generally trickier than you think!
If you use Datepart(week, aDate) you make a lot of assumptions about the concept 'week'.
Does the week start on Sunday or Monday? How do you deal with the transition between week 1 and week 5x. The actual number of weeks in a year is different depending on which week calculation rule you use (first4dayweek, weekOfJan1 etc.)
if you simply want to deal with differences you could use
DATEDIFF('s', firstDateTime, secondDateTime) > (7 * 86400 * numberOfWeeks)
if the first dateTime is at 2011-01-01 15:43:22 then the difference is 5 weeks after 2011-02-05 15:43:22
EDIT: Actually, according to this post: Wrong week number using DATEPART in SQL Server
You can now use Datepart(isoww, aDate) to get ISO 8601 week number. I knew that week was broken but not that there was now a fix. Cool!
THIS WORKS if you are using monday as the first day of the week
set language = british
select datepart(ww, #endofMonthDate) -
datepart(ww, #startofMonthDate) + 1
Datepart is language sensistive. By setting language to british you make monday the first day of the week.
This returns the correct values for feburary 2010 and june 2012! (because of monday as opposed to sunday is the first day of the week).
It also seems to return correct number of weeks for january and december (regardless of year). The isoww parameter uses monday as the first day of the week, but it causes january to sometimes start in week 52/53 and december to sometimes end in week 1 (which would make your select statement more complex)
SET DATEFIRST is important when counting weeks. To check what you have you can use select ##datefirst. ##datefirst=7 means that first day of week is sunday.
set datefirst 7
declare #FromDate datetime = '20100201'
declare #ToDate datetime = '20100228'
select datepart(week, #ToDate) - datepart(week, #FromDate) + 1
Result is 5 because Sunday 28/2 - 2010 is the first day of the fifth week.
If you want to base your week calculations on first day of week is Monday you need to do this instead.
set datefirst 1
declare #FromDate datetime = '20100201'
declare #ToDate datetime = '20100228'
select datepart(week, #ToDate) - datepart(week, #FromDate) + 1
Result is 4.