How to get month first date and end date by given month? - postgresql

Based on Month I want to get start date and end date of that month. But I am getting current month start date and end date.
If I give 9 (month number) as input parameter.
Output should be:
2021-09-01 -- start date
2021-09-30 -- end date.
here my code is:
start_date =(select date_trunc('month', current_date-interval '1 year')::date);
end_date = (select date_trunc('month', current_date-interval '1 year')+'1month'::interval-
'1day'::interval as end_date);
output: 2021-10-01,2021-10-31

You can use make_date to create the first of the month (for the current year), then use + interval '1 month - 1day to find the last day:
start_date := make_date(extract(year from current_date)::int, 9, 1);
end_date := (make_date(extract(year from current_date)::int, 9, 1) + interval '1 month - 1day')::date;

Related

How to group data from 26th of a month to 25th of the next month using postgresql?

I want to define the start of a “month” as the 26th day of the previous calendar month (and of course ending on 25th).
How can I group by this definition of month using date_trunc()?
This expression gives the month you want:
date_trunc(
'month',
date_add(
day,
case
when extract(day from date) > 25 then 7
else 0
end),
my_date_col
)
)
Select it and group by it.
The logic is: If the day of the month is greater than 25, then add some days to bump it into the next month before truncating it to the month.
I would use an INTERVAL to calculate the correct dates. Here an example using generate_series():
SELECT d::date as reference_date
, (d + interval '25 days')::date AS first_day
, (d + interval '1 month' + interval '24 days')::date as last_day
FROM generate_series('2020-01-01'::timestamp, '2021-01-01'::timestamp, '1 month') g(d);

generate series based on particular day in each month -postgresql

i have following query in postgresql for dates between 2 ranges.
select generate_series('2019-04-01'::timestamp, '2020-03-31', '1 month')
as g_date
I need to generate specific date in every month .i.e 15 th of every month. Following is my query to generate series
DO $$
DECLARE
compdate date = '2019-04-15';
BEGIN
CREATE TEMP TABLE tmp_table ON COMMIT DROP AS
select *,
case
when extract('day' from d) <> extract('day' from compdate) then 0
when ( extract('month' from d)::int - extract('month' from compdate)::int ) % 1 = 0 then 1
else 0
end as c
from generate_series('2019-04-01'::timestamp, '2020-03-31', '1 day') d;
END $$;
SELECT * FROM tmp_table
where c=1;
;
But every thing is perfect if input date between (1..29)-04-2019 ..
2019-04-25
2019-05-25
2019-06-25
2019-07-25
2019-08-25
2019-09-25
2019-10-25
2019-11-25
2019-12-25
2020-01-25
2020-02-25
2020-03-25
but if i give compdate: 31-04-2019 or 30-04-2019 giving out put:
2019-05-31
2019-07-31
2019-08-31
2019-10-31
2019-12-31
2020-01-31
2020-03-31
Expected Output:
date flag
2019-04-01 0 ----start_date
2019-04-30 1
2019-05-31 1
2019-06-30 1
2019-07-31 1
2019-08-31 1
2019-09-30 1
2019-10-31 1
2019-11-30 1
2019-12-31 1
2020-01-31 1
2020-02-29 1
2020-03-31 0 ---end_date
If matched day not found in the result it should take last day of that month..i.e if 31 not found in month of feb it
should take 29-02-2019 and also in april month instead of 31 it should take 2019-04-30.
Please suggest.
to generate the last days of the month, just generate first days & subtract a 1 day interval
example: the following generates all last day of month in the year 2010
SELECT x - interval '1 day' FROM
GENERATE_SERIES('2010-02-01', '2011-01-01', interval '1 month') x
You cannot accomplish what you want with generate_series. This results due to that process applying a fixed increment from the previous generated value. Your case 1 month. Now Postgres will successfully compute correct end-of-month date from 1 month to the next. So for example 1month from 31-Jan yields 28-Feb (or 29), because 31-Feb would be an invalid date, Postgres handles it. However, that same interval from 28-Feb gives the valid date 28-Mar so no end-of-month adjustment is needed. Generate_Series will return 28th of the month from then on. The same applies to 30 vs. 31 day months.
But you can achieve what your after with a recursive CTE by employing a varying interval to the same initial start date. If the resulting date is invalid for date the necessary end-of-month adjustment will be made. The following does that:
create or replace function constant_monthly_date
( start_date timestamp
, end_date timestamp
)
returns setof date
language sql strict
as $$
with recursive date_set as
(select start_date ds, start_date sd, end_date ed, 1 cnt
union all
select (sd + cnt*interval '1 month') ds, sd, ed, cnt+1
from date_set
where ds<end_date
)
select ds::date from date_set;
$$;
-- test
select * from constant_monthly_date(date '2020-01-15', date '2020-12-15' );
select * from constant_monthly_date(date '2020-01-31', date '2020-12-31' );
Use the least function to get the least one between the computed day and end of month.
create or replace function test1(day int) returns table (t timestamptz) as $$
select least(date_trunc('day', t) + make_interval(days => day-1), date_trunc('day', t) + interval '1 month' - interval '1 day') from generate_series('2019-04-01', '2020-03-31', interval '1 month') t
$$ language sql;
select test1(31);

