Любая хорошая высокопроизводительная библиотека Java, которая работает с меткой времени? - PullRequest
1 голос
/ 24 июня 2011

Я ищу высокопроизводительную библиотеку Java, которая предоставляет методы, которые позволяют мне получить:

  1. Текущий час (0-24)
  2. Текущий день (1-31)
  3. Текущая неделя (1-52)
  4. Текущий месяц (1-12)
  5. Текущий сезон (1-4)
  6. Текущий год (ГГГГ или ГГ)

Производительность - самая важная проблема для меня. Вот почему я не могу использовать стандартный класс Calendar. Лучшим было бы решение, которое выполняет все вычисления без создания новых объектов.

ДОБАВЛЕНО: Для пояснения я упомяну еще один раз: более 100000 операций в секунду.

Ответы [ 9 ]

3 голосов
/ 24 июня 2011

Вы уверены, что Calendar слишком медленно или вы просто в это верите? Вы измерили это?

Создание новых объектов в Java довольно дешево. Держать их рядом дорого.

Тем не менее, попробуйте Joda Time или скопируйте алгоритмы из кода Java в статические вспомогательные методы.

3 голосов
/ 24 июня 2011

Вы могли бы фактически использовать превосходную библиотеку joda-time, чтобы сделать это. Реализации Chronology в joda обеспечивают логику методов типа DateTime getHour getDay. Нет проблем с его использованием напрямую, если вы хотите пропустить создание DateTime мгновений.

long msSinceEpoch = System.currentTimeMillis();

Chronology chronology = ISOChronology.getInstanceUTC() // This can be static

chronology.hourOfDay().get(msSinceEpoch);
chronology.dayOfMonth().get(msSinceEpoch);
chronology.weekOfWeek().get(msSinceEpoch);
chronology.monthOfYear().get(msSinceEpoch);
chronology.years().get(msSinceEpoch);

Сессия - это не то, что есть у Джоды. Вы должны будете отработать это за месяц, учитывая ваши собственные правила.

См. документацию по времени по хронологии

2 голосов
/ 24 июня 2011

Вы можете получить текущее время и рассчитать текущие часы, минуты, секунды, миллисекунды по делению и остатку.День, месяц, годы меняются только один раз в день, поэтому вам нужно только рассчитать их при изменении.

Вы можете использовать кэшированный день / месяц / год и рассчитать остаток в микросекунду,без создания объектов (более одного раза в день)

import java.util.Calendar;
import java.util.TimeZone;

public class Daytime {
    private static final long HOUR_MS = 3600*1000;

    public short year;
    public byte month, day;
    public byte hour, min, sec;
    public short millis;

    private long lastMillis = Integer.MIN_VALUE;
    private final TimeZone timeZone;
    private long timeOffset;

    public Daytime() {
        timeZone = TimeZone.getTimeZone("UTC");
        now();
    }

    public Daytime(TimeZone timeZone) {
        this.timeZone = timeZone;
        now();
    }

    public void now() {
        long now = System.currentTimeMillis() + timeOffset;
        if (now == lastMillis) return;
        long cachePeriod = now/HOUR_MS;
        // could the day have changed?
        if (cachePeriod != lastMillis/HOUR_MS) {
            timeOffset = timeZone.getOffset(now);
            Calendar cal = Calendar.getInstance(timeZone);
            year = (short) cal.get(Calendar.YEAR);
            month = (byte) cal.get(Calendar.MONTH);
            day = (byte) cal.get(Calendar.DAY_OF_MONTH);
            hour = (byte) cal.get(Calendar.HOUR);
        }
        millis = (short) (now % 1000);
        now /= 1000;
        sec = (byte) (now % 60);
        now /= 60;
        min = (byte) (now % 60);
    }

