pg: Add date type & httpdate tests

...I was hoping not to have to implement the date type, because date
conversions suck, but it turns out manned.org actually needs it.
(Only to then convert it into a Unix timestamp again, hmm, maybe this
string conversion isn't useful at all?)
This commit is contained in:
Yorhel 2025-02-24 11:51:43 +01:00
parent 8595c4ba64
commit fbbaa23842
4 changed files with 56 additions and 2 deletions

View file

@ -570,6 +570,11 @@ represent that without loss for dates that are near enough to the epoch (still
seems to be fine in 2025, at least), but this conversion may be lossy for dates
far beyond or before the epoch.
=item date
Converted between strings in C<YYYY-MM-DD> format. Postgres accepts a bunch of
alternative date formats, this module does not.
=item json / jsonb
These types are converted through C<json_parse()> and C<json_format()> from
@ -599,7 +604,7 @@ These are converted to and from hashrefs.
=item money
=item date / time / timetz
=item time / timetz
=item bit / varbit

View file

@ -511,6 +511,34 @@ SENDFN(timestamp) {
fustr_writebeI(64, out, ts);
}
RECVFN(date) {
RLEN(4);
time_t ts = ((time_t)fu_frombeI(32, buf)) * 86400 + UNIX_PG_EPOCH;
struct tm tm;
gmtime_r(&ts, &tm);
return newSVpvf("%04d-%02d-%02d", tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday);
}
SENDFN(date) {
int year, month, day;
if (sscanf(SvPV_nolen(val), "%4d-%2d-%2d", &year, &month, &day) != 3) SERR("invalid date format");
/* Can't use mktime() hackery here because libc has no UTC variant. Code
* below is adapted from PostgreSQL date2j() instead. */
if (month > 2) {
month += 1;
year += 4800;
} else {
month += 13;
year += 4799;
}
int century = year / 100;
int v = year * 365 - 32167;
v += year / 4 - century + century / 4;
v += 7834 * month / 256 + day;
v -= 2451545; /* Julian -> Postgres */
fustr_writebeI(32, out, v);
}
#undef UNIX_PG_EPOCH
#undef SIV
@ -615,7 +643,7 @@ SENDFN(timestamp) {
A( 1041, "_inet", 869 )\
B( 1042, "bpchar", text )\
B( 1043, "varchar", text )\
/* 1082 date */\
B( 1082, "date", date )\
/* 1083 time */\
B( 1114, "timestamp", timestamp)\
A( 1115, "_timestamp", 1114 )\

13
t/httpdate.t Normal file
View file

@ -0,0 +1,13 @@
use v5.38;
use Test::More;
use FU::Util 'httpdate_format', 'httpdate_parse';
is httpdate_format(0), 'Thu, 01 Jan 1970 00:00:00 GMT';
is httpdate_format(1740325942), 'Sun, 23 Feb 2025 15:52:22 GMT';
is httpdate_parse('Thu, 01 Jan 1970 00:00:00 GMT'), 0;
is httpdate_parse('Sun, 23 Feb 2025 15:52:22 GMT'), 1740325942;
is httpdate_parse('Sub, 23 Feb 2025 15:52:22 GMT'), undef;
is httpdate_parse('Sun, 3 Feb 2025 15:52:22 GMT'), undef;
done_testing;

View file

@ -115,6 +115,14 @@ v timestamptz => 1740133814.705915, undef, '2025-02-21 10:30:14.705915+00';
v timestamp => 0, undef, '1970-01-01 00:00:00';
v timestamp => 1740133814.705915, undef, '2025-02-21 10:30:14.705915';
v date => '1970-01-01';
v date => '1999-01-08';
v date => '2025-02-24';
f date => '';
f date => '2025-';
f date => '2025-02-';
f date => '1999-Jan-08';
v 'int[]', [], undef, '{}';
v 'int[]', [1], undef, '{1}';
v 'int[]', [1,-3,undef,3], undef, '{1,-3,NULL,3}';