Как измерить время, прошедшее на Java?

Я хочу иметь что-то вроде этого:

public class Stream
{
    public startTime;
    public endTime;

    public getDuration()
    {
        return startTime - endTime;
    }
}

Также важно, чтобы, например, если startTime это 23:00 и endTime 1:00, чтобы получить продолжительность 2:00.

Какие типы использовать для выполнения этого в Java?

Ответ 1

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

Если вы измеряете прошедшее время и хотите, чтобы оно было правильным, вы должны использовать System.nanoTime(). Вы не можете использовать System.currentTimeMillis(), если только вы не возражаете, чтобы ваш результат был неправильным.

Цель nanoTime - измерять прошедшее время, а целью currentTimeMillis является измерение времени настенных часов. Вы не можете использовать его для других целей. Причина в том, что никакие компьютерные часы не идеальны; он всегда дрейфует и иногда нуждается в исправлении. Эта коррекция может произойти вручную, или, в случае большинства машин, есть процесс, который выполняется и постоянно выдает небольшие исправления системным часам ( "настенные часы" ). Они часто случаются. Другая такая коррекция происходит всякий раз, когда есть прыжок второй.

Поскольку цель nanoTime заключается в измерении прошедшего времени, на нее не влияет какая-либо из этих небольших поправок. Это то, что вы хотите использовать. Любые текущие текущие значения с currentTimeMillis будут отключены - возможно, даже отрицательные.

Вы можете сказать: "Это не звучит так, как будто это действительно так важно", о чем я говорю, может быть, нет, но в целом, это неправильный код, который лучше, чем неправильный код? Кроме того, nanoTime в любом случае короче.

Ранее опубликованные объявления об отказе от nanoTime, обычно имеющие только микросекундную точность, действительны. Также может потребоваться больше, чем целая микросекунда для вызова, в зависимости от обстоятельств (как и другая), поэтому не ожидайте времени очень очень малых интервалов правильно.

Ответ 2

Какие типы использовать для выполнения этого в Java?

Короткий ответ - long. Теперь, больше о том, как измерить...

System.currentTimeMillis()

"Традиционный" способ сделать это - действительно использовать System.currentTimeMillis():

long startTime = System.currentTimeMillis();
// ... do something ...
long estimatedTime = System.currentTimeMillis() - startTime;

o.a.c.l.t.StopWatch

Обратите внимание, что Commons Lang имеет класс StopWatch, который может использоваться для измерения времени выполнения в миллисекундах. Он имеет методы, такие как split(), suspend(), resume() и т.д., которые позволяют принимать меры в разных точках исполнения и могут оказаться удобными. Посмотрите на это.

System.nanoTime()

Вы можете использовать System.nanoTime(), если вы ищете чрезвычайно точные измерения прошедшего времени. Из своего javadoc:

long startTime = System.nanoTime();    
// ... the code being measured ...    
long estimatedTime = System.nanoTime() - startTime;

Хамон

Другим вариантом было бы использовать JAMon, инструмент, который собирает статистику (время выполнения, количество ударов, среднее время выполнения, мин., max и т.д.) для любого кода, который находится между методами start() и stop(). Ниже приведен очень простой пример:

import com.jamonapi.*;
...
Monitor mon=MonitorFactory.start("myFirstMonitor");
...Code Being Timed...
mon.stop();

Ознакомьтесь с этой статьей на www.javaperformancetunning.com для приятного ознакомления.

Использование AOP

Наконец, если вы не хотите загромождать свой код этими измерениями (или если вы не можете изменить существующий код), то AOP станет идеальным оружием. Я не буду обсуждать это очень глубоко, но я хотел хотя бы упомянуть об этом.

Ниже, очень простой аспект с использованием AspectJ и JAMon (здесь короткое имя pointcut будет использоваться для монитора JAMon, следовательно, вызов thisJoinPoint.toShortString()):