    public static void main(String... args) {
        Daytime dt = new Daytime();
        long start = System.nanoTime();
        final int runs = 10 * 1000 * 1000;
        for(int i=0;i< runs;i++)
            dt.now();
        long time = System.nanoTime() - start;
        System.out.printf("Daytime.now() took %.3f micro-seconds on average%n", time/1e3/runs);
    }
}

печать

Daytime.now() took 0.287 micro-seconds on average

Существуют различные предположения о том, как происходят изменения летнего времени.Возможно, вам потребуется изменить период проверки в соответствии с вашими потребностями.

1 голос
/ 21 мая 2019

Я бы рекомендовал JodaTime, когда вам нужно каждый раз создавать экземпляр класса DateTime перед вызовом методов получения полей. Но когда вы вызываете методы getters больше, чем создаете экземпляры, лучше использовать библиотеку java.time из JDK 8 или backport ThreeTenABP .

Это потому, что класс DateTime JodaTime хранит только long iMillis с начала эпохи, и все получатели определенных полей, таких как minuteOfHour, dayOfMonth, всегда вычисляют эти значения с нуля. Но ZonedDateTime из java.time хранит эти поля в отдельных переменных, таких как: int year, short month, short day, ...
Я создал несколько тестов для сравнения

1 голос
/ 24 июня 2011

Я прочитал так много постов о Joda Time на SO теперь, когда я, наконец, скачал его и попробовал.

Ответ от Гарета Дэвиса уже принят, и у меня нет проблем с этим.Но мне любопытно узнать, в чем же заключается разница между Joda Time.

Основываясь на вопросе и принятом ответе, я организовал урок для сравнения времени выполнения JDK Calendar и Joda Time Chronology.

Я считаю, что реализация календаря работает стабильно быстрее, а не в два раза быстрее.

import java.util.Calendar;
import java.util.Date;

import org.joda.time.Chronology;
import org.joda.time.chrono.ISOChronology;


public class CalendarTest {

    private static final int ITERATIONS = 1000000;

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            jdkCalendar();
            jodaChronology();
        }
    }

    private static void jdkCalendar() {
        long start = System.currentTimeMillis();
        Calendar c = Calendar.getInstance();
        int hourOfDay = 0;
        int dayOfMonth = 0;
        int weekOfYear = 0;
        int month = 0;
        int year = 0;
        for (int i = 0; i < ITERATIONS; i++) {
            c.setTimeInMillis(System.currentTimeMillis());
            hourOfDay = c.get(Calendar.HOUR_OF_DAY);
            dayOfMonth = c.get(Calendar.DAY_OF_MONTH);
            weekOfYear = c.get(Calendar.WEEK_OF_YEAR);
            month = c.get(Calendar.MONTH);
            year = c.get(Calendar.YEAR);
        }
        long duration = System.currentTimeMillis() - start;
        System.err.printf("jdk:  duration %d, hourOfDay: %d, dayOfMonth: %d, weekOfYear: %d, month: %d, year: %d\n", duration, hourOfDay, dayOfMonth, weekOfYear, month, year);
    }

    private static void jodaChronology() {
        long start = System.currentTimeMillis();
        Chronology chronology = ISOChronology.getInstanceUTC(); // This can be static
        int hourOfDay = 0;
        int dayOfMonth = 0;
        int weekOfYear = 0;
        int month = 0;
        int year = 0;
        for (int i = 0; i < ITERATIONS; i++) {
            long msSinceEpoch = System.currentTimeMillis();
            hourOfDay = chronology.hourOfDay().get(msSinceEpoch);
            dayOfMonth = chronology.dayOfMonth().get(msSinceEpoch);
            weekOfYear = chronology.weekOfWeekyear().get(msSinceEpoch);
            month = chronology.monthOfYear().get(msSinceEpoch);
            year = chronology.years().getValue(msSinceEpoch);
        }
        long duration = System.currentTimeMillis() - start;
        System.err.printf("joda: duration %d, hourOfDay: %d, dayOfMonth: %d, weekOfYear: %d, month: %d, year: %d\n", duration, hourOfDay, dayOfMonth, weekOfYear, month, year);
    }

}

