Cannot insert date(Y-m-d H:i:s) in Postgres "timestamp" - postgresql

I am trying to insert data in Postgres with cakephp which includes a date.
The column in my database is a timestamp without timezone and I have a datetime string "Y-m-d H:i:s" (also tried with an int).
Must I cast that value?

You do not have to cast the inserted values as long as the text literal is unambiguous and in accepted format.
Don't mistake a date ('2011-10-21') for a timestamp ('2011-10-21 12:10:23').
This is perfectly legal for a timestamp:
INSERT INTO tbl (timestamp_col)
VALUES ('2011-01-01 0:0:0');
But a date you have to cast, resulting in '2011-01-01 0:0:0' in this case:
INSERT INTO tbl (timestamp_col)
VALUES ('2011-01-01'::timestamp);
ISO 8601 format 'yyyy-mm-dd' for a date and 'yyyy-mm-dd hh:mm:ss' for a timestmap are unambiguous for any locale. Other formats may depend on your locale.

use
'Y-m-d H:i:s'::timestamp
Don't forget single quotes
for example
select '2011-01-01'::timestamp

Related

Save datetime with timezone in Postgres table

I am trying to save datetime with timezone in Postgres but can not find anything usefull.
Input would be like,
2021-03-21T12:24:30Z
2021-03-21T12:24:30PST'
and i am expecting output in the datetime column like,
'2001-02-16 18:38:40+05:30'
'2001-02-16 18:38:40+00'
what would be the datatype in column and what's the way i can save the date time including timezone.
You should use the TIMESTAMPTZ data type for the column - https://www.postgresql.org/docs/9.5/datatype-datetime.html

JSON (S3) to Redshift, can't load in YYYY-MM-DDTHH24:MI:SSZ into timestamptz column

I am having issues loading a json file (date fields) in my S3 bucket into Redshift via the copy command. The three columns that are problematic look like this...
{
...
"date":20201209,
"dateChecked": "2020-12-09T24:00:00Z",
"lastModified": "2020-12-09T24:00:00Z",
...
}
The DDL looks like...
create table table1 (
...,
date date,
dateChecked timestamptz,
lastModified timestamptz,
...
);
and the copy command is ...
COPY {schema}.{table}
FROM 's3://{s3_bucket}/{s3_prefix}'
with credentials
'aws_access_key_id={access_key};aws_secret_access_key={secret_key}'
DATEFORMAT 'YYYYMMDD'
TIMEFORMAT 'YYYY-MM-DDTHH24:MM:SSZ'
JSON 'auto ignorecase';
The way I understood it was that the DATEFORMAT would parse the date column and the TIMEFORMAT would handle the timestamptz columns. I am only getting an error on the timestamptz columns, specifically "Invalid timestamp format or value [YYYY-MM-DDTHH24:MI:SSZ]".
Now I have also tried defining the dateChecked and lastModified columns as dates and using the DATEFORMAT 'YYYY-MM-DD' in the copy statement without the TIMEFORMAT. This works for those two columns but then the "date" column is null.
I've also tried every combination of ACCEPTANYDATE, DATEFORMAT 'auto', TIMEFORMAT 'auto' commands, which returns null for all three columns.
My question is how do I load data with different date/time formats?
Any assistance would be greatly appreciated. Thank you.

Postgres Converting Data Types

