Cast string 'May 11 2022 9:16AM' to a timestamp - postgresql

I have this query:
select to_timestamp('May 11 2022 9:16AM', 'Month DD YYYY HH:MI')
Returns: 2022-05-11 09:16:00.000 -0300
The expression 'Month DD YYYY HH:MI' is the result of some trial and error.
I can't tell if what I have is 'right'? Expected something more like: 2022-05-11 09:16:00
What is ...00.000 -0300 this part?
How can I get a timestamp from May 11 2022 9:16AM?

Per the docs Data Type Formatting Functions to_timestamp:
to_timestamp ( text, text ) → timestamp with time zone
Converts string to time stamp according to the given format. (See also to_timestamp(double precision) in Table 9.32.)
to_timestamp('05 Dec 2000', 'DD Mon YYYY') → 2000-12-05 00:00:00-05
So what you are seeing is a timestamptz value, e.g a timestamp with time zone information. If you want to eliminate the time zone then:
select to_timestamp('May 11 2022 9:16AM', 'Month DD YYYY HH:MI')::timestamp;
to_timestamp
---------------------
2022-05-11 09:16:00

Related

Postgresql extracting 'epoch' from timestamp cuts off last date in date range

My table has the column event_ts with column type numeric.
Here is my query:
select
min(to_timestamp(event_ts)), max(to_timestamp(event_ts))
from
table1
where
event_ts >= extract('epoch' from '2021-07-01'::timestamp) and
event_ts <= extract('epoch' from '2021-07-31'::timestamp)
However, the results are
min: 2021-06-30 20:00:00.000 -0400
max: 2021-07-30 20:00:00.000 -0400
I would think the where clause would include data from 2021-07-01 to 2021-07-31.
There is data for July 31st, 2021.
Why does this query start at 2021-06-30 and end 2021-07-30?
show timezone;
TimeZone
------------
US/Pacific
select extract('epoch' from '2021-07-01'::timestamp);
extract
-------------------
1625097600.000000
select to_timestamp(1625097600);;
to_timestamp
-------------------------
06/30/2021 17:00:00 PDT
select extract('epoch' from '2021-07-01'::timestamptz);
extract
-------------------
1625122800.000000
(1 row)
test(5432)=# select to_timestamp(1625122800);
to_timestamp
-------------------------
07/01/2021 00:00:00 PDT
So by using timestamp you are creating a local time offset by the timezone offset. Using timestamptz will return a timestamp at 0:00:00.
This is because from here:
https://www.postgresql.org/docs/current/functions-datetime.html#FUNCTIONS-DATETIME-EXTRACT
epoch
For timestamp with time zone values, the number of seconds since 1970-01-01 00:00:00 UTC (negative for timestamps before that); for date and timestamp values, the nominal number of seconds since 1970-01-01 00:00:00, without regard to timezone or daylight-savings rules; for interval values, the total number of seconds in the interval
Epoch is based on UTC timezone.
Not sure why you are using epoch anyway?
Why not?:
...
where
event_ts between '2021-07-01'::timestamptz and '2021-07-31'::timestamptz

how to get hour, month from timestamp in postgresql

timestamp with timezone is this - 2020-05-31T10:05:07Z
this is not working, despite referencing official documentation. I need to extract may 2020 or separate month and year to compare against May 2020
SELECT date_trunc('hour', TIMESTAMP '2020-05-31T10:05:07Z')
SELECT date_part('day', TIMESTAMP '2020-05-31T10:05:07Z');
If you want to check if a timestamp value is "may 2020", you have different options.
to_char(the_value, 'yyyy-mm') = '2020-05'
or
extract(month from the_value) = 5
and extract(year from the_value) = 2020
or
(extract(month from the_value), extract(year from the_value)) = (5, 2020)
extract() and date_part() are the same thing - but I prefer the standard compliant extract() version.
demo:db<>fiddle
You need to_char() to format a date or timestamp. Mon gives you the first three letters of a month name:
SELECT
to_char(
TIMESTAMP '2020-05-31T10:05:07Z',
'Mon YYYY'
)
Returning the entire month name you can use Month instead of Mon. But, for some reasons, the length of the Month value is fixed to the longest month name available. That means May is returned with right padded spaces. To avoid this, you need to add the modifier FM:
SELECT
to_char(
TIMESTAMP '2020-05-31T10:05:07Z',
'FMMonth YYYY'
)

convert values from two columns into one new column

