[java] 자바의 현재 시간 (마이크로 초)

Unix 시스템에서 Java에서 마이크로 초 수준의 정확도로 타임 스탬프를 얻을 수있는 방법이 있습니까? C의 gettimeofday기능 과 같은 것 .



답변

아니요, Java에는 그러한 기능이 없습니다.

System.nanoTime ()이 있지만 이전에 알려진 시간에서 오프셋을 제공합니다. 따라서 여기에서 절대 숫자를 가져올 수는 없지만 나노초 (또는 더 높은) 정밀도를 측정하는 데 사용할 수 있습니다.

JavaDoc은 이것이 나노초 정밀도를 제공하지만 나노초 정밀도를 의미하지는 않는다고 말합니다. 따라서 반환 값의 적절하게 큰 계수를 사용하십시오.


답변

tl; dr

Java 9 이상 : 현재 순간을 캡처 할 때 최대 나노초 해상도. 이것은 소수의 9 자리 숫자입니다.

Instant.now()   

2017-12-23T12 : 34 : 56.123456789Z

로 제한하려면 마이크로 , 잘라 내기를 .

Instant                // Represent a moment in UTC. 
.now()                 // Capture the current moment. Returns a `Instant` object. 
.truncatedTo(          // Lop off the finer part of this moment. 
    ChronoUnit.MICROS  // Granularity to which we are truncating. 
)                      // Returns another `Instant` object rather than changing the original, per the immutable objects pattern. 

2017-12-23T12 : 34 : 56.123456Z

실제로 .now현대의 기존 컴퓨터 하드웨어 시계는 나노초 단위로 정확하지 않기 때문에 마이크로 초 만 캡처 할 수 있습니다.

세부

다른 답변은 Java 8에서 다소 구식입니다.

java.time

Java 8 이상은 java.time 프레임 워크 와 함께 제공됩니다 . 이 새로운 클래스는 java.util.Date/.Calendar 및 java.text.SimpleDateFormat과 같은 Java의 초기 버전과 함께 제공되는 결함이있는 날짜-시간 클래스를 대체합니다. 프레임 워크는 ThreeTen-Extra 프로젝트에 의해 확장 된 Joda-Time 에서 영감을 얻은 JSR 310에 의해 정의됩니다 .

java.time의 클래스 는 이전 날짜-시간 클래스와 Joda-Time에서 사용 하는 밀리 초 보다 훨씬 더 미세한 나노초로 확인 됩니다. 그리고 질문에서 묻는 마이크로 초 보다 더 세밀 합니다.

여기에 이미지 설명 입력

Clock 이행

java.time 클래스는 나노초 단위로 값을 나타내는 데이터를 지원하지만 클래스는 아직 나노초 단위로 값을 생성 하지 않습니다 . now()방법은 이전의 날짜 – 시간 클래스와 같은 오래 된 시계 구현을 사용 System.currentTimeMillis(). Clockjava.time에 새 인터페이스가 있지만 해당 인터페이스의 구현은 이전 밀리 초 시계와 동일합니다.

따라서 결과의 텍스트 표현을 형식화하여 ZonedDateTime.now( ZoneId.of( "America/Montreal" ) )분수 초의 9 자리를 볼 수 있지만 처음 세 자리 만 다음과 같은 숫자를 갖습니다.

2017-12-23T12:34:56.789000000Z

자바 9의 새로운 시계

Java 9의 OpenJDK 및 Oracle 구현 Clock에는 java.time 클래스의 최대 나노초 기능까지 세분화 된 새로운 기본 구현이 있습니다.

OpenJDK 문제, java.time.Clock.systemUTC () 구현의 정밀도 향상을 참조하십시오 . 이 문제는 성공적으로 구현되었습니다.

2017-12-23T12:34:56.123456789Z

macOS Sierra가 설치된 MacBook Pro (Retina, 15-inch, Late 2013)에서는 현재 순간을 마이크로 초 (소수점의 최대 6 자리)로 표시합니다.

2017-12-23T12:34:56.123456Z

하드웨어 시계

새롭고 미세한 Clock구현 이 있더라도 결과는 컴퓨터에 따라 다를 수 있습니다. Java는 현재 순간을 알기 위해 기본 컴퓨터 하드웨어의 시계에 의존합니다.

  • 하드웨어 시계 의 해상도 는 매우 다양합니다. 예를 들어, 특정 컴퓨터의 하드웨어 시계가 마이크로 초 단위 만 지원하는 경우 생성 된 모든 날짜-시간 값에는 마지막 세 자리가 0 인 분수 초의 6 자리 만 있습니다.
  • 하드웨어 시계 의 정확도 는 매우 다양합니다. 시계가 1 초의 소수 자릿수 몇 자릿수로 값을 생성하기 때문에 이러한 자릿수는 원자 시계 에서 읽을 수있는 실제 시간에서 벗어난 근사치 일 수 있습니다 . 다시 말해, 소수점 오른쪽에 숫자가 많다고해서 그러한 판독 값 사이의 경과 시간이 1 분 정도라고 믿을 수 있다는 의미는 아닙니다.

답변

다음을 사용할 수 있습니다 System.nanoTime().

long start = System.nanoTime();
// do stuff
long end = System.nanoTime();
long microseconds = (end - start) / 1000;