public aspect MonitorAspect {
    pointcut monitor() : execution(* *.ClassToMonitor.methodToMonitor(..));

    Object arround() : monitor() {
        Monitor monitor = MonitorFactory.start(thisJoinPoint.toShortString());
        Object returnedObject = proceed();
        monitor.stop();
        return returnedObject;
    }
}

Определение pointcut может быть легко адаптировано для мониторинга любого метода, основанного на имени класса, имени пакета, имени метода или любой их комбинации. Измерение действительно идеально подходит для АОП.

Ответ 3

Ваш новый класс:

public class TimeWatch {    
    long starts;

    public static TimeWatch start() {
        return new TimeWatch();
    }

    private TimeWatch() {
        reset();
    }

    public TimeWatch reset() {
        starts = System.currentTimeMillis();
        return this;
    }

    public long time() {
        long ends = System.currentTimeMillis();
        return ends - starts;
    }

    public long time(TimeUnit unit) {
        return unit.convert(time(), TimeUnit.MILLISECONDS);
    }
}

Использование:

    TimeWatch watch = TimeWatch.start();
    // do something
    long passedTimeInMs = watch.time();
    long passedTimeInSeconds = watch.time(TimeUnit.SECONDS);

Затем прошедшее время может быть преобразовано в любой формат, который вам нравится, например, с каландром

Greetz, GHAD

Ответ 4

Если целью является просто напечатать грубую информацию о времени в ваших журналах программ, тогда простое решение для проектов Java не должно писать собственные классы секундомера или таймера, но просто используйте org.apache.commons.lang.time.StopWatch, который является частью Apache Commons Lang.

final StopWatch stopwatch = new StopWatch();
stopwatch.start();
LOGGER.debug("Starting long calculations: {}", stopwatch);
...
LOGGER.debug("Time after key part of calcuation: {}", stopwatch);
...
LOGGER.debug("Finished calculating {}", stopwatch);

Ответ 5

ТЛ; др

например, если startTime это 23:00 и endTime 1:00, чтобы получить продолжительность 2:00.

Невозможно. Если у вас есть только время суток, часы останавливаются в полночь. Без контекста дат, как мы узнаем, если вы имеете в виду 1 AM на следующий день, на следующей неделе или в следующее десятилетие?

Таким образом, с 11:00 до 1:00 означает движение назад в течение 22 часов, пробегая руки против часовой стрелки. См. Результат ниже, минус двадцать два часа.

Duration.between(              // Represent a span of time a total number of seconds plus a fractional second in nanoseconds.
    LocalTime.of( 23 , 0 ) ,   // A time-of-day without a date and without a time zone. 
    LocalTime.of( 1 , 0 )      // A time-of-day clock stops at midnight. So getting to 1 AM from 11 PM means going backwards 22 hours.
)                              // Return a 'Duration' object.
.toString()                    // Generate a 'String' representing this span of time using standard ISO 8601 format: PnYnMnDTnHnMnS

PT-22H

Пересечение полуночи требует большего контекста даты в дополнение к времени дня (см. Ниже).

Как измерить время, прошедшее на Java?

  1. Захватите текущий момент в UTC, с помощью Instant.now().
  2. Захватите другой такой момент позже.
  3. Переходите к Duration.between.
  4. (a) Из результирующего объекта Duration выделите несколько 24-часовых дней, часов, минут, секунд и дробную секунду в наносекундах, вызвав различные методы to…Part.
    (b) Или вызовите toString для генерации String в стандартном формате ISO 8601 PnYnMnDTnHnMnS.

Пример кода, используя пару Instant объектов.

Duration.between(    // Represent a span of time a total number of seconds plus a fractional second in nanoseconds.
    then ,           // Some other 'Instant' object, captured earlier with 'Instant.now()'.
    Instant.now()    // Capture the current moment in UTC with a resolution as fine as nanoseconds, depending on the limits of your host computer hardware clock and operating system. Generally you will get current moment in microseconds (six decimal digits of fractional second) in Java 9, 10, and 11, but only milliseconds in Java 8. 
)                    // Return a 'Duration' object.
.toString()          // Generate a 'String' representing this span of time using standard ISO 8601 format: PnYnMnDTnHnMnS

