How to correctly select date field using libpqxx? - c++

I am trying to select date field from PostgreSQL database using libpqxx and C++.
I would use this code, but I don't know if it is legal. I have searched in the documentation but I haven't any documented way.
using time_point = std::chrono::steady_clock::time_point;
pqxx::work txn(c);
auto&& rst = txn.exec("SELECT date FROM table");
for(auto&& row : rst)
time_point date = row[0].as<time_point>();
Is this okey please? Do you know any better alternative?
I would like the same with date time and time field. Is there any difference please?
Thank you.
--
the documentation for field type: https://libpqxx.readthedocs.io/en/6.4/a01063.html#a3a55f6b44040b68e70382d9db7dea457

The answer on Github by JadeMatrix:
field.as<>() will work with any type for which a specialization of pqxx::string_traits<> exists. libpqxx comes with support for std::string, builtin numerics (int, etc.), and maybe a few others I don't remember.
Support for std::chrono:: types are missing by default, unfortunately. You can implement your own, but be warned that they will only work for TIMESTAMP WITHOUT TIME ZONE, DATE, TIME WITHOUT TIME ZONE, and INTERVAL. To correctly support … WITH TIME ZONE you will need Howard Hinnant's date library, which is what I use (there is talk of adding it to the standard library).
If you want, I can share my code, which relies on date functionality for parsing Postgres date/time strings (ISO 8601 format).

Related

Cannot parse UTC date in Athena

I have the date string in the form: 2019-02-18 09:17:31.260000+00:00 and I am trying to convert it into date in Athena.
I have tried converting into timestamp as suggested in the SO answers but failed.
There is a discussion in https://github.com/prestodb/presto/issues/10567 but no answer to this particular date format.
I tried several format like 'YYYY-MM-dd HH:mm:ss.SSSSSSZ' but doesn't work and get error like INVALID_FUNCTION_ARGUMENT: Invalid format:..is malformed at "+00:00".
Been stuck for a while, any help is appreciated!
Athena is based on a very old version of Presto, and there is no straightforwad way of doing that with some string manipulation trick. For instance, you can use regexp_replace to extract the part of the string that's compatible with the built-in timestamp with timezone type and do:
SELECT cast(regexp_replace('2019-02-18 09:17:31.260000+00:00','(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3})\d{3}(.*)', '$1$2') AS timestamp with time zone)
Recent versions of Trino (formerly known as PrestoSQL) introduced support for variable-precision temporal types with up to nanosecond precision (12 decimals).
With that feature, you can just do:
trino> select cast('2019-02-18 09:17:31.260000+00:00' as timestamp(6) with time zone);
_col0
--------------------------------
2019-02-18 09:17:31.260000 UTC
(1 row)
A shorter version to Martin Traverso's answer is to sub string the extra characters:
select cast(substr('2019-02-18 09:17:31.260000+00:00',1,23) as timestamp);

Django and PostgreSQL - how to store time range?

I would like to store a time range (without dates) like "HH:MM-HH:MM".
Can you give me a hint, how can I implement it most easily? Maybe there is a way to use DateRangeField for this aim or something else.
Thanks for your spend time!
Time without date doesn't make much since if you ever need a range that span mid-night (days) You could always convert to text using to_char(<yourtimestamp>,'hh24.mi:ss') or extract the individual parts. Unfortunately Postgres does not provide an extract(time from <yourtimestamp>) function. The following function provides essentially that.
create or replace
function extract_tod(date_time_in timestamp without time zone)
returns time
language sql
as $$
select to_char(date_time_in, 'hh24:mi:ss')::time;
$$;
See here for timestatamp ranges and here for their associated functions. As for how to store then just store with the date
as a standard TIMESTAMP (date + time).

C++ and Sqlite3: How to store date/time with milliseconds precision

I´m building a C++ application that will be running in Ubuntu and will use Sqlite3 as a database.
One of my goals is to have a C++ class containing time/date fields and store then on database.
In the past I´ve used time_t as the variable type on my class and stored them as INTEGER type on Sqlite3, like:
C++ Class:
class MyClass {
time_t dateTimeInfo;
}
Sqlite3:
CREATE TABLE MYCLASS (....., INTEGER DATETIMEINFO, ...);
That approach allows me to SELECT times with different comparasion operatiors (>, >=, < , <=, ==) with no problems at all, as I´m dealing with simple number. At the user level the time_t is converted to ISO 8601 std::string´s so that I can have a human readable interface.
This works very well except that it does not support millisecods. In my current project I need to support them, so I need to make changes to this.
As far I had studies I undestand I need to use std::chrono::time_point as the class type, as follows:
C++ Class:
class MyClass {
std::chrono::time_point dateTimeInfo;
}
But I really don´t know what data type to use in Sqlite3 and if it will work the same way time_t used to...
Sqlite3:
CREATE TABLE MYCLASS (....., ???? DATETIMEINFO, ...);
My questions:
a) Is std::chrono::time_point the correct option here ?
b) What is the Sqlite3 type equivalent ? Still an INTEGER ?
c) Is this the recommended approach (no boost please, C++11) ?
Thanks for helping.
You can store the ISO 8601 string formatted times as TEXT directly. For instance, you can make the following table:
CREATE TABLE tbl(name TEXT, ts TEXT);
and insert ISO 8601 formatted strings with millisecond values as a text string:
INSERT INTO tbl VALUES ('first', '2015-07-06T10:59:46.1234Z');
INSERT INTO tbl VALUES ('second', '2015-07-06T10:59:47.5678Z');
INSERT INTO tbl VALUES ('third', '2015-07-06T10:59:48.9012Z');
At this point you can query them using comparison operators:
SELECT * FROM tbl WHERE ts <= '2015-07-06T10:59:46.1233Z';
// Returns nothing
SELECT * FROM tbl WHERE ts <= '2015-07-06T10:59:46.1234Z';
// Returns the first record
SELECT * FROM tbl WHERE ts > '2015-07-06T10:59:46.1234Z';
// Returns the last two records
As an added bonus, you get ISO 8601 formats on the way out when you interface with this database, which is what you're doing on the client side anyway.
This method makes use of the fact that within a timezone, the lexicographic ordering of the strings produces a semantically correct ordering of datetimes. If your usage scenario involves multiple timezones, using a single timezone, such as UTC time, for storage within the database helps preserve this ordering property.
Yes, std::chrono is a very good approach (C++ internally). You can convert time points from/to milliseconds using std::chrono like this:
using namespace std::chrono;
typedef time_point<system_clock, milliseconds> time_points_millis;
time_points_millis tp = system_clock::now();
// An at least 43 bit signed integral type
auto epoch = tp.time_since_epoch();
In this case you should use an 64-bit integral type to store it with SQLite because the data can exceed 32 bits.
Comment: I don't really know much about SQLite, yet, but I found this for 64-bit types: official docs.