I have two columns: year and month:
Year Month
2017 01
2017 02
2018 12
2019 06
2020 07
With
select to_date(concat(Year, Month), 'YYYYMM') csv_date FROM my_table;
I can get just one column with date datatype.
How can I add this column in my table, to get this:
Year Month csv_date
2017 01 2017-01-00
2017 02 2017-02-00
2018 12 2018-12-00
2019 06 2019-06-00
2020 07 2020-07-00
You can not have a column defined as date that contains 00 for the day. That would be an invalid date, and Postgres will not allow it. The suggested method of concatenating the 2 works if the year and month are defined as a string type column, but the result will have '01' for the day. If those columns are defined as numeric then you can use the make date function.
with my_table(tyr, tmo, nyr,nmo) as
( values ('2020', '04', 2020, 04 ) )
select to_date(concat(tyr, tmo), 'YYYYMM') txt_date
, make_date(nyr,nmo,01) num_date
from my_table;
With that said then use the to_char function for a date column you can to get just year and month (and if you must) add the '-00'. so
with my_table (adate) as
( values ( date '2020-04-01') )
select adate, to_char(adate,'yyyy-mm') || '-00' as yyyymm
from mytable;
If you are on v12 and want to add the column you can add it as a generated column. This will have the advantage that it cannot be updated independently but will automatically update when the source columns(s) get updated. See fiddle complete example;
alter table my_table add column cvs_date date generated always as (make_date(yr, mo,01)) stored;
Using PostgreSQL Query
If you want to add new column then
alter table my_table add column csv_date date;
update my_table set csv_date=to_date(concat(Year, Month), 'YYYYMM');
If you want only select output then:
select year, month, to_date(concat(Year, Month), 'YYYYMM') csv_date FROM my_table;

converting milliseconds to string date dd MMM YYYY and using it in LIKE Clause

I have stored a date in milliseconds in table as follow:
table: person
columns: id,name,dob
want to select person details based on given dob
Eg. SELECT id,name,to_date(dob) as dob FROM person WHERE dob LIKE '10 Jun 1991'
here function to_date() should select the milliseconds and convert to format '10 Jun 1991'
You can convert your timestamp in milliseconds to the desired format with the following if the milliseconds are measured from the UNIX epoch on:
to_char(to_timestamp(dob / 1000.0), 'DD Mon YYYY')
For MySQL
SELECT id, name, FROM_UNIXTIME(dob / 1000) FROM person
https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_from-unixtime
For Postgres:
SELECT id, name, to_timestamp(dob / 1000) FROM person
https://www.postgresql.org/docs/current/static/functions-formatting.html

H2 FORMATDATETIME() unexpecting changing year on 01/01

I'm trying to set the minutes and seconds to 00 in a date, I use formatdatetime(date, 'Y-MM-dd HH:00:00') and it works fine with normal dates, but trying with formatdatetime('2017-01-01 12:27:27', 'Y-MM-dd HH:00:00') the result is 2016-01-01 12:00:00 instead of 2017-01-01 12:00:00.
Why?
Here is some sample code:
CREATE TABLE test_table (
timestamp DATETIME(3) NOT NULL
);
INSERT INTO test_table
VALUES
('2017-01-01 12:27:27'),
('2017-01-02 12:27:27'),
('2017-01-03 12:27:27');
SELECT FORMATDATETIME(timestamp, 'Y-MM-dd HH:00:00')
FROM test_table;
Result is:
FORMATDATETIME(TIMESTAMP, 'Y-MM-dd HH:00:00')
2016-01-01 12:00:00
2017-01-02 12:00:00
2017-01-03 12:00:00
Why this behaviour?
I tried with H2 1.4.192/JDK 1.7.0_80 and H2 1.4.195/JRE 1.8.0_74.
Output from SELECT timestamp FROM test_table is normal:
TIMESTAMP ▼
2017-01-01 12:27:27.0
2017-01-02 12:27:27.0
2017-01-03 12:27:27.0
EDIT:
I've found the problem, it seems to be the locale:
Output from SELECT FORMATDATETIME(timestamp, 'Y-MM-dd HH:00:00 z', 'it', 'GMT') FROM test_table:
FORMATDATETIME(TIMESTAMP, 'Y-MM-dd HH:00:00 z', 'it')
2016-01-01 12:00:00 CET
2017-01-02 12:00:00 CET
2017-01-03 12:00:00 CET
Output from SELECT FORMATDATETIME(timestamp, 'Y-MM-dd HH:00:00 z', 'en', 'GMT') FROM test_table:
FORMATDATETIME(TIMESTAMP, 'Y-MM-dd HH:00:00 z', 'en')
2017-01-01 12:00:00 CET
2017-01-02 12:00:00 CET
2017-01-03 12:00:00 CET
With it locale it subtract one year at 01/01/2017, while with en locale it doesn't. Can someone explain me why this occurs? Shouldn't locale change only data rapresentation?
Ok issue solved, it was my misunderstanding on date formatting:
H2 uses, as suggested by hendrik in his comment, Java SimpleDateFormat to format dates. Following SimpleDateFormat formats, 'Y' (uppercase) stands for week year (the year to whom the week belongs).
Now 01/01/2017 was a Sunday. In the Italian locale (used on my machine), Sunday is considered the last day of the week (so the week belongs to the past year, 2016), while in the international standard (and in the en locale too), Sunday is the first day of week, then belonging to 2017.