Skip to content

Commit d589f94

Browse files
committed
Support for FF1-FF6 datetime format patterns
SQL Standard 2016 defines FF1-FF9 format patters for fractions of seconds in jsonpath .datetime() method and CAST (... FORMAT ...) SQL clause. Parsing engine of upcoming .datetime() method will be shared with to_date()/ to_timestamp(). This patch implements FF1-FF6 format patterns for upcoming jsonpath .datetime() method. to_date()/to_timestamp() functions will also get support of this format patterns as positive side effect. FF7-FF9 are not supported due to lack of precision in our internal timestamp representation. Extracted from original patch by Nikita Glukhov, Teodor Sigaev, Oleg Bartunov. Heavily revised by me. Discussion: https://postgr.es/m/fcc6fc6a-b497-f39a-923d-aa34d0c588e8%402ndQuadrant.com Discussion: https://postgr.es/m/CAPpHfdsZgYEra_PeCLGNoXOWYx6iU-S3wF8aX0ObQUcZU%2B4XTw%40mail.gmail.com Author: Nikita Glukhov, Teodor Sigaev, Oleg Bartunov, Alexander Korotkov Reviewed-by: Anastasia Lubennikova, Peter Eisentraut
1 parent d812257 commit d589f94

File tree

10 files changed

+239
-23
lines changed

10 files changed

+239
-23
lines changed

doc/src/sgml/func.sgml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6150,6 +6150,30 @@ SELECT regexp_match('abc01234xyz', '(?:(.*?)(\d+)(.*)){1,1}');
61506150
<entry><literal>US</literal></entry>
61516151
<entry>microsecond (000000-999999)</entry>
61526152
</row>
6153+
<row>
6154+
<entry><literal>FF1</literal></entry>
6155+
<entry>tenth of second (0-9)</entry>
6156+
</row>
6157+
<row>
6158+
<entry><literal>FF2</literal></entry>
6159+
<entry>hundredth of second (00-99)</entry>
6160+
</row>
6161+
<row>
6162+
<entry><literal>FF3</literal></entry>
6163+
<entry>millisecond (000-999)</entry>
6164+
</row>
6165+
<row>
6166+
<entry><literal>FF4</literal></entry>
6167+
<entry>tenth of a millisecond (0000-9999)</entry>
6168+
</row>
6169+
<row>
6170+
<entry><literal>FF5</literal></entry>
6171+
<entry>hundredth of a millisecond (00000-99999)</entry>
6172+
</row>
6173+
<row>
6174+
<entry><literal>FF6</literal></entry>
6175+
<entry>microsecond (000000-999999)</entry>
6176+
</row>
61536177
<row>
61546178
<entry><literal>SSSS</literal></entry>
61556179
<entry>seconds past midnight (0-86399)</entry>

src/backend/utils/adt/formatting.c

Lines changed: 78 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
#endif
8787

8888
#include "catalog/pg_collation.h"
89+
#include "catalog/pg_type.h"
8990
#include "mb/pg_wchar.h"
9091
#include "utils/builtins.h"
9192
#include "utils/date.h"
@@ -434,7 +435,8 @@ typedef struct
434435
clock, /* 12 or 24 hour clock? */
435436
tzsign, /* +1, -1 or 0 if timezone info is absent */
436437
tzh,
437-
tzm;
438+
tzm,
439+
ff; /* fractional precision */
438440
} TmFromChar;
439441

