+#include "postgres.h"
+#include "fmgr.h"
+
+#include "utils/timestamp.h"
+#include "utils/uuid.h"
+
+PG_MODULE_MAGIC;
+
+#define UUID_EPOCH_JDATE 2299161 /* == date2j(1582, 10, 15) */
+
+struct pg_uuid_t {
+ unsigned char data[UUID_LEN];
+};
+
+__attribute__((__packed__))
+struct timeuuid_t {
+ uint32_t time_low;
+ uint16_t time_mid;
+ uint16_t time_hi_and_version;
+ uint8_t data[8];
+};
+
+typedef struct timeuuid_t timeuuid_t;
+
+Datum timeuuid_lt(PG_FUNCTION_ARGS);
+Datum timeuuid_gt(PG_FUNCTION_ARGS);
+Datum timeuuid_le(PG_FUNCTION_ARGS);
+Datum timeuuid_ge(PG_FUNCTION_ARGS);
+
+PG_FUNCTION_INFO_V1(timeuuid_lt);
+PG_FUNCTION_INFO_V1(timeuuid_gt);
+PG_FUNCTION_INFO_V1(timeuuid_le);
+PG_FUNCTION_INFO_V1(timeuuid_ge);
+
+Datum timeuuid_cmp(PG_FUNCTION_ARGS);
+PG_FUNCTION_INFO_V1(timeuuid_cmp);
+
+static int timeuuid_internal_cmp(const pg_uuid_t *arg1, const pg_uuid_t *arg2) {
+ int result;
+ if ((result = memcmp(&arg1->data[6], &arg2->data[6], 2)) != 0)
+ return result;
+ if ((result = memcmp(&arg1->data[4], &arg2->data[4], 2)) != 0)
+ return result;
+ if ((result = memcmp(&arg1->data[0], &arg2->data[0], 4)) != 0)
+ return result;
+ return memcmp(&arg1->data[8], &arg2->data[8], 8);
+}
+
+Datum timeuuid_lt(PG_FUNCTION_ARGS) {
+ pg_uuid_t *arg1 = PG_GETARG_UUID_P(0);
+ pg_uuid_t *arg2 = PG_GETARG_UUID_P(1);
+ PG_RETURN_BOOL(timeuuid_internal_cmp(arg1, arg2) < 0);
+}
+
+Datum timeuuid_gt(PG_FUNCTION_ARGS) {
+ pg_uuid_t *arg1 = PG_GETARG_UUID_P(0);
+ pg_uuid_t *arg2 = PG_GETARG_UUID_P(1);
+ PG_RETURN_BOOL(timeuuid_internal_cmp(arg1, arg2) > 0);
+}
+
+Datum timeuuid_le(PG_FUNCTION_ARGS) {
+ pg_uuid_t *arg1 = PG_GETARG_UUID_P(0);
+ pg_uuid_t *arg2 = PG_GETARG_UUID_P(1);
+ PG_RETURN_BOOL(timeuuid_internal_cmp(arg1, arg2) <= 0);
+}
+
+Datum timeuuid_ge(PG_FUNCTION_ARGS) {
+ pg_uuid_t *arg1 = PG_GETARG_UUID_P(0);
+ pg_uuid_t *arg2 = PG_GETARG_UUID_P(1);
+ PG_RETURN_BOOL(timeuuid_internal_cmp(arg1, arg2) >= 0);
+}
+
+Datum timeuuid_cmp(PG_FUNCTION_ARGS) {
+ pg_uuid_t *arg1 = PG_GETARG_UUID_P(0);
+ pg_uuid_t *arg2 = PG_GETARG_UUID_P(1);
+ PG_RETURN_INT32(timeuuid_internal_cmp(arg1, arg2));
+}
+
+#ifdef HAVE_INT64_TIMESTAMP
+Datum timeuuid_to_timestamptz(PG_FUNCTION_ARGS);
+Datum timestamptz_to_timeuuid(PG_FUNCTION_ARGS);
+
+PG_FUNCTION_INFO_V1(timeuuid_to_timestamptz);
+PG_FUNCTION_INFO_V1(timestamptz_to_timeuuid);
+
+static const int64_t uuid_diff = ((int64_t) POSTGRES_EPOCH_JDATE - (int64_t) UUID_EPOCH_JDATE) * SECS_PER_DAY * USECS_PER_SEC;
+
+Datum timeuuid_to_timestamptz(PG_FUNCTION_ARGS) {
+ timeuuid_t *uuid = (timeuuid_t *) PG_GETARG_UUID_P(0);
+ TimestampTz ts = (((uint64_t) ntohs(uuid->time_hi_and_version) & 0xfff) << 48) + ((uint64_t) ntohs(uuid->time_mid) << 32) + (uint64_t) ntohl(uuid->time_low);
+ ts = (int64_t) (ts / 10) - uuid_diff;
+ PG_RETURN_TIMESTAMPTZ(ts);
+}
+
+Datum timestamptz_to_timeuuid(PG_FUNCTION_ARGS) {
+ TimestampTz ts = PG_GETARG_TIMESTAMPTZ(0);
+ ts = (ts + uuid_diff) * 10;
+ timeuuid_t *uuid = (timeuuid_t *) palloc(sizeof(*uuid));
+ uuid->time_hi_and_version = htons((ts >> 48) | (0x1 << 12));
+ uuid->time_mid = htons(ts >> 32);
+ uuid->time_low = htonl(ts);
+ memset(uuid->data, 0, 8);
+ PG_RETURN_UUID_P(uuid);
+}
+#else
+#error
+#endif