Comment puis-je obtenir l'heure système Windows avec une résolution en millisecondes?
Si ce qui précède n'est pas possible, comment puis-je obtenir l'heure de démarrage du système d'exploitation? Je voudrais utiliser cette valeur avec timeGetTime () afin de calculer une heure système avec une résolution de la milliseconde.
Merci d'avance.
GetTickCount
ne le fera pas pour vous.
Regardez dans QueryPerformanceFrequency
/QueryPerformanceCounter
. Le seul truc à obtenir ici est la mise à l'échelle du processeur, alors faites vos recherches.
Essayez cet article de MSDN Magazine. C'est en fait assez compliqué.
Implémentez un fournisseur de temps haute résolution et à mise à jour continue pour Windows
Ceci est une élaboration des commentaires ci-dessus pour expliquer certains des pourquoi.
Premièrement, les appels GetSystemTime * sont les seules API Win32 fournissant l’heure du système. Cette fois, la granularité est assez grossière, car la plupart des applications n'ont pas besoin de la surcharge nécessaire pour conserver une résolution plus élevée. Le temps est (probablement) stocké en interne sous la forme d'un nombre de millisecondes sur 64 bits. L'appel de timeGetTime obtient les 32 bits de poids faible. L'appel de GetSystemTime, etc. demande à Windows de renvoyer cette milliseconde après la conversion en jours, etc. et en indiquant l'heure de démarrage du système.
Il existe deux sources de temps dans une machine: l'horloge de la CPU et une horloge intégrée (par exemple, l'horloge en temps réel (RTC), les temporisations à intervalles programmables (PIT) et la minuterie d'événements haute précision (HPET)). Le premier a une résolution d'environ ~ 0,5 ns (2 GHz) et le second est généralement programmable jusqu'à une période de 1 ms (bien que les puces plus récentes (HPET) aient une résolution plus élevée). Windows utilise ces ticks périodiques pour effectuer certaines opérations, notamment la mise à jour de l'heure système.
Les applications peuvent modifier cette période via timerBeginPeriod ; Cependant, cela affecte tout le système. Le système d'exploitation vérifiera/mettra à jour les événements réguliers à la fréquence demandée. Sous faibles charges/fréquences du processeur, il existe des périodes d'inactivité pour les économies d'énergie. Aux hautes fréquences, il n’ya pas de temps pour placer le processeur dans des états de faible consommation. Voir Résolution du minuteur pour plus de détails. Enfin, chaque tick entraîne une surcharge et l’augmentation de la fréquence consomme plus de cycles de la CPU.
Pour un temps de résolution plus élevé, le temps système n'est pas maintenu avec cette précision, pas plus que Big Ben n'a une seconde main. L'utilisation de QueryPerformanceCounter (QPC) ou des ticks du processeur (rdtsc) peut fournir la résolution entre les ticks horaires du système. Une telle approche a été utilisée dans l'article du magazine MSDN cité par Kevin. Bien que ces approches puissent avoir une dérive (due, par exemple, à l’échelle de fréquence), etc., elles doivent donc être synchronisées avec l’heure du système.
À partir de Windows 8, Microsoft a introduit la nouvelle commande API GetSystemTimePreciseAsFileTime:
https://msdn.Microsoft.com/en-us/library/windows/desktop/hh706895%28v=vs.85%29.aspx
Malheureusement, vous ne pouvez pas l'utiliser si vous créez un logiciel qui doit également fonctionner sur des systèmes d'exploitation plus anciens.
Ma solution actuelle est la suivante, mais sachez que l'heure déterminée n'est pas exacte, elle est seulement proche de l'heure réelle. Le résultat doit toujours être inférieur ou égal au temps réel, mais avec une erreur corrigée (à moins que l'ordinateur ne se mette en veille). Le résultat a une résolution en millisecondes. Pour moi, c'est assez exact.
void GetHighResolutionSystemTime(SYSTEMTIME* pst)
{
static LARGE_INTEGER uFrequency = { 0 };
static LARGE_INTEGER uInitialCount;
static LARGE_INTEGER uInitialTime;
static bool bNoHighResolution = false;
if(!bNoHighResolution && uFrequency.QuadPart == 0)
{
// Initialize performance counter to system time mapping
bNoHighResolution = !QueryPerformanceFrequency(&uFrequency);
if(!bNoHighResolution)
{
FILETIME ftOld, ftInitial;
GetSystemTimeAsFileTime(&ftOld);
do
{
GetSystemTimeAsFileTime(&ftInitial);
QueryPerformanceCounter(&uInitialCount);
} while(ftOld.dwHighDateTime == ftInitial.dwHighDateTime && ftOld.dwLowDateTime == ftInitial.dwLowDateTime);
uInitialTime.LowPart = ftInitial.dwLowDateTime;
uInitialTime.HighPart = ftInitial.dwHighDateTime;
}
}
if(bNoHighResolution)
{
GetSystemTime(pst);
}
else
{
LARGE_INTEGER uNow, uSystemTime;
{
FILETIME ftTemp;
GetSystemTimeAsFileTime(&ftTemp);
uSystemTime.LowPart = ftTemp.dwLowDateTime;
uSystemTime.HighPart = ftTemp.dwHighDateTime;
}
QueryPerformanceCounter(&uNow);
LARGE_INTEGER uCurrentTime;
uCurrentTime.QuadPart = uInitialTime.QuadPart + (uNow.QuadPart - uInitialCount.QuadPart) * 10000000 / uFrequency.QuadPart;
if(uCurrentTime.QuadPart < uSystemTime.QuadPart || abs(uSystemTime.QuadPart - uCurrentTime.QuadPart) > 1000000)
{
// The performance counter has been frozen (e. g. after standby on laptops)
// -> Use current system time and determine the high performance time the next time we need it
uFrequency.QuadPart = 0;
uCurrentTime = uSystemTime;
}
FILETIME ftCurrent;
ftCurrent.dwLowDateTime = uCurrentTime.LowPart;
ftCurrent.dwHighDateTime = uCurrentTime.HighPart;
FileTimeToSystemTime(&ftCurrent, pst);
}
}
Sous Windows, la base de tous les temps est une fonction appelée GetSystemTimeAsFiletime
name__.
La structure FILETIME
enregistre le nombre d'intervalles de 100ns depuis le 1er janvier 1600; ce qui signifie que sa résolution est limitée à 100ns.
Ceci forme notre première fonction:
Un nombre de ticks de 100 ns sur 64 bits depuis le 1er janvier 1600 est un peu difficile à manier. Windows fournit une fonction d'assistance très utile, FileTimeToSystemTime
name__, qui permet de décoder cet entier 64 bits en parties utiles:
record SYSTEMTIME {
wYear: Word;
wMonth: Word;
wDayOfWeek: Word;
wDay: Word;
wHour: Word;
wMinute: Word;
wSecond: Word;
wMilliseconds: Word;
}
Notez que SYSTEMTIME
a une limitation de résolution intégrée de 1ms
Nous avons maintenant un moyen de passer de FILETIME
à SYSTEMTIME
name__:
Nous pourrions écrire la fonction pour obtenir l'heure système actuelle sous la forme d'une structure SYSTEIMTIME
name__:
SYSTEMTIME GetSystemTime()
{
//Get the current system time utc in it's native 100ns FILETIME structure
FILETIME ftNow;
GetSytemTimeAsFileTime(ref ft);
//Decode the 100ns intervals into a 1ms resolution SYSTEMTIME for us
SYSTEMTIME stNow;
FileTimeToSystemTime(ref stNow);
return stNow;
}
Sauf que Windows a déjà écrit une telle fonction pour vous: GetSystemTime
NAME_
Maintenant, que se passe-t-il si vous ne voulez pas l'heure actuelle en UTC. Et si vous le voulez dans votre heure locale? Windows fournit une fonction permettant de convertir un FILETIME
au format UTC en votre heure locale: FileTimeToLocalFileTime
name__
Vous pourriez écrire une fonction qui vous renvoie déjà un FILETIME
dans local time:
FILETIME GetLocalTimeAsFileTime()
{
FILETIME ftNow;
GetSystemTimeAsFileTime(ref ftNow);
//convert to local
FILETIME ftNowLocal
FileTimeToLocalFileTime(ftNow, ref ftNowLocal);
return ftNowLocal;
}
Et disons que vous voulez décoder le local FILETIME en SYSTEMTIME. Ce n'est pas un problème, vous pouvez à nouveau utiliser FileTimeToSystemTime
name__:
Heureusement, Windows vous fournit déjà une fonction qui vous renvoie la valeur:
Il y a une autre considération. Avant Windows 8, l'horloge avait une résolution d'environ 15 ms. Sous Windows 8, l’horloge a été améliorée à 100 ns (ce qui correspond à la résolution de FILETIME
name__).
GetSystemTimeAsFileTime
name__ (hérité, résolution 15ms) GetSystemTimeAsPreciseFileTime
name__ (Windows 8, résolution 100ns) Cela signifie que nous devrions toujours préférer la nouvelle valeur:
Vous avez demandé l'heure; mais vous avez des choix.
Le fuseau horaire:
Le format:
FILETIME
name__ (système natif, résolution 100ns) SYTEMTIME
name__ (décodé, résolution 1ms) FILETIME
name __ GetSytemTimeAsPreciseFileTime
name__ (ou GetSystemTimeAsFileTime
name__) SYSTEMTIME
name __ GetSystemTime
name__GetLocalTime
name__GetSystemTimeAsFileTime donne la meilleure précision de toute fonction Win32 pour le temps absolu. QPF/QPC, comme le suggérait Joel Clark, donnera un meilleur temps relatif.
Puisque nous venons tous ici pour des extraits rapides au lieu d'explications ennuyeuses, je vais en écrire un:
FILETIME t;
GetSystemTimeAsFileTime(&t); // unusable as is
ULARGE_INTEGER i;
i.LowPart = t.dwLowDateTime;
i.HighPart = t.dwHighDateTime;
int64_t ticks_since_1601 = i.QuadPart; // now usable
int64_t us_since_1601 = (i.QuadPart * 1e-1);
int64_t ms_since_1601 = (i.QuadPart * 1e-4);
int64_t sec_since_1601 = (i.QuadPart * 1e-7);
// unix Epoch
int64_t unix_us = (i.QuadPart * 1e-1) - 11644473600LL * 1000000;
int64_t unix_ms = (i.QuadPart * 1e-4) - 11644473600LL * 1000;
double unix_sec = (i.QuadPart * 1e-7) - 11644473600LL;
// i.QuadPart is # of 100ns ticks since 1601-01-01T00:00:00Z
// difference to Unix Epoch is 11644473600 seconds (attention to units!)
Aucune idée de la façon dont les réponses basées sur les compteurs de performance ont évolué, ne faites pas de bugs de glissement, les gars.
QueryPerformanceCounter () est conçu pour une résolution de minuterie fine.
Il s'agit du minuteur de résolution le plus élevé du système que vous pouvez utiliser dans le code de votre application pour identifier les goulots d'étranglement des performances.
Voici une implémentation simple pour les développeurs C #:
[DllImport("kernel32.dll")]
extern static short QueryPerformanceCounter(ref long x);
[DllImport("kernel32.dll")]
extern static short QueryPerformanceFrequency(ref long x);
private long m_endTime;
private long m_startTime;
private long m_frequency;
public Form1()
{
InitializeComponent();
}
public void Begin()
{
QueryPerformanceCounter(ref m_startTime);
}
public void End()
{
QueryPerformanceCounter(ref m_endTime);
}
private void button1_Click(object sender, EventArgs e)
{
QueryPerformanceFrequency(ref m_frequency);
Begin();
for (long i = 0; i < 1000; i++) ;
End();
MessageBox.Show((m_endTime - m_startTime).ToString());
}
Si vous êtes un développeur C/C++, consultez la page suivante: http://support.Microsoft.com/kb/815668
Celle-ci est très ancienne, mais il existe une autre fonction utile dans la bibliothèque Windows C _ftime
, qui renvoie une structure avec l'heure locale time_t
, millisecondes, fuseau horaire et indicateur d'heure avancée.