RR MILLENNIUM equivalent in Postgres - postgresql

Is there a built in function in PostgreSQL 9.5 version to calculate the appropriate century/millenium?
When I use birth_date::TIMESTAMP from a table, sometimes it prefix 19 and sometimes it prefix 20. Below example
Input:
28JUN80
25APR48
Output:
"1980-06-28 00:00:00"
"2048-04-25 00:00:00"
I also have records in the table with birth_date holding values like "07APR1963" which gets computed appropriately as "1963-04-07 00:00:00".
I need use CASE statement when the length is 7 characters, then prefix with 19 millennium and when its 9 characters, just load it as it is.

https://en.wikipedia.org/wiki/Unix_time Unix epoch is
beginning (00:00:00 1 January 1970)
So if you don't specify the century, but just last YY it will be 20th century from 00:00:00 1 January and 21st century before YY equal 70. If you want it to guess the 20th century either append year as you do, or specify CC, eg:
t=> select
to_timestamp('1JAN70', 'ddmonYY')
, to_timestamp('31DEC69', 'ddmonyy')
, to_timestamp('31DEC69 20', 'ddmonyy cc');
to_timestamp | to_timestamp | to_timestamp
------------------------+------------------------+------------------------
1970-01-01 00:00:00+00 | 2069-12-31 00:00:00+00 | 1969-12-31 00:00:00+00
(1 row)
https://www.postgresql.org/docs/current/static/functions-formatting.html
In conversions from string to timestamp or date, the CC (century)
field is ignored if there is a YYY, YYYY or Y,YYY field. If CC is used
with YY or Y then the year is computed as the year in the specified
century. If the century is specified but the year is not, the first
year of the century is assumed.
update
So in your case you should do smth like:
vao=# create table arasu (member_birth_date character(9)); insert into arasu values ('28JUN80'),('25APR48');
CREATE TABLE
INSERT 0 2
vao=# select to_timestamp(member_birth_date||' 20', 'ddmonYY cc') from arasu;
to_timestamp
------------------------
1980-06-28 00:00:00+03
1948-04-25 00:00:00+03
(2 rows)

Related

Return number of days passed in current quarter

How can I get the number of days passed in the current quarter?
For example, if today is 1/2/2021, it will return 2.
If today is 2/5, it will return 36.
If today is 4/2, it will return 2.
Use date_trunc() to get the start of the quarter and subtract dates:
WITH cte(day) AS (
VALUES
(date '2021-01-02')
, (date '2021-02-05')
, (date '2021-04-02')
)
SELECT day
, day - date_trunc('quarter', day)::date + 1 AS days_passed_in_quarter
FROM cte;
day | days_passed_in_quarter
------------+------------------------
2021-01-02 | 2
2021-02-05 | 36
2021-04-02 | 2
+ 1 to fix off-by-one error as you clearly want to include the current day as "passed".
Always use unambiguous ISO 8601 date format (YYYY-MM-DD - 2021-02-05), which is the default in Postgres and always unambiguous, or you depend on the current datestyle setting (and may be in for surprises). Also avoids misunderstandings general communication.
Related:
PostgreSQL: between with datetime

How to convert respectively four column to date formatting at MATLAB?

Excel file(104976x10) includes large data.
A column: Time (unit year)
B column: Year
C column: Day of the year
D column: Hour
E column: Minute
and others including values
I would like to convert column which begins with B column until E column to date format like 'dd/mm/yyyy HH:MM'.
Example for the data:
1998,41655251 1998 152 1 0 12,5 12,0 11,8 11,9 12,0
I would like to do date instead of 2-th, 3-th, 4-th and 5-th columns.
1998,41655251 01/06/1998 01:00 12,5 12,0 11,8 11,9 12,0
or
1998,41655251 01/06/1998 01:00 1998 152 1 0 12,5 12,0 11,8 11,9 12,0
Welcome to SO.
Matlab has two types of date-format:
datetime, introduced in 2014b.
datenum, introcuced in long ago (before 2006b), it is basically a double precision value giving the number of days from January 0, 0000.
I think the best way is to use datetime, and give it the year, month, day, hour and minute values like this:
t=datetime(1998,0,152,1,0,0)
t= '01-May-1998 01:00:00'
As you can see the days automatically overflow into the months. But I end up 1st of may, not 1st of june like in your example.
to change the format:
t.Format='dd/MM/yyyy hh:mm'
t= '01/05/1998 01:00'
to convert it to a string, you can simply use string(t)
This is an example that combines the above functions to read an xlsx file and writes a new one with the updated column.
data=xlsread('test.xlsx');
S = size(data);
t = datetime(data(:,2),0,data(:,3),data(:,4),data(:,5),0);
t.Format='dd/MM/yyyy HH:mm';
data2=num2cell(data(:,1));
data2(:,2)=cellstr(string(t));
data2(:,3:S(2)-3)=num2cell(data(:,6:end));
xlswrite('test2.xlsx',data2);

Subtracting 1 ISO 8601 year from a date in BigQuery