나노초 단위로 시간을 얻을 수 있지만 이는 엄격히 상대적인 측정입니다. 절대적인 의미가 없습니다. 다른 나노 시간과 비교하여 작업에 걸리는 시간을 측정하는 데만 유용합니다.


답변

다른 포스터가 이미 지적했듯이; 시스템 시계가 실제 세계 시간과 최대 마이크로 초까지 동기화되지 않았을 수 있습니다. 그럼에도 불구하고 마이크로 초 정밀도 타임 스탬프는 현재 벽 시간을 표시하고 사물의 지속 시간을 측정 / 프로파일 링하는 하이브리드로 유용합니다.

“2012-10-21 19 : 13 : 45.267128″과 같은 타임 스탬프를 사용하여 로그 파일에 기록 된 모든 이벤트 / 메시지에 레이블을 지정합니다. 이 둘을 전달 하는 경우 는 ( “벽”시간) 발생하고, 또한 측정하는 데 사용할 수있는 기간 이 로그 파일에 다음 이벤트 (마이크로 상대적 차이) 사이를.

이를 위해서는 System.currentTimeMillis ()를 System.nanoTime ()과 연결하고 그 순간부터 System.nanoTime ()으로 독점적으로 작업해야합니다. 예제 코드 :

/**
 * Class to generate timestamps with microsecond precision
 * For example: MicroTimestamp.INSTANCE.get() = "2012-10-21 19:13:45.267128"
 */
public enum MicroTimestamp
{  INSTANCE ;

   private long              startDate ;
   private long              startNanoseconds ;
   private SimpleDateFormat  dateFormat ;

   private MicroTimestamp()
   {  this.startDate = System.currentTimeMillis() ;
      this.startNanoseconds = System.nanoTime() ;
      this.dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS") ;
   }

   public String get()
   {  long microSeconds = (System.nanoTime() - this.startNanoseconds) / 1000 ;
      long date = this.startDate + (microSeconds/1000) ;
      return this.dateFormat.format(date) + String.format("%03d", microSeconds % 1000) ;
   }
}


답변

System.nanoTime ()과 System.currentTimeMillis () 사이의 오프셋을 결정하는 구성 요소를 만들고 epoch 이후 효과적으로 나노초를 얻을 수 있습니다.

public class TimerImpl implements Timer {

    private final long offset;

    private static long calculateOffset() {
        final long nano = System.nanoTime();
        final long nanoFromMilli = System.currentTimeMillis() * 1_000_000;
        return nanoFromMilli - nano;
    }

    public TimerImpl() {
        final int count = 500;
        BigDecimal offsetSum = BigDecimal.ZERO;
        for (int i = 0; i < count; i++) {
            offsetSum = offsetSum.add(BigDecimal.valueOf(calculateOffset()));
        }
        offset = (offsetSum.divide(BigDecimal.valueOf(count))).longValue();
    }

    public long nowNano() {
        return offset + System.nanoTime();
    }

    public long nowMicro() {
        return (offset + System.nanoTime()) / 1000;
    }

    public long nowMilli() {
        return System.currentTimeMillis();
    }
}

다음 테스트는 내 컴퓨터에서 상당히 좋은 결과를 생성합니다.

    final Timer timer = new TimerImpl();
    while (true) {
        System.out.println(timer.nowNano());
        System.out.println(timer.nowMilli());
    }

차이는 + -3ms 범위에서 진동하는 것처럼 보입니다. 오프셋 계산을 조금 더 조정할 수 있다고 생각합니다.

1495065607202174413
1495065607203
1495065607202177574
1495065607203
...
1495065607372205730
1495065607370
1495065607372208890
1495065607370
...


답변

Linux에 관심이있는 경우 : 소스 코드를 “currentTimeMillis ()”로 보내면 Linux에서이 메서드를 호출하면 마이크로 초 시간이 돌아옵니다. 그러나 Java는 마이크로 초를 자르고 밀리 초를 돌려줍니다. 이는 부분적으로 Java가 크로스 플랫폼이어야하므로 Linux 전용 메소드를 제공하는 것은 그날의 큰 일이 아니 었습니다 (1.6 이전 버전의 부드러운 소프트 링크 지원을 기억하십니까?!). 또한 클럭은 Linux에서 마이크로 초를 되돌릴 수 있지만 반드시 시간을 확인하는 데 좋은 것은 아닙니다. 마이크로 초 수준에서 NTP가 시간을 재정렬하지 않고 메서드 호출 중에 시계가 너무 많이 드리프트되지 않았 음을 알아야합니다.

이것은 이론적으로 Linux에서 시스템 패키지의 것과 동일하지만 마이크로 초를 자르지 않는 JNI 래퍼를 작성할 수 있음을 의미합니다.


답변

결국 내가 함께했던 “빠르고 더러운”솔루션 :

TimeUnit.NANOSECONDS.toMicros(System.nanoTime());

최신 정보:

원래 System.nanoTime을 사용했지만 경과 시간에만 사용해야한다는 것을 알았고 결국 밀리 초 또는 일부 장소에서 사용하도록 코드를 변경했습니다.

TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis());

그러나 이것은 값의 끝에 0을 추가합니다 (마이크로 = 밀리 * 1000)

다른 누군가가 nanoTime을 생각할 경우를 대비하여 여기에이 답변을 “경고 표시”로 남겨 두었습니다. 🙂