PT3M27.602197S

Новые технологии в Java 8+

У нас есть новые технологии для этого, теперь встроенные в Java 8 и более поздние версии, java.time framework.

java.time

Рамка java.time определена JSR 310, вдохновленная очень успешным проектом Joda-Time, дополненным проектом ThreeTen-Extra и описанным в учебнике Oracle.

Старые классы времени, такие как java.util.Date/.Calendar в комплекте с самыми ранними версиями Java, оказались плохо спроектированными, запутанными и сложными. Они вытесняются классами java.time.

разрешение

Другие ответы обсуждают решение.

Классы java.time имеют наносекундное разрешение, до девяти цифр десятичной доли секунды. Например, 2016-03-12T04:29:39.123456789Z.

И старые классы java.util.Date/.Calendar, и классы Joda-Time имеют миллисекундное разрешение (3 цифры дроби). Например, 2016-03-12T04:29:39.123Z.

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

Time-of-Day

Если вы действительно хотите работать только с отсутствием какой-либо даты или часового пояса, используйте класс LocalTime.

LocalTime sooner = LocalTime.of ( 17, 00 );
LocalTime later = LocalTime.of ( 19, 00 );

A Duration представляет собой промежуток времени, на который он рассчитывает количество секунд плюс наносекунды.

Duration duration = Duration.between ( sooner, later );

Сбросьте консоль.

System.out.println ( "sooner: " + sooner + " | later: " + later + " | duration: " + duration );

раньше: 17:00 | позже: 19:00 | продолжительность: PT2H

ISO 8601

Обратите внимание на вывод по умолчанию Duration::toString в стандартном формате ISO 8601. В этом формате P обозначает начало (как в "Периоде"), а T отделяет часть лет-месяцев-дней от части часов-минут-секунд.

Пересечение полуночи

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

Используя тот же код, что и выше, но с 23:00 до 01:00 получаете отрицательные двадцать два часа (PT-22H).

LocalTime sooner = LocalTime.of ( 23, 0 );
LocalTime later = LocalTime.of ( 1, 0 );

раньше: 23:00 | позже: 01:00 | продолжительность: PT-22H

Дата-время

Если вы намерены пересечь полночь, вам, вероятно, будет полезно работать со значениями даты и времени, а не только значениями времени суток.

Часовой пояс

Часовой пояс имеет решающее значение для дат. Поэтому мы указываем три элемента: (1) желаемую дату, (2) желаемое время суток и (3) часовой пояс в качестве контекста, с помощью которого можно интерпретировать эту дату и время. Здесь мы произвольно выбираем часовой пояс в районе Монреаля.

Если вы определяете дату только по смещению от UTC, используйте ZoneOffset с параметром OffsetDateTime. Если у вас есть полный часовой пояс (правила смещения плюс для обработки аномалий, таких как летнее время), используйте ZoneId с ZonedDateTime.

LocalDate localDate = LocalDate.of ( 2016, 1, 23 );
ZoneId zoneId = ZoneId.of ( "America/Montreal" );
ZonedDateTime sooner = ZonedDateTime.of ( localDate, LocalTime.of ( 23, 0 ), zoneId );

Мы указываем более позднее время как на следующий день в 1:00.

ZonedDateTime later = ZonedDateTime.of ( localDate.plusDays ( 1 ), LocalTime.of ( 1, 0 ), zoneId );

Мы вычисляем Duration же, как показано выше. Теперь мы получаем два часа, ожидаемых этим Вопросом.

Duration duration = Duration.between ( sooner, later );

Сбросьте консоль.

System.out.println ( "sooner: " + sooner + " | later: " + later + " | duration: " + duration );

раньше: 2016-01-23T23: 00-05: 00 [Америка/Монреаль] | позже: 2016-01-24T01: 00-05: 00 [Америка/Монреаль] | продолжительность: PT2H

Летнее время

Если в момент времени было задействовано время перехода на летнее время (DST) или другая такая аномалия, классы java.time будут настраиваться по мере необходимости. Прочтите документ класса для получения более подробной информации.