I'm trying to manipulate a date value to go back in time exactly 1 ISO-8601 year.
The following does not work, but best describes what I want to accomplish:
date_add(date '2018-01-03', interval -1 isoyear)
I tried string conversion as an intermediate step, but that doesn't work either:
select parse_date('%G%V%u',safe_cast(safe_cast(format_date('%G%V%u',date '2018-01-03') as int64)-1000 as string))
The error provided for the last one is "Failed to parse input string "2017013"". I don't understand why, this should always resolve to a unique date value.
Is there another way in which I can subtract an ISO year from a date?
This gives the corresponding day of the previous ISO year by subtracting the appropriate number of weeks from the date. I based the calculation on the description of weeks per year from the Wikipedia page:
CREATE TEMP FUNCTION IsLongYear(d DATE) AS (
-- Year starting on Thursday
EXTRACT(DAYOFWEEK FROM DATE_TRUNC(d, YEAR)) = 5 OR
-- Leap year starting on Wednesday
(EXTRACT(DAY FROM DATE_ADD(DATE(EXTRACT(YEAR FROM d), 2, 28), INTERVAL 1 DAY)) = 29
AND EXTRACT(DAYOFWEEK FROM DATE_TRUNC(d, YEAR)) = 4)
);
CREATE TEMP FUNCTION PreviousIsoYear(d DATE) AS (
DATE_SUB(d, INTERVAL IF(IsLongYear(d), 53, 52) WEEK)
);
SELECT PreviousIsoYear('2018-01-03');
This returns 2017-01-04, which is the third day of the 2017 ISO year. 2018-01-03 is the third day of the 2018 ISO year.

Producing date from year and month values in PostgreSQL

Hello I'm having two problems with converting a concatenated date value into an actual date.
I've tired looking here to convert the concatenated value with to_char(DATE ...) but I keep getting odd dates. I think it is because my month does not have a zero padding in front of it.
This is my base query:
SELECT
expiry_month,
expiry_year,
to_date(CONCAT(expiry_year, expiry_month), 'YYYY/MM'),
FROM thisTable
Here is an example of the data output:
expiry_month expiry_year concatvalues
9 2018 20189-01-01
1 2019 20191-01-01
5 2016 20165-01-01
3 2019 20193-01-01
10 2017 201710-01-01
2 2020 20202-01-01
I think I need to LPAD() my month value to get the correct date parsed. E.g. 01 not 1, and 05 not 5.
However when I try to LPAD the month values it does not work. I've tried:
lpad(to_char(expiry_month),2,'0'),
I get this error 'HINT: No function matches the given name and argument types. You might need to add explicit type casts.'
Which I don't understand because lpad is a function. Any suggestion on how to use LPAD()?
Thank you for the advice.
EDIT 1
I've tried to update the to_date() function with this code:
to_date(CONCAT(payment_cards.expiry_year || ' - ' || payment_cards.expiry_month || ' - 01'), 'YYYY-MM-01') and now it is throwing a different error:
ERROR: invalid value "- " for "MM" DETAIL: Value must be an integer.
I'm still thinking I need to pad the month date?
There's a '/' missing:
SELECT
expiry_month,
expiry_year,
to_date(CONCAT(expiry_year, '/', expiry_month), 'YYYY/MM') AS the_start_of_year_month
FROM thisTable ;
will produce:
expiry_month | expiry_year | the_start_of_year_month
-----------: | ----------: | :----------------------
9 | 2018 | 2018-09-01
1 | 2019 | 2019-01-01
5 | 2016 | 2016-05-01
3 | 2019 | 2019-03-01
10 | 2017 | 2017-10-01
2 | 2020 | 2020-02-01
The date format is specifying '/' and it wasn't there, so, the whole text was taken as the year, and the month and day were taken as 1/1. CONCAT('2018','9') was just returning '20189' (which is a valid year).
dbfiddle here
Use:
make_date(year int, month int, day int)
like:
make_date(expiry_year, expiry_month, 1)
Postgresql documentation

Convert Period in Year/Quarter format to Date (First Day of Quarter)

I would like to take a string in the format 'YYYYQQ' and parse it into a date. Specifically I would like to parse it into the first date of the quarter. For example I would like to parse '2016Q2' into '2016-04-01'.
Per the Postgres documentation, "Q (quarter) is ignored by to_date and to_timestamp". Well frankly I wish it wasn't ignored :) This means this code will return a result I don't want:
select to_date('2014q3', 'YYYY\qQ');
**result**
2014-01-01
**desired result**
2014-07-01
How could I parse this string to the proper date?
Use string manipulation functions format(), left() and right():
with quarters(q) as (
values ('2014q1'), ('2015q2'), ('2016q3'), ('2017q4')
)
select format('%s-%s-1', left(q, 4), right(q, 1)::int* 3- 2)::date
from quarters;
format
------------
2014-01-01
2015-04-01
2016-07-01
2017-10-01
(4 rows)
Create a function for convenience:
create or replace function quarter_to_date(text)
returns date language sql as $$
select format('%s-%s-1', left($1, 4), right($1, 1)::int* 3- 2)::date
$$;
with quarters(q) as (
values ('2014q1'), ('2015q2'), ('2016q3'), ('2017q4')
)
select quarter_to_date(q)
from quarters;
quarter_to_date
-----------------
2014-01-01
2015-04-01
2016-07-01
2017-10-01
(4 rows)
In PostgreSQL 9.4 and greater there is a function that will create a date.
make_date(year, month, day)
You can use it as follows:
make_date(year, quarter * 3 -2 , 1)::date