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.
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.
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
Les autres réponses sont quelque peu obsolètes à partir de Java 8.
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.
Clock
ImplémentationBien 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
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
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.
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.
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) ;
}
}
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
...
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 :)
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.
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);
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();
Utilisez Instant pour calculer les microsecondes depuis Epoch:
val instant = Instant.now();
val currentTimeMicros = instant.getEpochSecond() * 1000_000 + instant.getNano() / 1000;