> d) {
return d - std::chrono::milliseconds(START_EPOCH);
}
/**
* @param timestamp milliseconds since Unix epoch
* @return
*/
static int64_t from_unix_timestamp(int64_t timestamp) {
return (timestamp - START_EPOCH) * 10000;
}
public:
/**
* Converts a 100-nanoseconds precision timestamp into the 16 byte representation
* of a type 1 UUID (a time-based UUID).
*
* To specify a 100-nanoseconds precision timestamp, one should provide a milliseconds timestamp and
* a number 0 <= n < 10000 such that n*100 is the number of nanoseconds within that millisecond.
*
* Warning: This method is not guaranteed to return unique UUIDs; Multiple
* invocations using identical timestamps will result in identical UUIDs.
*
* @return a type 1 UUID represented as a byte[]
*/
static std::array get_time_UUID_bytes(int64_t time_millis, int nanos)
{
#if 0
if (nanos >= 10000)
throw new IllegalArgumentException();
#endif
return create_time_UUID_bytes(instance->create_time_unsafe(time_millis, nanos));
}
private:
static std::array create_time_UUID_bytes(uint64_t msb)
{
uint64_t lsb = clock_seq_and_node;
std::array uuid_bytes;
for (int i = 0; i < 8; i++)
uuid_bytes[i] = (int8_t) (msb >> 8 * (7 - i));
for (int i = 8; i < 16; i++)
uuid_bytes[i] = (int8_t) (lsb >> 8 * (7 - (i - 8)));
return uuid_bytes;
}
public:
/**
* Returns a milliseconds-since-epoch value for a type-1 UUID.
*
* @param uuid a type-1 (time-based) UUID
* @return the number of milliseconds since the unix epoch
* @throws IllegalArgumentException if the UUID is not version 1
*/
static int64_t get_adjusted_timestamp(UUID uuid)
{
#if 0
if (uuid.version() != 1)
throw new IllegalArgumentException("incompatible with uuid version: "+uuid.version());
#endif
return (uuid.timestamp() / 10000) + START_EPOCH;
}
static uint64_t make_nanos_since(int64_t millis) {
return (static_cast(millis) - static_cast(START_EPOCH)) * 10000;
}
// nanos_since must fit in 60 bits
static bool is_valid_nanos_since(uint64_t nanos_since) {
return !(0xf000000000000000UL & nanos_since);
}
private:
// needs to return two different values for the same when.
// we can generate at most 10k UUIDs per ms.
// NOTE: In the original Java code this function was "synchronized". This isn't
// needed if we assume our code will run on just one CPU.
int64_t create_time_safe()
{
using namespace std::chrono;
int64_t millis = duration_cast(
system_clock::now().time_since_epoch()).count();
uint64_t nanos_since = make_nanos_since(millis);
if (nanos_since > last_nanos)
last_nanos = nanos_since;
else
nanos_since = ++last_nanos;
return create_time(nanos_since);
}
int64_t create_time_unsafe(int64_t when, int nanos)
{
uint64_t nanos_since = make_nanos_since(when) + static_cast(static_cast(nanos));
return create_time(nanos_since);
}
// std::chrono typeaware wrapper around create_time().
// Creates a timeuuid compatible time (decimicroseconds since
// the start of GMT epoch).
template
static int64_t create_time(std::chrono::duration> d) {
return create_time(duration_cast(d).count());
}
public:
static int64_t create_time(uint64_t nanos_since)
{
uint64_t msb = 0L;
assert(is_valid_nanos_since(nanos_since));
msb |= (0x00000000ffffffffL & nanos_since) << 32;
msb |= (0x0000ffff00000000UL & nanos_since) >> 16;
msb |= (0x0fff000000000000UL & nanos_since) >> 48;
msb |= 0x0000000000001000L; // sets the version to 1.
return msb;
}
};
// for the curious, here is how I generated START_EPOCH
// Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT-0"));
// c.set(Calendar.YEAR, 1582);
// c.set(Calendar.MONTH, Calendar.OCTOBER);
// c.set(Calendar.DAY_OF_MONTH, 15);
// c.set(Calendar.HOUR_OF_DAY, 0);
// c.set(Calendar.MINUTE, 0);
// c.set(Calendar.SECOND, 0);
// c.set(Calendar.MILLISECOND, 0);
// long START_EPOCH = c.getTimeInMillis();
} // namespace utils