получить до 100 с наносекунд UUID на основе времени - PullRequest
1 голос
/ 08 ноября 2019

Я использую эту библиотеку libraryDependencies += "com.datastax.oss" % "java-driver-core" % "4.3.0" для создания UUID на основе времени. Хотя он генерирует UUID на основе времени, он дает мне до секунд, но я ищу значения в 100 с нано секунд

import com.datastax.oss.driver.api.core.uuid.Uuids
println(Uuids.timeBased().toString)

Выходной UUID что-то вроде f642f350-0230-11ea-a02f-597f2801796a, что соответствует Friday, November 8, 2019 at 2:06:30 PM Greenwich Mean Time

Пожалуйста, помогите, как получить время в миллисекундах примерно так: Friday, November 8, 2019 at 2:06:30:0000000Z PM Greenwich Mean Time

Я хочу, чтобы временная метка была преобразована в формат uuid для тестирования (тесты принимают только формат uuid). Затем я бы преобразовал UUID во время, чтобы измерить разницу во времени.

1 Ответ

2 голосов
/ 08 ноября 2019

Здесь есть несколько шагов. Во-первых, необходимо преобразовать временную метку UUID на основе времени (которая составляет 100 с наносекунд с 15 октября 1582 года) в метку, совместимую с функциональностью даты Java (т. Е. Миллисекунды с 1 января 1970 года). Примечательно, что вы запросили точность с точностью до миллисекунды.

Далее нам нужно интерпретировать эту дату в правильном часовом поясе.

Наконец, нам нужно отформатировать ее в текст в желаемом формате.

Вот код:

// this is the difference between midnight October 15, 1582 UTC and midnight January 1, 1970 UTC as 100 nanosecond units
private static final long EPOCH_DIFFERENCE = 122192928000000000L;

private static final ZoneId GREENWICH_MEAN_TIME = ZoneId.of("GMT");

private static final DateTimeFormatter FORMATTER = new DateTimeFormatterBuilder()
        .appendText(DAY_OF_WEEK, FULL)
        .appendLiteral(", ")
        .appendText(MONTH_OF_YEAR, FULL)
        .appendLiteral(' ')
        .appendValue(DAY_OF_MONTH)
        .appendLiteral(", ")
        .appendValue(YEAR, 4)
        .appendLiteral(" at ")
        .appendValue(CLOCK_HOUR_OF_AMPM)
        .appendLiteral(':')
        .appendValue(MINUTE_OF_HOUR, 2)
        .appendLiteral(':')
        .appendValue(SECOND_OF_MINUTE, 2)
        .appendLiteral('.')
        .appendFraction(NANO_OF_SECOND, 7, 7, false)
        .appendLiteral(' ')
        .appendText(AMPM_OF_DAY)
        .appendLiteral(' ')
        .appendZoneText(FULL)
        .toFormatter(Locale.getDefault());

public static String formattedDateFromTimeBasedUuid(UUID uuid) {
    ZonedDateTime date = timeBasedUuidToDate(uuid);
    return FORMATTER.format(date);
}

public static ZonedDateTime timeBasedUuidToDate(UUID uuid) {
    if (uuid.version() != 1) {
        throw new IllegalArgumentException("Provided UUID was not time-based.");
    }
    // the UUID timestamp is in 100 nanosecond units.
    // convert that to nanoseconds
    long nanoseconds = (uuid.timestamp() - EPOCH_DIFFERENCE) * 100;
    long milliseconds = nanoseconds / 1000000000;
    long nanoAdjustment = nanoseconds % 1000000000;
    Instant instant = Instant.ofEpochSecond(milliseconds, nanoAdjustment);
    return ZonedDateTime.ofInstant(instant, GREENWICH_MEAN_TIME);
}

Я бы отбросил эти методы и константы в служебный класс для удобного повторного использования.

Пара замечаний:

  • Здесь много статически импортированных констант. Они приходят от java.time.format.TextStyle и java.time.temporal.ChronoField.
  • Я использовал DateTimeFormatterBuilder вместо более распространенного DateTimeFormatter.forPattern(String). Я нахожу это более читабельным и готов терпеть получающееся многословие.
  • Я подправил одну вещь о вашем желаемом формате: вы попросили время быть 2:06:30:001;этот код дает 2:06:30.001 - десятичную точку между секундами и миллисекундами, а не двоеточие. Это более правильно, но если вы предпочитаете двоеточие, просто измените соответствующий .appendLiteral('.'), чтобы вместо него передавать двоеточие.
  • Вы часто найдете пример кода, который определяет DateTimeFormatters, ZoneIds и т. Д. Встроенными. Эти классы являются поточно-ориентированными и могут использоваться повторно, поэтому для достижения наилучших результатов вы должны определить их как константы, как я сделал здесь. Вы получите более высокую производительность и уменьшите использование памяти.
  • Обратите внимание, что класс Uuids драйвера DataStax использует значение с точностью до миллисекунды системных часов, поэтому вы просто увидите нули в последних четырехпозиции, если вы не реализуете свой вариант на основе наносекунды. Вы можете сделать это, используя System.nanoTime(), но есть некоторые сложности - проверьте примечание в JavaDoc для получения дополнительной информации .

Чтобы определить промежуток времени между двумя ZonedDateTimes, вы просто делаете это:

Duration duration = Duration.between(date1, date2);

Класс Duration имеет несколько полезных методов , которые вы можете использовать для интерпретации результата.

...