Здесь есть несколько шагов. Во-первых, необходимо преобразовать временную метку 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
имеет несколько полезных методов , которые вы можете использовать для интерпретации результата.