О java.time

Рамка java.time встроена в Java 8 и более поздние версии. Эти классы вытесняют неприятные старые устаревшие классы времени, такие как java.util.Date, Calendar и SimpleDateFormat.

Проект Joda-Time, теперь в режиме обслуживания, советует перейти на классы java.time.

Чтобы узнать больше, ознакомьтесь с учебным пособием Oracle. И поиск Qaru для многих примеров и объяснений. Спецификация - JSR 310.

Вы можете обменивать объекты java.time непосредственно с вашей базой данных. Используйте JDBC-драйвер, совместимый с JDBC 4.2 или новее. Нет необходимости в строках, нет необходимости в java.sql.*.

Где можно получить классы java.time?

  • Java SE 8, Java SE 9, Java SE 10 и более поздние версии
    • Встроенный.
    • Часть стандартного Java API с интегрированной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и Java SE 7
    • Большая часть функциональных возможностей java.time включена обратно в Java 6 и 7 в ThreeTen-Backport.
  • Android
    • Более поздние версии реализаций пакетов Android классов java.time.
    • Для более ранних Android (<26), то ThreeTenABP проект адаптирует ThreeTen-Backport (упоминалось выше). См. Раздел Как использовать ThreeTenABP....

Проект ThreeTen-Extra расширяет java.time с дополнительными классами. Этот проект является доказательством возможных будущих дополнений к java.time. Здесь вы можете найти полезные классы, такие как Interval, YearWeek, YearQuarter и другие.

Ответ 6

Java предоставляет статический метод System.currentTimeMillis(). И это возвращает долгую ценность, поэтому это хорошая рекомендация. Многие другие классы принимают параметр timeInMillis, который также длинный.

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

Ответ 7

Какие типы использовать для выполнения этого в Java?

Ответ: длинный

public class Stream {
    public long startTime;
    public long endTime;

    public long getDuration() {
        return endTime - startTime;
    }
    // I  would add
    public void start() {
        startTime = System.currentTimeMillis();
    }
    public void stop() {
         endTime = System.currentTimeMillis();
     }
}

Использование:

  Stream s = .... 

  s.start();

  // do something for a while 

  s.stop();

  s.getDuration(); // gives the elapsed time in milliseconds. 

Это мой прямой ответ на ваш первый вопрос.

Для последней "заметки" я предлагаю вам использовать Joda Time. Он содержит класс interval, подходящий для того, что вам нужно.

Ответ 8

Стоит отметить, что

  • System.currentTimeMillis() в лучшем случае имеет только миллисекундную точность. При достоинстве может быть 16 мс на некоторых системах Windows. Он имеет более низкую стоимость, чем альтернативы < 200 нс.
  • System.nanoTime() является только микросекундой, точной для большинства систем, и может переходить на системы Windows на 100 микросекунд (иногда это не так точно, как кажется).
  • Календарь - очень дорогой способ рассчитать время. (я могу думать отдельно от XMLGregorianCalendar) Иногда это наиболее подходящее решение, но помните, что вам нужно только промежутки времени.

Ответ 9

Если вы пишете приложение, которое должно иметь дело с продолжительностью времени, пожалуйста, взгляните на Joda-Time, у которого есть класс специально для обработки Durations, Интервалы и Периоды. Ваш метод getDuration() выглядит так, как будто он может возвращать интервал времени Joda:

DateTime start = new DateTime(2004, 12, 25, 0, 0, 0, 0);
DateTime end = new DateTime(2005, 1, 1, 0, 0, 0, 0);

public Interval getInterval() {
    Interval interval = new Interval(start, end);
}

Ответ 10

Если вы предпочитаете использовать Java API календаря, вы можете попробовать это,

Date startingTime = Calendar.getInstance().getTime();
//later on
Date now = Calendar.getInstance().getTime();
long timeElapsed = now.getTime() - startingTime.getTime();

Ответ 11

