Понадобилось мне из секунд с начала эпохи™ получать год и месяц.
Итерация №0:
Берём java.util.Calendar, делаем .setTimeMillis(...), делаем .get(Calendar.YEAR) и .get(Calendar.MONTH) (не забываем месяц на единицу увеличивать)
Исследование №1:
Запускаем под JProfiler, видим, что 16.3% времени занимает извлечение даты. Печалимся.
Итерация №1:
Видим, что в папке lib/ проекта уже лежит joda-time-2.0.jar. Делаем date = new DateTime(millis) и .get(DateTimeFieldType.year()) и .get(DateTimeFieldType.month()).
Исследование №2:
Запускаем под JProfiler, видим, что извлечение даты занимает уже 12.7%. «И увидел Бог, что это хорошо».
Исследование №3:
Хочется понять насколько реально быстрее работает joda-time:
1. Качаем joda-time-2.4
2. Пишем небольшой бенчмарк.
3. Запускаем 10kk итераций. Видим, что Calendar выполняет их за 789 мс, а joda-time — за 1126 мс.
4. Охуеваем
5. Чешем репу
6. Копируем из папки проекта joda-time-2.0.jar и запускаем с ним. Результат — 458 мс.
Исследование №4:
1. Качаем бету Java 8 от IBM
2. Дописываем бенчмарк, который делает LocalDateTime.ofInstant(Instant.ofEpochMilli(millis), id).getYear()
3. Запускаем — 960 мс. Т.е. уже лучше Calendar, но всё ещё хуже joda-time-2.0.
Выводы:
Новое — не значит лучшее.
Хочешь реально быстрого извлечения времени — создавай один объект MutableDateTime из joda-time и будет тебе счастье.
Для истории, код бенчмарка:
```java
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoField;
import java.util.Calendar;
import org.joda.time.DateTimeFieldType;
import org.joda.time.DateTime;
import org.joda.time.MutableDateTime;
interface MillisToYear {
int year(long millis);
}
class CalendarMillisToYear implements MillisToYear {
private final Calendar cal = Calendar.getInstance();
@Override
public int year(final long millis) {
cal.setTimeInMillis(millis);
return cal.get(Calendar.YEAR);
}
}
class JodaMillisToYear implements MillisToYear {
private final DateTimeFieldType year = DateTimeFieldType.year();
@Override
public int year(final long millis) {
return new DateTime(millis).get(year);
}
}
class MutableJodaMillisToYear implements MillisToYear {
private final DateTimeFieldType year = DateTimeFieldType.year();
private final MutableDateTime date = new MutableDateTime();
@Override
public int year(final long millis) {
date.setMillis(millis);
return date.get(year);
}
}
class Java8MillisToYear implements MillisToYear {
private final ZoneId id = ZoneId.of("Europe/Moscow");
@Override
public int year(final long millis) {
return LocalDateTime.ofInstant(Instant.ofEpochMilli(millis), id)
.getYear();
}
}
public class Main {
public static void main(final String... args) {
MillisToYear mty;
switch (Integer.parseInt(args[0])) {
case 0:
mty = new CalendarMillisToYear();
break;
case 1:
mty = new JodaMillisToYear();
break;
case 2:
mty = new MutableJodaMillisToYear();
break;
case 3:
mty = new Java8MillisToYear();
break;
default:
throw new RuntimeException();
}
long now = System.currentTimeMillis() / 86400000L * 86400000L;
for (long i = 0; i < 1000000; ++i) {
mty.year(now + i);
}
long start = System.currentTimeMillis();
long chksum = 0L;
for (long i = 0L; i < 10000000000L; i += 1000L) {
chksum += mty.year(now + i);
}
long total = (System.currentTimeMillis() - start);
System.out.println("Total time: " + total);
System.out.println("Checksum: " + chksum);
}
}
```