Преобразование java.util.Date в String в формате yyyy-MM-dd без создания большого количества объектов

Мне нужно преобразовать java.util.Date в String в формате yyyy-MM-dd в больших количествах.

Я только что перешел в java 8 и хочу знать, как это сделать правильно. Мое решение с Java 7 было похоже:

DateTimeFormatter DATE_FORMATTER = DateTimeFormat.forPattern(DATE_FORMAT_PATTERN)

DATE_FORMATTER.print(value.getTime())

Это помогло мне не создавать множество избыточных объектов.

Итак, теперь, когда я переехал в java 8, я хочу переписать его правильно, но:

LocalDate.fromDateFields(value).toString())

каждый раз создает новый объект LocalDate и это дает большую работу GC.

Есть ли способы решить мою проблему? Производительность и безопасность потока очень важны.

После некоторого тестирования я обнаружил, что даже при создании новых объектов с помощью:

new SimpleDateFormat("yyyy-MM-dd")).format(value)) 

быстрее всего по этой теме.

Ответ 1

Ниже перечислены только накладные расходы на преобразование старой даты в новый LocalDate.

    Date date = new Date();
    LocalDate ldate = LocalDate.from(date.toInstant().atZone(ZoneOffset.UTC));
    String s = DateTimeFormatter.ISO_DATE.format(ldate); // uuuu-MM-dd

Однако верно, что DateTimeFormatters являются потокобезопасными и, следовательно, будут иметь один экземпляр за каждый вызов.

PS

Я добавил .atZone(ZoneOffset.UTC) из-за сообщенного исключения и решения @Flown: указание зоны. Поскольку Date не обязательно используется для дат UTC, можно использовать другую.

Ответ 2

Используйте SimpleDateFormat для форматирования даты.

следите, SDF НЕ РЕЗЬБОЙ, это может быть не важно, но помните об этом.

Например:

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
System.out.println((sdf.format(new Date())).toString());

LINK с дополнительной информацией.

Ответ 3

У меня нет точных чисел с точки зрения производительности, но я бы использовал Java 8 Time API для решения этой проблемы. В вашем специальном случае я бы использовал следующее выражение:

LocalDate.now().format(DateTimeFormatter.ISO_DATE);

EDIT: для этого решения происходит переход от java.util.Date к java.time.LocalDate требуется!

new Date().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

Ответ 4

Без создания большого количества объектов, что означает, что вы хотите версию исполнения?

public static String getIsoDate(java.util.Date time) {
    java.util.Calendar cal = java.util.Calendar.getInstance();
    cal.setTime(time);
    StringBuilder sb = new StringBuilder();
    int year = cal.get(java.util.Calendar.YEAR);
    int month = cal.get(java.util.Calendar.MONTH) + 1;
    int day = cal.get(java.util.Calendar.DAY_OF_MONTH);
    sb.append(year);
    sb.append('-');
    if (month < 10) {
        sb.append('0');
    }
    sb.append(month);
    sb.append('-');
    if (day < 10) {
        sb.append('0');
    }
    sb.append(day);
    return sb.toString();
}

Эта версия является потокобезопасной и позволяет избежать создания большинства скрытых объектов, и если у вас нет лет в возрасте до 1000 или более 9999, она будет печататься просто отлично.

Ответ 5

вы можете использовать аннотацию @JsonFormat (shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") в вашем поле.