Пример вывода:

jdk:  duration 1714, hourOfDay: 12, dayOfMonth: 24, weekOfYear: 25, month: 5, year: 2011
joda: duration 2099, hourOfDay: 12, dayOfMonth: 24, weekOfYear: 25, month: 6, year: 41
jdk:  duration 377, hourOfDay: 12, dayOfMonth: 24, weekOfYear: 25, month: 5, year: 2011
joda: duration 689, hourOfDay: 12, dayOfMonth: 24, weekOfYear: 25, month: 6, year: 41
jdk:  duration 340, hourOfDay: 12, dayOfMonth: 24, weekOfYear: 25, month: 5, year: 2011
joda: duration 680, hourOfDay: 12, dayOfMonth: 24, weekOfYear: 25, month: 6, year: 41
jdk:  duration 330, hourOfDay: 12, dayOfMonth: 24, weekOfYear: 25, month: 5, year: 2011
joda: duration 653, hourOfDay: 12, dayOfMonth: 24, weekOfYear: 25, month: 6, year: 41
jdk:  duration 326, hourOfDay: 12, dayOfMonth: 24, weekOfYear: 25, month: 5, year: 2011
joda: duration 596, hourOfDay: 12, dayOfMonth: 24, weekOfYear: 25, month: 6, year: 41
jdk:  duration 337, hourOfDay: 12, dayOfMonth: 24, weekOfYear: 25, month: 5, year: 2011
joda: duration 620, hourOfDay: 12, dayOfMonth: 24, weekOfYear: 25, month: 6, year: 41
jdk:  duration 471, hourOfDay: 12, dayOfMonth: 24, weekOfYear: 25, month: 5, year: 2011
joda: duration 590, hourOfDay: 12, dayOfMonth: 24, weekOfYear: 25, month: 6, year: 41
jdk:  duration 326, hourOfDay: 12, dayOfMonth: 24, weekOfYear: 25, month: 5, year: 2011
joda: duration 591, hourOfDay: 12, dayOfMonth: 24, weekOfYear: 25, month: 6, year: 41
jdk:  duration 336, hourOfDay: 12, dayOfMonth: 24, weekOfYear: 25, month: 5, year: 2011
joda: duration 595, hourOfDay: 12, dayOfMonth: 24, weekOfYear: 25, month: 6, year: 41
jdk:  duration 327, hourOfDay: 12, dayOfMonth: 24, weekOfYear: 25, month: 5, year: 2011
joda: duration 560, hourOfDay: 12, dayOfMonth: 24, weekOfYear: 25, month: 6, year: 41
1 голос
/ 24 июня 2011

Имейте в виду, что Calendar.getInstance довольно дорог, но вы обычно можете получить объект Calendar, вызвав этот метод один раз и повторно (если вам не нужен Calendar для потока: Calendar не является потокобезопасным).

1 голос
/ 24 июня 2011

Вы можете использовать Joda Time , потому что это намного быстрее, чем Calendar, и сделайте это:

LocalDateTime now = new LocalDateTime(); // automatically points to current datetime.
int hour = now.getHourOfDay();
int day = now.getDayOfMonth();
int week = now.getWeekOfWeekyear();
int month = now.getMonthOfYear();
int year = now.getYear();
int season = getSeason(day, month);

GetSeason () легко реализовать.Нет решения, которое делает все это без создания какого-либо объекта.Кстати, зачем вам столько производительности?!?!

1 голос
/ 24 июня 2011

Вы можете использовать java.util.Calander , и, если вас это не устраивает, вы можете использовать Joda Time .

Это может вам помочь.

1 голос
/ 24 июня 2011

Используйте только один объект и обновите время следующим образом:

Date d = new Date();
...
d.setTime(System.currentTimeMillis());
...