I have a column saved as a character data type. This column is what I am going to be using as a date. The column goes "YYYY-MM-DD" in that format.
This is a problem because if I ever need to filter by date, I have to go
select col_1, col_2
from table
where date LIKE '2016-04%;
If I want to search for a date range, this turns into a giant complicated mess.
What is the easiest way to convert this to a "date" data type? I want it to continue to be in YYYY-MM-DD order (no timestamp).
My ultimate goal is to be able to search for dates in a format like this:
select col_1, col_2
from table
where date between 2016-01-01 AND 2016-05-31;
What do you guys recommend? I am terrified I am going to corrupt my date if I use an alter statement to convert my data type. (I have a copy of the data saved and can upload it again, but it will take forever.)
Edit: This is a VERY Large table.
Edit Part 2: I originally stored the data as a varchar data type because my dates were not uploading correctly and I got an error message when I tried to save as a date data type. The every date in this column is in the "YYYY-MM-DD" order. My solution was to save it as varchar to avoid the error message (I couldn't figure out what was wrong. I even got rid of leading and trailing spaces.)
Storing a date as a varchar was the wrong choice to begin with. It's very good that you want to change that.
The first step is to convert the columns using an ALTER TABLE statement:
alter table the_table
ALTER COLUMN col_1 TYPE date using col_1::date,
ALTER COLUMN col_2 TYPE date using col_2::date;
Note that this will fail if you have any value in those columns that cannot be convert to a correct date. If you get that you need to first fix those invalid strings before you can change the data type.
I want it to continue to be in YYYY-MM-DD order
This is a misconception. A DATE (or timestamp) does not have a "format". Once it's stored as a date you can display it in any format you want.
My ultimate goal is to be able to search for dates in a format like this:
2016-01-01 is not a valid date literal, a proper (i.e. correctly typed) date constant can be specified e.g. using date '2016-01-01' (note the single quotes!
So your query becomes:
select col_1, col_2
from table
where col_1 between date '2016-01-01' AND date '2016-05-31';
If you have a lot of queries like that you should consider creating an index on the date columns.
Regarding the date constant format:
Are you telling me that despite having the varchar data types, I can still (as of right now) search between specific dates by just typing the word date and putting single quotes between two dates
No, that's not the case. SQL is a strongly typed language and as such will only compare values of the same type.
Using an ANSI date literal (or e.g. to_date()) results in a type constant (i.e. a value with a specific data type).
The difference between date '2016-01-01' and '2016-01-01' is the same as between42(a number) and'42'` (a string).
If you compare a string with a date, you are comparing apples and oranges and the database will do an implicit data type conversion from one type to the other. This is something that should be avoided at all costs.
If you do not want to change the table, you should use the query sagi provided which explicitly converts the strings to dates and then does the comparison on (real) date values (not strings)
You can use POSTGRES TO_DATE() cast function :
SELECT col_1,col_2
FROM Your_Table
WHERE to_date(date_col,'yyyy-mm-dd') between to_date('2016-05-31','yyyy-mm-dd') and to_date('2016-01-01','yyyy-mm-dd')
What #a_horse said.
Plus, if you can't change the data type for some odd reason, to_date() is a safe option to convert the column on the column, but there is no point to use the same expression for provided constants. So:
SELECT col_1, col_2
FROM tbl
WHERE to_date(date, 'YYYY-DD-MM') BETWEEN date '2016-05-31' AND date '2016-01-01';
Or just use string literals without type. The type date is deferred from the context in this expression. And you don't even need to_date(). Since you are using ISO format already. A plain cast is safe:
WHERE date::date BETWEEN '2016-05-31' AND '2016-01-01';
Be sure to use ISO 8601 format for all date strings, so they are unambiguous and valid with any locale.
You can even have an expression index to support the query. Match the actual expression used in queries:
CREATE INDEX tbl_date_idx ON tbl ((date::date)); -- parentheses required!
But I wouldn't use the basic type name date as identifier to begin with.

DB2 VARCHAR_FORMAT works with a Timestamp but not a Date

I want to convert a Date column to a formatted string in DB2. This SQL works fine:
select varchar_format(current timestamp, 'YYYY-MM')
from sysibm.sysdummy1;
but this SQL gives an error:
select varchar_format(current date, 'YYYY-MM')
from sysibm.sysdummy1;
The error is:
[SQL0171] Argument 1 of function VARCHAR_FORMAT not valid.
In the first SQL, the first arg for VARCHAR_FORMAT is a timestamp, and that works. In the second SQL, the first arg for VARCHAR_FORMAT is a date, and that doesn't work.
The IBM doc implies that there's only this one function, VARCHAR_FORMAT (and its synonym, TO_CHAR).
How am I supposed to convert a DATE (not a TIMESTAMP) to a string? Or, do I have to convert the DATE to a TIMESTAMP first, then use VARCHAR_FORMAT?
I am running DB2 7.1 for i Series.
Update: converting to TIMESTAMP_ISO works. But it's ugly:
select varchar_format(timestamp_iso(current date), 'YYYY-MM')
from sysibm.sysdummy1;
That one works.
The documentation for the VARCHAR_FORMAT function in DB2 for i only mentions TIMESTAMP values, not DATE. Some DB2 platforms will implicitly cast a DATE value to a TIMESTAMP when the statement is calling a TIMESTAMP-only function or when comparing the DATE to a TIMESTAMP, but not all do.

Default timestamp format and fractional seconds

I'm trying to format the timestamps in my Postgres database to a certain format:
YYYY-MM-DD HH24:MI:SS
By doing:
update myTable set tds = to_char(tds, 'YYYY-MM-DD HH24:MI:SS')::timestamp;
I managed to set all the previously stored tds to this format. However, any newly added entry goes back to: YYYY-MM-DD HH24:MI:SS.MS since the default is set to now().
How do I change this so that newly added entries also have the format: YYYY-MM-DD HH24:MI:SS?
There is no format stored in a timestamp type. You can set its default to a timestamp truncated to the second at creation time
create table t (
tds timestamp default date_trunc('second', now())
)
Or alter the table
alter table t
alter column tds
set default date_trunc('second', now());
insert into t values (default);
INSERT 0 1
select * from t;
tds
---------------------
2014-03-11 19:24:11
If you just don't want to show the milliseconds part format the output
select to_char(now(), 'YYYY-MM-DD HH24:MI:SS');
to_char
---------------------
2014-03-11 19:39:40
The types timestamp or timestamptz optionally take a precision modifier p: timestamp(p).
To round to full seconds, set the default to:
now()::timestamp(0)
or:
now()::timestamptz(0)
Standard SQL functions CURRENT_TIMESTAMP (returns timestamptz) or LOCALTIMESTAMP (returns timestamp) allow the same precision modifier:
CURRENT_TIMESTAMP(0)
LOCALTIMESTAMP(0)
That's a bit shorter than calling date_trunc() - which truncates fractional seconds (may be what you really want!)
date_trunc('second', now())
Store timestamps as timestamptz (or timestamp), not as character type.
Finally, to make sure that ...
newly added entries also have the format: YYYY-MM-DD HH24:MI:SS
you could define your column as type timestamptz(0). This covers all values entered into that column, not just the default. But the rounding may introduce timestamps up to half a second in the future. If that can be an issue in any way, rather use date_trunc().
See #Clodoaldo's answer for instructions on to_char() and how to ALTER TABLE.
This related answer for in-depth information on timestamps and time zone handling:
Ignoring time zones altogether in Rails and PostgreSQL