Как измерить время, прошедшее в Java? [дубликат]

этот вопрос уже есть ответ здесь:

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

public class Stream
{
    public startTime;
    public endTime;

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

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

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

15 ответов


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

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

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

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

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

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


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

короткий ответ:long. Теперь подробнее о том, как измерить...


новый класс:

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, Гхад!--3-->


Если цель состоит в том, чтобы просто распечатать грубую информацию о времени в журналах программ, то простое решение для проектов 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);

tl; dr

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

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

таким образом, переход с 11 вечера до 1 утра означает перемещение назад во времени 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 of 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.время основы.

java.время

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

старые классы даты и времени, такие как java.утиль.Дата./Календарь в комплекте с самыми ранними версиями Java оказался плохо спроектированным, запутанным и хлопотным. Они вытеснены java.классы время.

разрешение

другие ответы обсудить резолюцию.

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

оба старые java.утиль.Дата./Классы календаря и классы времени Joda имеют разрешение миллисекунды (3 цифры дроби). Например, 2016-03-12T04:29:39.123Z.

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

Времени

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

Пересечение Полночь

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

используя тот же код, что и выше, но идя от 23:00 to 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. Если у вас есть полный часовой пояс (смещение плюс правила для обработки аномалий, таких как летнее время Time), используйте 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.классы времени будут корректироваться по мере необходимости. Прочитайте класс doc для деталей.


о java.время

на java.время framework встроен в Java 8 и более поздние версии. Эти классы вытесняют беспокойных старых наследие дата-время такие классы, как java.util.Date, Calendar, & SimpleDateFormat.

на Joda Времени, теперь режим обслуживания, советует миграцию в java.время классы.

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

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

где получить java.время занятий?

  • Java SE 8, Java SE 9, Java SE 10, и позже
    • встроенный.
    • часть стандартного API Java со встроенной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и Java SE 7
    • большая часть java.функциональность времени обратно портирована на Java 6 & 7 в ThreeTen-Backport.
  • Android
    • более поздние версии Android bundle реализации java.классы время.
    • для более раннего Android ( ThreeTenABP проект приспосабливается ThreeTen-Backport (упоминалось выше). См.как использовать ThreeTenABP....

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


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

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


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

ответ: long

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. 

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

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


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

  • система.currentTimeMillis () имеет только миллисекундную точность в лучшем случае. На счету его может быть 16 МС на некоторых системах windows. Он имеет более низкую стоимость, что альтернативы
  • система.nanoTime() является только микросекундным точным в большинстве систем и может прыгать на системах windows на 100 микросекунд (i.e иногда это не так точно, как кажется)
  • календарь-очень дорогой способ расчета времени. (я могу думать только из XMLGregorianCalendar) иногда его наиболее подходящее решение, но имейте в виду, что вы должны только длительные интервалы времени.

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

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

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

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


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

Я нашел этот код полезным при синхронизации вещей:

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;
}

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

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" может получить его правильно


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

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));

  }

}