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


104

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


6
컴퓨터 시계는 그 정확도 수준에 가깝게 설정되어 있지 않습니다. 고정밀 동기화 절차를 설정하는 데 약간의 노력을 기울이지 않는 한 다른 컴퓨터의 두 시계는 일반적으로 최소한 몇 밀리 초 차이가 날 것입니다. (그런 것이 물리적으로 가능할 때). 나는 컴퓨터의 시간을 마이크로 초로 아는 것이 어떤 시점이 될지 상상할 수 없다. ( 한 대의 컴퓨터에서 정확하게 간격 을 측정하려는 경우 , 그것은 완벽하게 합리적이지만 전체 타임 스탬프는 필요하지 않습니다.)
David Z

2
또한 일부 Unix / Linux 버전은 마이크로 초 필드에 1 밀리 초 또는 10 밀리 초 단위 만 반환합니다.
Stephen C

간접적 인 방법은 현재 시간을 마이크로 초 단위로 캡처하는 Postgres와 같은 데이터베이스에 연결된 경우 JDBC 를 사용하는 것입니다.
Basil Bourque

2
Java 9 이상 :Instant.now()
Basil Bourque

Instant를 사용하여 Epoch 이후 마이크로 초를 계산합니다. val instant = Instant.now(); val currentTimeMicros = instant.getEpochSecond() * 1000_000 + instant.getNano() / 1000;
Michael M.

답변:


148

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

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

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


3
Java에 getTimeInMicroseconds ()가없는 이유에는 1) 많은 플랫폼에서 사용할 수없는 정확도, 2) 마이크로 초 호출에서 밀리 초 정확도를 반환하면 응용 프로그램 이식성 문제가 발생한다고 추측 할 수 있습니다.
Stephen C

9
Linux에서 System.nanoTime ()은 clock_gettime (CLOCK_MONOTONIC, _)을 호출합니다. Brian Oxley 는이 덩어리를 찾기 위해 Java의 소스 코드를 파헤 쳤습니다.
David Weber

7
이 답변은 이제 구식 입니다. Java 9의 OpenJDK 및 Oracle 구현에는 Clock밀리 초보다 더 미세한 해상도로 현재 순간을 캡처 할 수 있는 새로운 구현이 함께 제공됩니다. MacBook Pro Retina에서 현재 시간을 마이크로 초 (소수점 6 자리)로 표시합니다. 실제 결과와 정확도는 호스트 컴퓨터의 기본 클럭 하드웨어에 따라 다릅니다.
Basil Bourque

1
@BasilBourque 많은 시스템은 마이그레이션 할 필요가 없기 때문에 여전히 Java 8 또는 그 이전 버전에서 실행됩니다. 답변은 구식이지만 여전히 유용합니다.
Dragas

1
@Dragas 사실, 이 질문에 의해 요구되는 마이크로 초 단위의 현재 시간을 얻기 위해 그것들을 마이그레이션 할 필요 가있을 입니다.
Basil Bourque

78

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.currentTimeMillis를 기반으로하므로 끝에 0을 추가합니다. 마이크로 / 나노 초 단위로 시간을 얻으려는 경우 전혀 도움이되지 않습니다. 사용자는 수동으로 밀리 초 시간에 0을 추가 할 수 있습니다.
annedroiid

@annedroiid 나는 내 대답에서 그것을 다루었습니다. Java 8에서는 나노초 해상도로 순간을 저장할 수 있지만 현재 순간을 캡처 하는 것은 밀리 초 단위입니다. Java 9에서 Clock. 그럼에도 불구하고 Java 8에서 java.time 클래스는 Postgres 데이터베이스의 마이크로 초와 같은 다른 소스에서 캡처 한 값을 보유하는 데 유용합니다. 그러나 마이크로 초 및 나노초 범위의 값이 부정확함에 유의하십시오. 일반적인 컴퓨터 하드웨어는 하드웨어 시계 추적 시간을 정확하게 전달하지 못할 수 있습니다. 6 자리 또는 9 자리 소수 초를 가진 값은 참이 아닐 수 있습니다.
Basil Bourque

그렇지 않습니다 ChronoUnit.MICROS ?
Roland

@Roland 예, 이제 수정되었습니다. 감사합니다. 참고로 Stack Overflow에서 이러한 오류를 수정하기 위해 답변을 직접 편집 할 수 있습니다.
Basil Bourque

55

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

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

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


14

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

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

5
아이디어는 좋지만 가끔씩 다시 동기화해야합니다. 시스템 시간 (currentTime)과 CPU 시계 (nanoTime)는 서로 다른 하드웨어 시계를 기반으로하는 경우가 많기 때문에 동기화되지 않습니다. 또한 운영 체제의 시간 서버는 가능한 경우 외부 시간 원본과 시스템 시계를 다시 동기화합니다. 따라서 겉보기에 매우 정확한 수업은 시간이 지날 수있는 타임 스탬프를 생성합니다!
h2stein 2014

3
해당 코드는 스레드로부터 안전하지 않은 것 같습니다. 두 개의 동시 호출 MicroTimestamp.INSTANCE.get()이 문제가 될 수 있습니다.
아메드

@Ahmed 왜 코드가 스레드로부터 안전하지 않다고 생각합니까? get()메소드에는 멤버 변수를 업데이트하는 것이 없습니다 . 임시 지역 변수 만 사용합니다.
Jason Smith

6

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
...

2

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

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


2

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

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

최신 정보:

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

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

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

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


1
문서 는 벽시계 시간에 사용 하지 말라고 명시 적으로 말합니다 System.nanoTime. "이 방법은 경과 시간을 측정하는 데만 사용할 수 있으며 시스템 또는 벽시계 시간의 다른 개념과 관련이 없습니다."
Basil Bourque 2015

1
@BasilBourque 당신이 맞습니다.이 글을 쓴 후에 결국 내 코드를 발견하고 변경했지만 여기에서 업데이트하는 것을 잊었습니다. 댓글 감사합니다!
keisar 2015

2

Java 지원 마이크로 초 TimeUnit enum을 합니다.

다음은 자바 문서입니다. Enum TimeUnit

다음과 같이 자바에서 마이크로 초를 얻을 수 있습니다.

long microsenconds = TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis());

마이크로 초를 다시 다른 시간 단위로 변환 할 수도 있습니다. 예를 들면 다음과 같습니다.

long seconds = TimeUnit.MICROSECONDS.toSeconds(microsenconds);

이것은 정확하지 않습니다. MICRO 해상도 / 길이로 시간을 얻을 수 있지만 시간 자체는 항상 MILI 정확도로만 나타납니다 (마지막 3 자리 숫자는 항상 0 임).
Michalsx

0

실시간 시스템에 사용하려는 경우 아마도 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();

0

Instant를 사용하여 Epoch 이후 마이크로 초를 계산합니다.

val instant = Instant.now();
val currentTimeMicros = instant.getEpochSecond() * 1000_000 + instant.getNano() / 1000;


-3

다음은 UnsignedLong 현재 타임 스탬프를 만드는 방법의 예입니다.

UnsignedLong current = new UnsignedLong(new Timestamp(new Date().getTime()).getTime());

2
정답이 아닙니다. java.util.Date 클래스의 해상도는 질문에 지정된 마이크로 초가 아니라 밀리 초입니다. java.sql.Timestamp를 만들어도 추가 데이터를 공중에서 가져 오지 않습니다.
Basil Bourque
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.