Если вы получаете отметки времени от System.currentTimeMillis(), то ваши временные переменные должны быть длинными.

Ответ 12

Byte Stream Reader Elapsed Time for 23.7 MB is 96 secs

import java.io.*;
import java.io.IOException;
import java.util.Scanner;

class ElaspedTimetoCopyAFileUsingByteStream
{

    private long startTime = 0;
    private long stopTime = 0;
    private boolean running = false;


    public void start() 
    {
        this.startTime = System.currentTimeMillis();
        this.running = true;
    }


    public void stop() 
    {
        this.stopTime = System.currentTimeMillis();
        this.running = false;
    }



    public long getElapsedTime() 
    {
        long elapsed;
        if (running) {
             elapsed = (System.currentTimeMillis() - startTime);
        }
        else {
            elapsed = (stopTime - startTime);
        }
        return elapsed;
    }



    public long getElapsedTimeSecs()                 
    {
        long elapsed;
        if (running) 
        {
            elapsed = ((System.currentTimeMillis() - startTime) / 1000);
        }
        else
        {
            elapsed = ((stopTime - startTime) / 1000);
        }
        return elapsed;
    }





    public static void main(String[] args) throws IOException
    {
        ElaspedTimetoCopyAFileUsingByteStream  s = new ElaspedTimetoCopyAFileUsingByteStream();
        s.start();

        FileInputStream in = null;
        FileOutputStream out = null;

      try {
         in = new FileInputStream("vowels.txt");   // 23.7  MB File
         out = new FileOutputStream("output.txt");

         int c;
         while ((c = in.read()) != -1) {
            out.write(c);
         }
      }finally {
         if (in != null) {
            in.close();
         }
         if (out != null) {
            out.close();
         }
      }



        s.stop();
        System.out.println("elapsed time in seconds: " + s.getElapsedTimeSecs());
    }
}

[Elapsed Time for Byte Stream Reader][1]

**Character Stream Reader Elapsed Time for 23.7 MB is 3 secs**

import java.io.*;
import java.io.IOException;
import java.util.Scanner;

class ElaspedTimetoCopyAFileUsingCharacterStream
{

    private long startTime = 0;
    private long stopTime = 0;
    private boolean running = false;


    public void start() 
    {
        this.startTime = System.currentTimeMillis();
        this.running = true;
    }


    public void stop() 
    {
        this.stopTime = System.currentTimeMillis();
        this.running = false;
    }



    public long getElapsedTime() 
    {
        long elapsed;
        if (running) {
             elapsed = (System.currentTimeMillis() - startTime);
        }
        else {
            elapsed = (stopTime - startTime);
        }
        return elapsed;
    }



    public long getElapsedTimeSecs()                 
    {
        long elapsed;
        if (running) 
        {
            elapsed = ((System.currentTimeMillis() - startTime) / 1000);
        }
        else
        {
            elapsed = ((stopTime - startTime) / 1000);
        }
        return elapsed;
    }





    public static void main(String[] args) throws IOException
    {
        ElaspedTimetoCopyAFileUsingCharacterStream  s = new ElaspedTimetoCopyAFileUsingCharacterStream();
        s.start();

         FileReader in = null;                // CharacterStream Reader
      FileWriter out = null;

      try {
         in = new FileReader("vowels.txt");    // 23.7 MB
         out = new FileWriter("output.txt");

         int c;
         while ((c = in.read()) != -1) {
            out.write(c);
         }
      }finally {
         if (in != null) {
            in.close();
         }
         if (out != null) {
            out.close();
         }
      }

              s.stop();
        System.out.println("elapsed time in seconds: " + s.getElapsedTimeSecs());
    }
}


[Elapsed Time for Character Stream Reader][2]


  [1]: https://i.stack.imgur.com/hYo8y.png
  [2]: https://i.stack.imgur.com/xPjCK.png

Ответ 13

Я нашел этот код полезным при выборе времени:

