0

I need to convert number to timestamp in PostgreSQL. I got numbers in database as character varying. I have seen there is a lot of solutions for integers but I got decimal numbers and here comes the issue.

The max I got is something like below using '1899-12-30'::DATE + CAST(Round(CAST(REPLACE(Excel_date_number, ',','.') as DOUBLE PRECISION)) as INTEGER)

Value Date
45279,4029282407 2023-12-19
45294,5203472222 2024-01-04
45309,2083333333 2024-01-18

But I am completely lost in getting thw whole timestamp from these numbers. Can you give me any ideas how could I handle this?

4
  • Is Value supposed to be part of the timestamp. If so what is it, an epoch value or something else? FYI, you can deal with the , as decimal separator by changing lc_numeric to a locale that uses a , that way. Commented Feb 19, 2024 at 16:18
  • Value is Excel serial number date. It represents number of the days from 1899-12-30 to today. So 0.4029282407 is around 9:40 as it has to be multiplied by 24 to get what hours it is. So the value contains all the information that is needed to get whole timestamp.
    – Tyraf
    Commented Feb 19, 2024 at 16:32
  • 1
    This would be a lot easier if you had export the formatted string for the datetime instead of underlying value. Commented Feb 19, 2024 at 16:49
  • You are casting your converted value to an INTEGER ... so that is why you lose your time portion of the timestamp.
    – topsail
    Commented Feb 19, 2024 at 16:51

2 Answers 2

1

Assuming you have the proper locale installed on your computer:

set lc_numeric = 'de_DE.utf8';

WITH ts_number AS (
    SELECT
        to_number('45279,4029282407', '99999D9999999999') AS value
)
SELECT
    ('1899-12-30'::date + ((trunc(value)::text || 'days')::interval))
+ (((value - trunc(value)) * 24)::text || 'hours')::interval
FROM
    ts_number;

 ?column?          
----------------------------
 2023-12-19 09:40:12.999996

If you where to go this route I would suggest putting the above logic in a function and use that. It would make your queries a lot cleaner. The simpler solution per my comment would be to export the formatted datetime string from Excel not the underlying value. Lastly the above does not take into account timezone and just assumes you are working in the same timezone as that of Excel.

1
  • This is exactly what I needed. Thank you very much for your help. I had to use time zone as well and now I got correct timestamps... almost. Almost cause I had to add +0.000001 to hours to get proper timestamp. Anyway it helped me a lot, thank you.
    – Tyraf
    Commented Feb 22, 2024 at 14:04
0

As suggested, the case is generic enough to be worth a function. Here are my 5 cents, basically the same as above.

create or replace function xlts_to_ts(xlts text)
returns timestamp language sql immutable as 
$$
with t(v) as (select replace(xlts,',','.')::numeric)
select date '1899-12-30' + 
       v::integer * interval '1 day' +
       v % 1 * 24 * interval '1 hour'
from t
$$;

Please note that Windows regional settings affect the way that numbers are presented by Excel. The decimal symbol may be a dot or a comma. There may be even a "thousands separator" (bookkeepers love it) which too can be a comma or a dot. So - as @AdrianKlaver noted in his answer - whenever possible explicitly "export the formatted datetime string from Excel not the underlying value". The above function will work if no "thousands separator" is set.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.