440442
#define ZERO_tmfc(_X) memset(_X, 0, sizeof(TmFromChar))
@@ -594,6 +596,12 @@ typedef enum
594596
DCH_Day,
595597
DCH_Dy,
596598
DCH_D,
599+
DCH_FF1,
600+
DCH_FF2,
601+
DCH_FF3,
602+
DCH_FF4,
603+
DCH_FF5,
604+
DCH_FF6,
597605
DCH_FX, /* global suffix */
598606
DCH_HH24,
599607
DCH_HH12,
@@ -643,6 +651,12 @@ typedef enum
643651
DCH_dd,
644652
DCH_dy,
645653
DCH_d,
654+
DCH_ff1,
655+
DCH_ff2,
656+
DCH_ff3,
657+
DCH_ff4,
658+
DCH_ff5,
659+
DCH_ff6,
646660
DCH_fx,
647661
DCH_hh24,
648662
DCH_hh12,
@@ -743,7 +757,13 @@ static const KeyWord DCH_keywords[] = {
743757
{"Day", 3, DCH_Day, false, FROM_CHAR_DATE_NONE},
744758
{"Dy", 2, DCH_Dy, false, FROM_CHAR_DATE_NONE},
745759
{"D", 1, DCH_D, true, FROM_CHAR_DATE_GREGORIAN},
746-
{"FX", 2, DCH_FX, false, FROM_CHAR_DATE_NONE}, /* F */
760+
{"FF1", 3, DCH_FF1, false, FROM_CHAR_DATE_NONE}, /* F */
761+
{"FF2", 3, DCH_FF2, false, FROM_CHAR_DATE_NONE},
762+
{"FF3", 3, DCH_FF3, false, FROM_CHAR_DATE_NONE},
763+
{"FF4", 3, DCH_FF4, false, FROM_CHAR_DATE_NONE},
764+
{"FF5", 3, DCH_FF5, false, FROM_CHAR_DATE_NONE},
765+
{"FF6", 3, DCH_FF6, false, FROM_CHAR_DATE_NONE},
766+
{"FX", 2, DCH_FX, false, FROM_CHAR_DATE_NONE},
747767
{"HH24", 4, DCH_HH24, true, FROM_CHAR_DATE_NONE}, /* H */
748768
{"HH12", 4, DCH_HH12, true, FROM_CHAR_DATE_NONE},
749769
{"HH", 2, DCH_HH, true, FROM_CHAR_DATE_NONE},
@@ -792,7 +812,13 @@ static const KeyWord DCH_keywords[] = {
792812
{"dd", 2, DCH_DD, true, FROM_CHAR_DATE_GREGORIAN},
793813
{"dy", 2, DCH_dy, false, FROM_CHAR_DATE_NONE},
794814
{"d", 1, DCH_D, true, FROM_CHAR_DATE_GREGORIAN},
795-
{"fx", 2, DCH_FX, false, FROM_CHAR_DATE_NONE}, /* f */
815+
{"ff1", 3, DCH_FF1, false, FROM_CHAR_DATE_NONE}, /* f */
816+
{"ff2", 3, DCH_FF2, false, FROM_CHAR_DATE_NONE},
817+
{"ff3", 3, DCH_FF3, false, FROM_CHAR_DATE_NONE},
818+
{"ff4", 3, DCH_FF4, false, FROM_CHAR_DATE_NONE},
819+
{"ff5", 3, DCH_FF5, false, FROM_CHAR_DATE_NONE},
820+
{"ff6", 3, DCH_FF6, false, FROM_CHAR_DATE_NONE},
821+
{"fx", 2, DCH_FX, false, FROM_CHAR_DATE_NONE},
796822
{"hh24", 4, DCH_HH24, true, FROM_CHAR_DATE_NONE}, /* h */
797823
{"hh12", 4, DCH_HH12, true, FROM_CHAR_DATE_NONE},
798824
{"hh", 2, DCH_HH, true, FROM_CHAR_DATE_NONE},
@@ -893,10 +919,10 @@ static const int DCH_index[KeyWord_INDEX_SIZE] = {
893919
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
894920
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
895921
-1, -1, -1, -1, -1, DCH_A_D, DCH_B_C, DCH_CC, DCH_DAY, -1,
896-
DCH_FX, -1, DCH_HH24, DCH_IDDD, DCH_J, -1, -1, DCH_MI, -1, DCH_OF,
922+
DCH_FF1, -1, DCH_HH24, DCH_IDDD, DCH_J, -1, -1, DCH_MI, -1, DCH_OF,
897923
DCH_P_M, DCH_Q, DCH_RM, DCH_SSSS, DCH_TZH, DCH_US, -1, DCH_WW, -1, DCH_Y_YYY,
898924
-1, -1, -1, -1, -1, -1, -1, DCH_a_d, DCH_b_c, DCH_cc,
899-
DCH_day, -1, DCH_fx, -1, DCH_hh24, DCH_iddd, DCH_j, -1, -1, DCH_mi,
925+
DCH_day, -1, DCH_ff1, -1, DCH_hh24, DCH_iddd, DCH_j, -1, -1, DCH_mi,
900926
-1, -1, DCH_p_m, DCH_q, DCH_rm, DCH_ssss, DCH_tz, DCH_us, -1, DCH_ww,
901927
-1, DCH_y_yyy, -1, -1, -1, -1
902928

@@ -960,7 +986,6 @@ typedef struct NUMProc
960986
*L_currency_symbol;
961987
} NUMProc;
962988

963-
964989
/* ----------
965990
* Functions
966991
* ----------
@@ -993,7 +1018,7 @@ static int from_char_parse_int(int *dest, char **src, FormatNode *node);
9931018
static int seq_search(char *name, const char *const *array, int type, int max, int *len);
9941019
static int from_char_seq_search(int *dest, char **src, const char *const *array, int type, int max, FormatNode *node);
9951020
static void do_to_timestamp(text *date_txt, text *fmt,
996-
struct pg_tm *tm, fsec_t *fsec);
1021+
struct pg_tm *tm, fsec_t *fsec, int *fprec);
9971022
static char *fill_str(char *str, int c, int max);
9981023
static FormatNode *NUM_cache(int len, NUMDesc *Num, text *pars_str, bool *shouldFree);
9991024
static char *int_to_roman(int number);
@@ -2518,18 +2543,32 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
25182543
str_numth(s, s, S_TH_TYPE(n->suffix));
25192544
s += strlen(s);
25202545
break;
2521-
case DCH_MS: /* millisecond */
2522-
sprintf(s, "%03d", (int) (in->fsec / INT64CONST(1000)));
2523-
if (S_THth(n->suffix))
2524-
str_numth(s, s, S_TH_TYPE(n->suffix));
2546+
#define DCH_to_char_fsec(frac_fmt, frac_val) \
2547+
sprintf(s, frac_fmt, (int) (frac_val)); \
2548+
if (S_THth(n->suffix)) \
2549+
str_numth(s, s, S_TH_TYPE(n->suffix)); \
25252550
s += strlen(s);
2551+
case DCH_FF1: /* tenth of second */
2552+
DCH_to_char_fsec("%01d", in->fsec / 100000);
2553+
break;
2554+
case DCH_FF2: /* hundredth of second */
2555+
DCH_to_char_fsec("%02d", in->fsec / 10000);
2556+
break;
2557+
case DCH_FF3:
2558+
case DCH_MS: /* millisecond */
2559+
DCH_to_char_fsec("%03d", in->fsec / 1000);
25262560
break;
2561+
case DCH_FF4: /* tenth of a millisecond */
2562+
DCH_to_char_fsec("%04d", in->fsec / 100);
2563+
break;
2564+
case DCH_FF5: /* hundredth of a millisecond */
2565+
DCH_to_char_fsec("%05d", in->fsec / 10);
2566+
break;
2567+
case DCH_FF6:
25272568
case DCH_US: /* microsecond */
2528-
sprintf(s, "%06d", (int) in->fsec);
2529-
if (S_THth(n->suffix))
2530-
str_numth(s, s, S_TH_TYPE(n->suffix));
2531-
s += strlen(s);
2569+
DCH_to_char_fsec("%06d", in->fsec);
25322570
break;
2571+
#undef DCH_to_char_fsec
25332572
case DCH_SSSS:
25342573
sprintf(s, "%d", tm->tm_hour * SECS_PER_HOUR +
25352574
tm->tm_min * SECS_PER_MINUTE +
@@ -3154,8 +3193,18 @@ DCH_from_char(FormatNode *node, char *in, TmFromChar *out)
31543193

31553194
SKIP_THth(s, n->suffix);
31563195
break;
3196+
case DCH_FF1:
3197+
case DCH_FF2:
3198+
case DCH_FF3:
3199+
case DCH_FF4:
3200+
case DCH_FF5:
3201+
case DCH_FF6:
3202+
out->ff = n->key->id - DCH_FF1 + 1;
3203+
/* fall through */
31573204
case DCH_US: /* microsecond */
3158-
len = from_char_parse_int_len(&out->us, &s, 6, n);
3205+
len = from_char_parse_int_len(&out->us, &s,
3206+
n->key->id == DCH_US ? 6 :
3207+
out->ff, n);
31593208

31603209
out->us *= len == 1 ? 100000 :
31613210
len == 2 ? 10000 :
@@ -3689,8 +3738,9 @@ to_timestamp(PG_FUNCTION_ARGS)
36893738
int tz;
36903739
struct pg_tm tm;
36913740
fsec_t fsec;
3741+
int fprec;
36923742

3693-
do_to_timestamp(date_txt, fmt, &tm, &fsec);
3743+
do_to_timestamp(date_txt, fmt, &tm, &fsec, &fprec);
36943744

36953745
/* Use the specified time zone, if any. */
36963746
if (tm.tm_zone)
@@ -3708,6 +3758,10 @@ to_timestamp(PG_FUNCTION_ARGS)
37083758
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
37093759
errmsg("timestamp out of range")));
37103760

3761+
/* Use the specified fractional precision, if any. */
3762+
if (fprec)
3763+
AdjustTimestampForTypmod(&result, fprec);
3764+
37113765
PG_RETURN_TIMESTAMP(result);
37123766
}
37133767