public class Et {
    public Et() {
    reset();
    }
    public void reset() {
    t0=System.nanoTime();
    }
    public long t0() {
        return t0;
    }
    public long dt() {
        return System.nanoTime()-t0();
    }
    public double etms() {
    return etms(dt());
    }
    @Override public String toString() {
        return etms()+" ms.";
    }
    public static double etms(long dt) {
        return dt/1000000.; // 1_000_000. breaks cobertura
    }
    private Long t0;
}

Ответ 14

Используйте это:

SimpleDateFormat format = new SimpleDateFormat("HH:mm");

Date d1 = format.parse(strStartTime);
Date d2 = format.parse(strEndTime);

long diff = d2.getTime() - d1.getTime();
long diffSeconds,diffMinutes,diffHours;

if (diff > 0) {
diffSeconds = diff / 1000 % 60;
diffMinutes = diff / (60 * 1000) % 60;
diffHours = diff / (60 * 60 * 1000);
}
else{
long diffpos = (24*((60 * 60 * 1000))) + diff;
diffSeconds = diffpos / 1000 % 60;
diffMinutes = diffpos / (60 * 1000) % 60;
diffHours = (diffpos / (60 * 60 * 1000));
}

(Также важно, чтобы, например, если startTime это 23:00 и endTime 1:00, чтобы получить продолжительность 2:00.)

часть "else" может быть корректной.

Ответ 15

Я построил функцию форматирования, основанную на материалах, которые я украл SO. Мне нужен способ "профилирования" в сообщениях журнала, поэтому мне понадобилось сообщение продолжительностью продолжительной длины.

public static String GetElapsed(long aInitialTime, long aEndTime, boolean aIncludeMillis)
{
  StringBuffer elapsed = new StringBuffer();

  Map<String, Long> units = new HashMap<String, Long>();

  long milliseconds = aEndTime - aInitialTime;

  long seconds = milliseconds / 1000;
  long minutes = milliseconds / (60 * 1000);
  long hours = milliseconds / (60 * 60 * 1000);
  long days = milliseconds / (24 * 60 * 60 * 1000);

  units.put("milliseconds", milliseconds);
  units.put("seconds", seconds);
  units.put("minutes", minutes);
  units.put("hours", hours);
  units.put("days", days);

  if (days > 0)
  {
    long leftoverHours = hours % 24;
    units.put("hours", leftoverHours);
  }

  if (hours > 0)
  {
    long leftoeverMinutes = minutes % 60;
    units.put("minutes", leftoeverMinutes);
  }

  if (minutes > 0)
  {
    long leftoverSeconds = seconds % 60;
    units.put("seconds", leftoverSeconds);
  }

  if (seconds > 0)
  {
    long leftoverMilliseconds = milliseconds % 1000;
    units.put("milliseconds", leftoverMilliseconds);
  }

  elapsed.append(PrependZeroIfNeeded(units.get("days")) + " days ")
      .append(PrependZeroIfNeeded(units.get("hours")) + " hours ")
      .append(PrependZeroIfNeeded(units.get("minutes")) + " minutes ")
      .append(PrependZeroIfNeeded(units.get("seconds")) + " seconds ")
      .append(PrependZeroIfNeeded(units.get("milliseconds")) + " ms");

  return elapsed.toString();

}

private static String PrependZeroIfNeeded(long aValue)
{
  return aValue < 10 ? "0" + aValue : Long.toString(aValue);
}

И тестовый класс:

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

import junit.framework.TestCase;

public class TimeUtilsTest extends TestCase
{

  public void testGetElapsed()
  {
    long start = System.currentTimeMillis();
    GregorianCalendar calendar = (GregorianCalendar) Calendar.getInstance();
    calendar.setTime(new Date(start));

    calendar.add(Calendar.MILLISECOND, 610);
    calendar.add(Calendar.SECOND, 35);
    calendar.add(Calendar.MINUTE, 5);
    calendar.add(Calendar.DAY_OF_YEAR, 5);

    long end = calendar.getTimeInMillis();

    assertEquals("05 days 00 hours 05 minutes 35 seconds 610 ms", TimeUtils.GetElapsed(start, end, true));

  }

}