Question

Je viens de croiser un comportement inattendu avec DateTime.UtcNow tout en faisant des tests unitaires. Il semble que lorsque vous appelez DateTime.Now/UtcNow en succession rapide, il semble vous redonner la même valeur pour un intervalle plus long que prévu du temps, plutôt que de capturer milliseconde plus précis.

Je sais qu'il ya une classe Chronomètre qui serait mieux adapté pour faire des mesures de temps précis, mais je suis curieux de savoir si quelqu'un pourrait expliquer ce comportement dans DateTime? Y at-il une précision officielle documentée pour DateTime.Now (par exemple, précise à moins de 50 ms?)? Pourquoi serait DateTime.Now être fait moins précis que ce que la plupart des horloges CPU pourraient gérer? Peut-être qu'il est juste conçu pour le processeur le plus petit dénominateur commun?

public static void Main(string[] args)
{
    var stopwatch = new Stopwatch();
    stopwatch.Start();
    for (int i=0; i<1000; i++)
    {
        var now = DateTime.Now;
        Console.WriteLine(string.Format(
            "Ticks: {0}\tMilliseconds: {1}", now.Ticks, now.Millisecond));
    }

    stopwatch.Stop();
    Console.WriteLine("Stopwatch.ElapsedMilliseconds: {0}",
        stopwatch.ElapsedMilliseconds);

    Console.ReadLine();
}
Était-ce utile?

La solution

  

Pourquoi serait DateTime.Now être fait moins précis que ce que la plupart des horloges CPU peuvent gérer?

Une bonne horloge doit être à la fois précis et précis ; ceux qui sont différents. Comme la vieille blague va, une horloge arrêtée est tout à fait exacte deux fois par jour, une horloge est jamais une minute précise lente à tout moment. Mais l'horloge une minute lente est toujours précis à la minute près, alors qu'une horloge arrêtée n'a pas de précision utile du tout.

Pourquoi le DateTime être précis , par exemple une microseconde quand il ne peut pas éventuellement être précis à la microseconde? La plupart des gens n'ont pas source de signaux horaires officiels qui sont exacts à la microseconde. Par conséquent, donner six chiffres après la virgule de précision , dont les cinq dernières qui sont déchets serait mensonge .

Rappelez-vous, le but de DateTime est de représentent une date et heure . timings de haute précision est pas du tout dans le but de DateTime; comme vous le notez, c'est le but de StopWatch. Le but de DateTime est de représenter une date et l'heure à des fins comme affichage de l'heure à l'utilisateur, le calcul du nombre de jours jusqu'à mardi prochain, et ainsi de suite.

En bref, « quelle heure est-il? » et « combien de temps cela at-il pris? » sont des questions complètement différentes; ne pas utiliser un outil conçu pour répondre à une question pour répondre à l'autre.

Merci pour la question; cela fera un bon article de blog! : -)

Autres conseils

La précision de DateTime est un peu spécifique au système, il est en cours d'exécution sur. La précision est liée à la vitesse d'un changement de contexte, qui a tendance à être d'environ 15 ou 16 ms. (Sur mon système, il est en fait environ 14 ms de mes tests, mais je l'ai vu certains ordinateurs portables où il est plus proche de 35-40 ms précision.)

Peter Bromberg a écrit un article sur le calendrier de code de haute précision en C #, qui traite de cette .

Je voudrais une Datetime.Now précise :), donc je cuit ce haut:

public class PreciseDatetime
{
    // using DateTime.Now resulted in many many log events with the same timestamp.
    // use static variables in case there are many instances of this class in use in the same program
    // (that way they will all be in sync)
    private static readonly Stopwatch myStopwatch = new Stopwatch();
    private static System.DateTime myStopwatchStartTime;

    static PreciseDatetime()
    {
        Reset();

        try
        {
            // In case the system clock gets updated
            SystemEvents.TimeChanged += SystemEvents_TimeChanged;
        }
        catch (Exception)
        {                
        }
    }

    static void SystemEvents_TimeChanged(object sender, EventArgs e)
    {
        Reset();
    }

    // SystemEvents.TimeChanged can be slow to fire (3 secs), so allow forcing of reset
    static public void Reset()
    {
        myStopwatchStartTime = System.DateTime.Now;
        myStopwatch.Restart();
    }

    public System.DateTime Now { get { return myStopwatchStartTime.Add(myStopwatch.Elapsed); } }
}

De MSDN vous trouverez que DateTime.Now a une approximative résolution de 10 millisecondes sur tous les systèmes d'exploitation NT.

La précision réelle dépend du matériel. Une meilleure précision peut être obtenue en utilisant QueryPerformanceCounter .

Pour ce que ça vaut, à court de vérifier réellement la source .NET, Eric Lippert a fourni un commentaire sur cette question SO disant que DateTime est seulement une précision de 30 ms environ. Le raisonnement pour ne pas être précis nanoseconde, dans ses paroles, est qu'il « n'a pas besoin d'être. »

De la documentation MSDN :

  

La résolution de cette propriété   dépend de la minuterie du système.

Ils affirment également que la résolution approximative sur Windows NT 3.5 et est plus tard 10 ms:)

  

La résolution de cette propriété dépend de la minuterie du système, qui   dépend du système d'exploitation sous-jacent. Il a tendance à être entre 0,5   et 15 millisecondes.

En conséquence, les appels répétés à la propriété maintenant dans un court intervalle de temps, comme dans une boucle, peut retourner la même valeur.

MSDN lien

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top