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()
. Clock
java.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을 생각할 경우를 대비하여 여기에이 답변을 “경고 표시”로 남겨 두었습니다. 🙂