Unix 시스템에서 Java에서 마이크로 초 수준의 정확도로 타임 스탬프를 얻을 수있는 방법이 있습니까? C의 gettimeofday
기능 과 같은 것 .
Instant.now()
val instant = Instant.now();
val currentTimeMicros = instant.getEpochSecond() * 1000_000 + instant.getNano() / 1000;
Unix 시스템에서 Java에서 마이크로 초 수준의 정확도로 타임 스탬프를 얻을 수있는 방법이 있습니까? C의 gettimeofday
기능 과 같은 것 .
Instant.now()
val instant = Instant.now();
val currentTimeMicros = instant.getEpochSecond() * 1000_000 + instant.getNano() / 1000;
답변:
아니요, Java에는 그러한 기능이 없습니다.
System.nanoTime ()이 있지만 이전에 알려진 시간에서 오프셋을 제공합니다. 따라서 여기에서 절대 숫자를 가져올 수는 없지만 나노초 (또는 더 높은) 정밀도를 측정하는 데 사용할 수 있습니다.
JavaDoc은 이것이 나노초 정밀도를 제공하지만 나노초 정밀도를 의미하지는 않는다고 말합니다. 따라서 반환 값의 적절하게 큰 계수를 사용하십시오.
Clock
밀리 초보다 더 미세한 해상도로 현재 순간을 캡처 할 수 있는 새로운 구현이 함께 제공됩니다. MacBook Pro Retina에서 현재 시간을 마이크로 초 (소수점 6 자리)로 표시합니다. 실제 결과와 정확도는 호스트 컴퓨터의 기본 클럭 하드웨어에 따라 다릅니다.
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 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
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는 현재 순간을 알기 위해 기본 컴퓨터 하드웨어의 시계에 의존합니다.
Clock
. 그럼에도 불구하고 Java 8에서 java.time 클래스는 Postgres 데이터베이스의 마이크로 초와 같은 다른 소스에서 캡처 한 값을 보유하는 데 유용합니다. 그러나 마이크로 초 및 나노초 범위의 값이 부정확함에 유의하십시오. 일반적인 컴퓨터 하드웨어는 하드웨어 시계 추적 시간을 정확하게 전달하지 못할 수 있습니다. 6 자리 또는 9 자리 소수 초를 가진 값은 참이 아닐 수 있습니다.
다음을 사용할 수 있습니다 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) ;
}
}
MicroTimestamp.INSTANCE.get()
이 문제가 될 수 있습니다.
get()
메소드에는 멤버 변수를 업데이트하는 것이 없습니다 . 임시 지역 변수 만 사용합니다.
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을 생각할 경우를 대비하여 여기에이 답변을 "경고 표시"로 남겨 두었습니다. :)
System.nanoTime
. "이 방법은 경과 시간을 측정하는 데만 사용할 수 있으며 시스템 또는 벽시계 시간의 다른 개념과 관련이 없습니다."
Java 지원 마이크로 초 TimeUnit
enum을 합니다.
다음은 자바 문서입니다. Enum TimeUnit
다음과 같이 자바에서 마이크로 초를 얻을 수 있습니다.
long microsenconds = TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis());
마이크로 초를 다시 다른 시간 단위로 변환 할 수도 있습니다. 예를 들면 다음과 같습니다.
long seconds = TimeUnit.MICROSECONDS.toSeconds(microsenconds);
실시간 시스템에 사용하려는 경우 아마도 java가 타임 스탬프를 얻는 최선의 선택이 아닙니다. 그러나 고유 키에 if를 사용하려는 경우 Jason Smith의 답변으로 충분합니다. 그러나 두 항목이 동일한 타임 스탬프를 얻게 될 것으로 예상하기 위해 (이 두 항목이 거의 동시에 처리 된 경우 가능) 마지막 타임 스탬프가 현재 타임 스탬프와 같지 않을 때까지 반복 할 수 있습니다.
String timestamp = new String();
do {
timestamp = String.valueOf(MicroTimestamp.INSTANCE.get());
item.setTimestamp(timestamp);
} while(lasttimestamp.equals(timestamp));
lasttimestamp = item.getTimestamp();
다음은 UnsignedLong 현재 타임 스탬프를 만드는 방법의 예입니다.
UnsignedLong current = new UnsignedLong(new Timestamp(new Date().getTime()).getTime());