@@ -3725,7 +3779,7 @@ to_date(PG_FUNCTION_ARGS)
37253779
struct pg_tm tm;
37263780
fsec_t fsec;
37273781

3728-
do_to_timestamp(date_txt, fmt, &tm, &fsec);
3782+
do_to_timestamp(date_txt, fmt, &tm, &fsec, NULL);
37293783

37303784
/* Prevent overflow in Julian-day routines */
37313785
if (!IS_VALID_JULIAN(tm.tm_year, tm.tm_mon, tm.tm_mday))
@@ -3749,8 +3803,8 @@ to_date(PG_FUNCTION_ARGS)
37493803
/*
37503804
* do_to_timestamp: shared code for to_timestamp and to_date
37513805
*
3752-
* Parse the 'date_txt' according to 'fmt', return results as a struct pg_tm
3753-
* and fractional seconds.
3806+
* Parse the 'date_txt' according to 'fmt', return results as a struct pg_tm,
3807+
* fractional seconds, and fractional precision.
37543808
*
37553809
* We parse 'fmt' into a list of FormatNodes, which is then passed to
37563810
* DCH_from_char to populate a TmFromChar with the parsed contents of
@@ -3761,7 +3815,7 @@ to_date(PG_FUNCTION_ARGS)
37613815
*/
37623816
static void
37633817
do_to_timestamp(text *date_txt, text *fmt,
3764-
struct pg_tm *tm, fsec_t *fsec)
3818+
struct pg_tm *tm, fsec_t *fsec, int *fprec)
37653819
{
37663820
FormatNode *format;
37673821
TmFromChar tmfc;
@@ -3817,6 +3871,7 @@ do_to_timestamp(text *date_txt, text *fmt,
38173871
DCH_from_char(format, date_str, &tmfc);
38183872

38193873
pfree(fmt_str);
3874+
38203875
if (!incache)
38213876
pfree(format);
38223877
}
@@ -3998,6 +4053,8 @@ do_to_timestamp(text *date_txt, text *fmt,
39984053
*fsec += tmfc.ms * 1000;
39994054
if (tmfc.us)
40004055
*fsec += tmfc.us;
4056+
if (fprec)
4057+
*fprec = tmfc.ff; /* fractional precision, if specified */
40014058

40024059
/* Range-check date fields according to bit mask computed above */
40034060
if (fmask != 0)

src/backend/utils/adt/timestamp.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@ typedef struct
7070

7171
static TimeOffset time2t(const int hour, const int min, const int sec, const fsec_t fsec);
7272
static Timestamp dt2local(Timestamp dt, int timezone);
73-
static void AdjustTimestampForTypmod(Timestamp *time, int32 typmod);
7473
static void AdjustIntervalForTypmod(Interval *interval, int32 typmod);
7574
static TimestampTz timestamp2timestamptz(Timestamp timestamp);
7675
static Timestamp timestamptz2timestamp(TimestampTz timestamp);
@@ -333,7 +332,7 @@ timestamp_scale(PG_FUNCTION_ARGS)
333332
* AdjustTimestampForTypmod --- round off a timestamp to suit given typmod
334333
* Works for either timestamp or timestamptz.
335334
*/
336-
static void
335+
void
337336
AdjustTimestampForTypmod(Timestamp *time, int32 typmod)
338337
{
339338
static const int64 TimestampScales[MAX_TIMESTAMP_PRECISION + 1] = {

src/include/utils/datetime.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,4 +336,6 @@ extern TimeZoneAbbrevTable *ConvertTimeZoneAbbrevs(struct tzEntry *abbrevs,
336336
int n);
337337
extern void InstallTimeZoneAbbrevs(TimeZoneAbbrevTable *tbl);
338338

339+
extern void AdjustTimestampForTypmod(Timestamp *time, int32 typmod);
340+
339341
#endif /* DATETIME_H */

src/test/regress/expected/horology.out

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2786,6 +2786,85 @@ SELECT to_timestamp('2011-12-18 11:38 20', 'YYYY-MM-DD HH12:MI TZM');
27862786
Sun Dec 18 03:18:00 2011 PST
27872787
(1 row)
27882788

2789+
SELECT i, to_timestamp('2018-11-02 12:34:56', 'YYYY-MM-DD HH24:MI:SS.FF' || i) FROM generate_series(1, 6) i;
2790+
i | to_timestamp
2791+
---+------------------------------
2792+
1 | Fri Nov 02 12:34:56 2018 PDT
2793+
2 | Fri Nov 02 12:34:56 2018 PDT
2794+
3 | Fri Nov 02 12:34:56 2018 PDT
2795+
4 | Fri Nov 02 12:34:56 2018 PDT
2796+
5 | Fri Nov 02 12:34:56 2018 PDT
2797+
6 | Fri Nov 02 12:34:56 2018 PDT
2798+
(6 rows)
2799+
2800+
SELECT i, to_timestamp('2018-11-02 12:34:56.1', 'YYYY-MM-DD HH24:MI:SS.FF' || i) FROM generate_series(1, 6) i;
2801+
i | to_timestamp
2802+
---+--------------------------------
2803+
1 | Fri Nov 02 12:34:56.1 2018 PDT
2804+
2 | Fri Nov 02 12:34:56.1 2018 PDT
2805+
3 | Fri Nov 02 12:34:56.1 2018 PDT
2806+
4 | Fri Nov 02 12:34:56.1 2018 PDT
2807+
5 | Fri Nov 02 12:34:56.1 2018 PDT
2808+
6 | Fri Nov 02 12:34:56.1 2018 PDT
2809+
(6 rows)
2810+
2811+
SELECT i, to_timestamp('2018-11-02 12:34:56.12', 'YYYY-MM-DD HH24:MI:SS.FF' || i) FROM generate_series(1, 6) i;
2812+
i | to_timestamp
2813+
---+---------------------------------
2814+
1 | Fri Nov 02 12:34:56.1 2018 PDT
2815+
2 | Fri Nov 02 12:34:56.12 2018 PDT
2816+
3 | Fri Nov 02 12:34:56.12 2018 PDT
2817+
4 | Fri Nov 02 12:34:56.12 2018 PDT
2818+
5 | Fri Nov 02 12:34:56.12 2018 PDT
2819+
6 | Fri Nov 02 12:34:56.12 2018 PDT
2820+
(6 rows)
2821+
2822+
SELECT i, to_timestamp('2018-11-02 12:34:56.123', 'YYYY-MM-DD HH24:MI:SS.FF' || i) FROM generate_series(1, 6) i;
2823+
i | to_timestamp
2824+
---+----------------------------------
2825+
1 | Fri Nov 02 12:34:56.1 2018 PDT
2826+
2 | Fri Nov 02 12:34:56.12 2018 PDT
2827+
3 | Fri Nov 02 12:34:56.123 2018 PDT
2828+
4 | Fri Nov 02 12:34:56.123 2018 PDT
2829+
5 | Fri Nov 02 12:34:56.123 2018 PDT
2830+
6 | Fri Nov 02 12:34:56.123 2018 PDT
2831+
(6 rows)
2832+
2833+
SELECT i, to_timestamp('2018-11-02 12:34:56.1234', 'YYYY-MM-DD HH24:MI:SS.FF' || i) FROM generate_series(1, 6) i;
2834+
i | to_timestamp
2835+
---+-----------------------------------
2836+
1 | Fri Nov 02 12:34:56.1 2018 PDT
2837+
2 | Fri Nov 02 12:34:56.12 2018 PDT
2838+
3 | Fri Nov 02 12:34:56.123 2018 PDT
2839+
4 | Fri Nov 02 12:34:56.1234 2018 PDT
2840+
5 | Fri Nov 02 12:34:56.1234 2018 PDT
2841+
6 | Fri Nov 02 12:34:56.1234 2018 PDT
2842+
(6 rows)
2843+
2844+
SELECT i, to_timestamp('2018-11-02 12:34:56.12345', 'YYYY-MM-DD HH24:MI:SS.FF' || i) FROM generate_series(1, 6) i;
2845+
i | to_timestamp
2846+
---+------------------------------------
2847+
1 | Fri Nov 02 12:34:56.1 2018 PDT
2848+
2 | Fri Nov 02 12:34:56.12 2018 PDT
2849+
3 | Fri Nov 02 12:34:56.123 2018 PDT
2850+
4 | Fri Nov 02 12:34:56.1235 2018 PDT
2851+
5 | Fri Nov 02 12:34:56.12345 2018 PDT
2852+
6 | Fri Nov 02 12:34:56.12345 2018 PDT
2853+
(6 rows)
2854+
2855+
SELECT i, to_timestamp('2018-11-02 12:34:56.123456', 'YYYY-MM-DD HH24:MI:SS.FF' || i) FROM generate_series(1, 6) i;
2856+
i | to_timestamp
2857+
---+-------------------------------------
2858+
1 | Fri Nov 02 12:34:56.1 2018 PDT
2859+
2 | Fri Nov 02 12:34:56.12 2018 PDT
2860+
3 | Fri Nov 02 12:34:56.123 2018 PDT
2861+
4 | Fri Nov 02 12:34:56.1235 2018 PDT
2862+
5 | Fri Nov 02 12:34:56.12346 2018 PDT
2863+
6 | Fri Nov 02 12:34:56.123456 2018 PDT
2864+
(6 rows)
2865+
2866+
SELECT i, to_timestamp('2018-11-02 12:34:56.123456789', 'YYYY-MM-DD HH24:MI:SS.FF' || i) FROM generate_series(1, 6) i;
2867+
ERROR: date/time field value out of range: "2018-11-02 12:34:56.123456789"
27892868
--
27902869
-- Check handling of multiple spaces in format and/or input
27912870
--

src/test/regress/expected/timestamp.out

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1584,6 +1584,21 @@ SELECT '' AS to_char_11, to_char(d1, 'FMIYYY FMIYY FMIY FMI FMIW FMIDDD FMID')
15841584
| 2001 1 1 1 1 1 1
15851585
(65 rows)
15861586

1587+
SELECT '' AS to_char_12, to_char(d, 'FF1 FF2 FF3 FF4 FF5 FF6 ff1 ff2 ff3 ff4 ff5 ff6 MS US')
1588+
FROM (VALUES
1589+
('2018-11-02 12:34:56'::timestamp),
1590+
('2018-11-02 12:34:56.78'),
1591+
('2018-11-02 12:34:56.78901'),
1592+
('2018-11-02 12:34:56.78901234')
1593+
) d(d);
1594+
to_char_12 | to_char
1595+
------------+--------------------------------------------------------------------
1596+
| 0 00 000 0000 00000 000000 0 00 000 0000 00000 000000 000 000000
1597+
| 7 78 780 7800 78000 780000 7 78 780 7800 78000 780000 780 780000
1598+
| 7 78 789 7890 78901 789010 7 78 789 7890 78901 789010 789 789010
1599+
| 7 78 789 7890 78901 789012 7 78 789 7890 78901 789012 789 789012
1600+
(4 rows)
1601+
15871602
-- timestamp numeric fields constructor
15881603
SELECT make_timestamp(2014,12,28,6,30,45.887);
15891604
make_timestamp

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy