web-dev-qa-db-fra.com

Heure actuelle en microsecondes dans java

Sur un système Unix, existe-t-il un moyen d’obtenir un horodatage avec une précision de niveau microseconde en Java? Quelque chose comme la fonction gettimeofday de C.

97
Seth

Non, Java n'a pas cette capacité.

Il possède System.nanoTime (), mais cela ne fait que compenser l’heure connue. Ainsi, même si vous ne pouvez pas en prendre le nombre absolu, vous pouvez l’utiliser pour mesurer une précision à la nanoseconde (ou supérieure).

Notez que le JavaDoc indique que si cela fournit une précision nanoseconde, cela ne signifie pas une précision nanoseconde. Prenez donc un module suffisamment grand de la valeur de retour.

140
AlBlue

tl; dr

Java 9 et versions ultérieures: résolution jusqu’à quelques nanosecondes lors de la capture du moment actuel. C’est 9 chiffres de la fraction décimale.

Instant.now()   

2017-12-23T12: 34: 56.123456789Z

Pour limiter à microsecondes , tronquer.

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

Détails

Les autres réponses sont quelque peu obsolètes à partir de Java 8.

Java.time

Java 8 et versions ultérieures sont livrés avec le framework Java.time . Ces nouvelles classes supplantent les classes de date-heure problématiques livrées avec les versions les plus anciennes de Java telles que Java.util.Date/.Calendar et Java.text.SimpleDateFormat. Le cadre est défini par JSR 310, inspiré par Joda-Time , étendu par le projet ThreeTen-Extra.

Les classes de Java.time se résolvent en nanosecondes , bien plus fine que la millisecondes utilisée à la fois par les anciennes classes date-heure et par Joda-Time. Et plus fin que le microsecondes demandé dans la question.

enter image description here

Clock Implémentation

Bien que les classes Java.time prennent en charge les données représentant les valeurs en nanosecondes, elles ne génèrent pas encore de valeurs en nanosecondes. Les méthodes now() utilisent la même implémentation d'horloge ancienne que les anciennes classes date-heure, System.currentTimeMillis() . Nous avons la nouvelle interface Clock dans Java.time, mais l'implémentation de cette interface est la même horloge millisecondes.

Ainsi, vous pouvez formater la représentation textuelle du résultat de ZonedDateTime.now( ZoneId.of( "America/Montreal" ) ) pour afficher neuf chiffres d'une seconde fractionnelle, mais seuls les trois premiers chiffres portent les chiffres suivants:

2017-12-23T12:34:56.789000000Z

Nouvelle entrée d'horloge Java 9

Les implémentations OpenJDK et Oracle de Java 9 ont une nouvelle implémentation par défaut de Clock avec une granularité plus fine, jusqu’à la capacité maximale de la nanoseconde des classes Java.time.

Voir le problème OpenJDK, Augmentez la précision de l'implémentation de Java.time.Clock.systemUTC () . Ce problème a été mis en œuvre avec succès.

2017-12-23T12:34:56.123456789Z

Sur un MacBook Pro (Retina, 15 pouces, fin 2013) avec macOS Sierra, le moment actuel est exprimé en microsecondes (jusqu'à six chiffres de la fraction décimale).

2017-12-23T12:34:56.123456Z

Horloge matérielle

N'oubliez pas que même avec une nouvelle implémentation Clock plus fine, vos résultats peuvent varier d'un ordinateur à l'autre. Java dépend de l'horloge du matériel informatique sous-jacent pour connaître le moment actuel.

  • La résolution des horloges matérielles varie considérablement. Par exemple, si l’horloge matérielle d’un ordinateur particulier ne prend en charge que la granularité microsecondes , les valeurs date-heure générées n’auront que six chiffres de la fraction de seconde, les trois derniers chiffres étant des zéros.
  • La précision des horloges matérielles varie considérablement. Juste parce qu'une horloge génère une valeur avec plusieurs chiffres de fraction décimale de seconde, ces chiffres peuvent être inexacts, juste des approximations, à la dérive de l'heure réelle comme cela pourrait être lu à partir de horloge atomique . En d'autres termes, ce n'est pas parce que vous voyez des chiffres à droite de la marque décimale que vous pouvez faire confiance au temps écoulé entre ces lectures pour être fidèle à cette minute.
66
Basil Bourque

Vous pouvez utiliser System.nanoTime() :

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

obtenir le temps en nanosecondes mais c'est une mesure strictement relative. Cela n'a pas de sens absolu. Ce n'est utile que si vous comparez à d'autres nanotechnologies pour mesurer le temps qu'il faut à quelque chose.

54
cletus

Comme d'autres affiches l'ont déjà indiqué; votre horloge système n’est probablement pas synchronisée jusqu’à quelques microsecondes avec l’heure réelle. Néanmoins, les horodatages de précision en microsecondes sont utiles en tant qu'hybride pour indiquer le temps de paroi actuel et pour mesurer/profiler la durée des choses.

J'étiquette tous les événements/messages écrits dans un fichier journal en utilisant des horodatages tels que "2012-10-21 19: 13: 45.267128". Ceux-ci transmettent à la fois quand il s’est passé (heure du "mur"), et peuvent également être utilisés pour mesurer la durée entre cet événement et le prochain événement du fichier journal (différence relative entre microsecondes).

Pour ce faire, vous devez lier System.currentTimeMillis () à System.nanoTime () et utiliser exclusivement System.nanoTime () à partir de ce moment. Exemple de code:

/**
 * 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) ;
   }
}
14
Jason Smith

Vous pouvez éventuellement créer un composant qui détermine le décalage entre System.nanoTime () et System.currentTimeMillis () et obtenir efficacement des nanosecondes depuis 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();
    }
}

Suivre le test produit des résultats assez bons sur ma machine.

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

La différence semble osciller dans la plage de + -3ms. Je suppose que l'on pourrait modifier un peu plus le calcul de l'offset.

1495065607202174413
1495065607203
1495065607202177574
1495065607203
...
1495065607372205730
1495065607370
1495065607372208890
1495065607370
...
4
kangcz

une solution "rapide et sale" que je suis finalement allé avec:

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

MISE À JOUR:

J'avais initialement choisi System.nanoTime, mais j'ai alors découvert qu'il ne devait être utilisé que le temps écoulé. J'ai finalement modifié mon code pour qu'il fonctionne en millisecondes ou, à certains endroits, il utilise:

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

mais cela ne fera qu'ajouter des zéros à la fin de la valeur (micros = millis * 1000)

Laissé cette réponse ici comme un "panneau d'avertissement" au cas où quelqu'un pense à nanoTime :)

2
keisar

Si vous êtes intéressé par Linux: Si vous recherchez le code source dans "currentTimeMillis ()", vous verrez que, sous Linux, si vous appelez cette méthode, elle récupère une microseconde. Cependant Java tronque ensuite les microsecondes et vous restitue millisecondes. Ceci est en partie dû au fait que Java doit être multiplate-forme, de sorte que fournir des méthodes spécifiquement pour Linux -pas de retour dans la journée (rappelez-vous que la cruddy soft link support from 1.6 backwards?!) est également due au fait que, même si votre horloge peut vous redonner des microsecondes sous Linux, cela ne signifie pas nécessairement qu'il sera utile pour vérifier l'heure Au niveau de la microseconde, vous devez savoir que NTP ne réaligne pas votre heure et que votre horloge n’a pas trop dérivé pendant les appels de méthode.

Cela signifie qu'en théorie, sur Linux, vous pouvez écrire un wrapper JNI identique à celui du package System, mais ne pas tronquer les microsecondes.

2
zamhassam

Prise en charge de Java en microsecondes via TimeUnit enum.

Voici le Java doc: Enum TimeUnit

Vous pouvez obtenir des microsecondes dans Java de cette façon:

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

Vous pouvez également reconvertir les microsecondes dans une autre unité de temps, par exemple:

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

Si vous avez l’intention de l’utiliser pour un système en temps réel, peut-être Java n’est pas le meilleur choix pour obtenir l’horodatage. Mais si vous voulez utiliser une clé unique, la réponse de Jason Smith suffira. Mais Juste au cas où, pour anticiper 2 éléments finissent par avoir le même horodatage (c'est possible si ces 2 ont été traités presque simultanément), vous pouvez effectuer une boucle jusqu'à ce que le dernier horodatage ne soit pas égal à l'horodatage actuel.

String timestamp = new String();
do {
    timestamp = String.valueOf(MicroTimestamp.INSTANCE.get());
    item.setTimestamp(timestamp);
} while(lasttimestamp.equals(timestamp));
lasttimestamp = item.getTimestamp();
0
wingedcrown

Utilisez Instant pour calculer les microsecondes depuis Epoch:

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