Library to discover dates from text?

I need to pull a date out of a string. Since not everyone uses the official ISO format when printing their dates, it is impractical to write a date parser for every possible date format that could be used, and I need to handle as many date formats as possible - I don't control the data and can't expect it to come in a specific format.
This seems like a problem that has probably already been solved ages ago, but my Google-fu is too weak to find the solution. :(
Does there already exist a C++ library that, given a string, will return the month, day, year, hour, minute, second, etc that is referenced in that string, if any?
Pseudocode:
string s1 = "There is an expected meteor shower this Thursday,"
"August 15th 2013 at 4:39 AM.";
string s2 = "20130815T04:39:00";
date d1 = magicConverter(s1);
date d2 = magicConverter(s2);
assert(d1 == d2);
You might use the code from here, but you need to configure a mask, that tells the code which time format is used. If you write a class routine, that takes a mask and a string and gets you out the time and is able to print in any format you like, you should be well prepared. You have to look in more detail, if it also supports Daynames and Monthnames. I got it to work in python with a module providing a function that seems pretty much the same.
For more detail:
Please look at the example 2013-08-03 again. Nobody and as follows no computer is able to tell you if this date belongs to August or April, except of having a mask telling JJJJ-MM-DD or JJJJ-DD-MM. Also this library may tell you only standard masked times. So it might lead you to August in this case. But as you said it can be any date declaration, thus it does not need to follow standards, thus it can also mean March. An other possibility is to tell you about the date from the context (e.g. a table with a column of all te same time formats by looking for the increase (which would also fail if you just look at one day per month for just one year).
Another example... if I ask you 2013-05-04... to which month does it belong? You might tell me... April. I would reply "no, to the 4th of May" and vice versa for May and 5th of April. If you tell me how to solve this puzzle with two possible solutions I would understand your downvote... please think before downvoting someone trying to help you.

How do I force boost::posix_time to recognize timezones?

I'm reading timestamp fields from a PostgreSQL database. The timestamp column is defined as:
my_timestamp TIMESTAMP WITH TIME ZONE DEFAULT NOW()
When reading from the database, I convert it to a boost timestamp like this:
boost::posix_time::ptime pt( boost::posix_time::time_from_string( str ) );
The problem seems to be that boost::posix_time::time_from_string() ignores the timezone.
For example:
database text string == "2013-05-30 00:27:04.8299-07" // note -07 timezone
boost::posix_time::to_iso_extended_string(pt) == "2013-05-30T00:27:04.829900"
When I do arithmetic with the resulting ptime object, the time is off by exactly 7 hours. Is there something better I should be doing to not lose the timezone information?
I think you should be using boost::local_date_time, which handles time zones. There is an example in the documentation that is very similar to what you're trying to do: http://www.boost.org/doc/libs/1_41_0/doc/html/date_time/examples.html#date_time.examples.seconds_since_epoch
EDIT: Boost supports date parsing with specific formats. http://www.boost.org/doc/libs/1_40_0/doc/html/date_time/date_time_io.html#date_time.format_flags
string inp("2013-05-30 00:27:04.8299-07");
string format("%Y-%m-%d %H:%M:%S%F%Q");
date d;
d = parser.parse_date(inp,
format,
svp);
// d == 2013-05-30 00:27:04.8299-07
I originally asked this question so many years ago, I don't even remember doing it. But since then, all my database date/time code on the client side has been greatly simplified. The trick is to tell PostgreSQL the local time zone when the DB connection is first established, and let the server automatically add or remove the necessary hours/minutes when it sends back timestamps. This way, timestamps are always in local time.
You do that with a 1-time call similar to this one:
SET SESSION TIME ZONE 'Europe/Berlin';
You can also use one of the many timezone abbreviations. For example, these two lines are equivalent:
SET SESSION TIME ZONE 'Asia/Hong_Kong';
SET SESSION TIME ZONE 'HKT';
The full list of timezones can be obtained with this:
SELECT * FROM pg_timezone_names ORDER BY name;
Note: there are over 1000 timezone names to pick from!
I have more details on PostgreSQL and timezones available on this post: https://www.ccoderun.ca/programming/2017-09-14_PostgreSQL_timestamps/index.html