date range in postgresql for a given period

I have the following records in a table, as image below. The last period is December / 2019.
I would like to list the periods within a range of 2 years (backwards) from the current date.
For example: today 09/10/2019, list periods from 01/01/2017 to 12/12/2019
I have difficulty assembling the query below.
SELECT c_period_id, name, startdate, enddate
FROM adempiere.C_Period
WHERE startdate BETWEEN now() - INTERVAL '2 year' AND now()
order by startdate desc
I am not quite sure what your problem is, but if it is rounding the dates to the year boundary, this might serve:
WHERE startdate >= date_trunc('year', current_timestamp) - INTERVAL '2 years'
AND startdate < date_trunc('year', current_timestamp) + INTERVAL '1 year'

How to calculate end of the month in Postgres?

How to calculate end of the month in Postgres? I have table with column date datatype. I want to calculate end of the month of every date. For Eg. In the table there values like "2015-07-10 17:52:51","2015-05-30 11:30:19" then end of the month should be like 31 July 2015,31 May 2015.
Please guide me in this.
How about truncating to the beginning of this month, jumping forward one month, then back one day?
=# select (date_trunc('month', now()) + interval '1 month - 1 day')::date;
date
------------
2015-07-31
(1 row)
Change now() to your date variable, which must be a timestamp, per the docs. You can then manipulate this output (with strftime, etc.) to any format you need.
Source
SELECT TO_CHAR(
DATE_TRUNC('month', CURRENT_DATE)
+ INTERVAL '1 month'
- INTERVAL '1 day',
'YYYY-MM-DD HH-MM-SS'
) endOfTheMonth
Hi I tried like this and it worked
Date(to_char(date_trunc('month'::text, msm013.msa011) + '1 mon - 1 day '::interval , 'DD-MON-YYYY') )
Thanks a lot!!

How to get last 24 hrs data in postgreSQL

I want to get last 24 hrs data. i wrote a query in postgreSQL as follows. But I couldn't get the answer as i expected.
SELECT startdate::timestamp AS startdate,
(DATE_PART('hour',startdate::timestamp)::integer) as hrs,count(guorderid)
FROM ord_entitlement
WHERE DATE_PART('Day',CURRENT_DATE::timestamp - startdate::timestamp) < 1
AND DATE_PART('hour',startdate::timestamp) <= 24
GROUP BY hrs,startdate
ORDER BY startdate
Instead of checking date parts, do the time math to get an interval. Use NOW() to get a timestamptz.
SELECT startdate::timestamp AS startdate,
(DATE_PART('hour',startdate::timestamp)::integer) as hrs,
count(guorderid)
FROM ord_entitlement
WHERE NOW() > startdate::timestamptz
AND NOW() - startdate::timestamptz <= interval '24 hours'
GROUP BY hrs,startdate
ORDER BY startdate
This ensures you will get the last 24 hours no matter what your time zone or daylight savings says. NOW() > startdate::timestamptz ensures you don't accidentally pick up things from the future.
If you use CURRENT_DATE you will not get the time instead use now() function. Try the following,
SELECT startdate::timestamp AS startdate,
(DATE_PART('hour',startdate::timestamp)::integer) as hrs,count(guorderid)
FROM ord_entitlement
WHERE DATE_PART('Day',now() - startdate::timestamptz) < 1
GROUP BY hrs,startdate
ORDER BY startdate
date_part() works like extract(), i.e. they will extract a subfield from the source:
-- they will both yield 9 as result
select date_part('day', date '2015-01-09') "day part of 2015-01-09",
date_part('day', date '2015-02-09') "day part of 2015-02-09";
Extracting day(s) therefore is not suited to select the last 24 hours. Similarly extracting hour(s) will (almost) always yield less than or equal to 24.
Extraction day(s) from interval (that's the result of substracting 2 timestamps) is a little different. The result might depend on, whether the interval is justified, or not:
-- they will both yield 1 as result
select date_part('day', interval '1 day') "day part of 1 day",
date_part('day', interval '1 month 1 day') "day part of 1 month 1 day";
-- they will yield 1, 32 and 397 respectively
select date_part('day', timestamp '2015-02-09' - timestamp '2015-02-08') "interval 1",
date_part('day', timestamp '2015-02-09' - timestamp '2015-01-08') "interval 2",
date_part('day', timestamp '2015-02-09' - timestamp '2014-01-08') "interval 3";
Depending on the fact, that the timestamp subtraction is not giving justified intervals is not the best option, I think. You could use simpler conditions to achieve your goal:
-- if startdate is a timestamp:
where current_timestamp - interval '1 day' <= startdate
-- if startdate is a date:
where current_date - 1 <= startdate
If you want to disallow future dates too (as your question's title suggests), you could use a single between condition:
-- if startdate is a timestamp:
where startdate between current_timestamp - interval '1 day' and current_timestamp
-- if startdate is a date:
where startdate between current_date - 1 and current_date