Conversion entre Date Universelle GMT et Date Localisée, puis correction de date extraite du DOS

Boostez vos compétences Excel avec notre communauté !

Rejoignez Excel Downloads, le rendez-vous des passionnés où l'entraide fait la force. Apprenez, échangez, progressez – et tout ça gratuitement ! 👉 Inscrivez-vous maintenant !

Lu76Fer

XLDnaute Occasionnel
Source : http://www.cpearson.com/excel/TimeZoneAndDaylightTime.aspx

Bonjour,

Les dates et heures des fichiers affichées sur l'explorateur ne sont pas exactement les mêmes que celles stockées en mémoire, la raison pour laquelle un décalage existe est l'existence de fuseau horaire, d'une heure d'été et aussi de l'échange de fichier sur le réseau mondial. Afin de savoir qu'elle est la date complète (Date et Heure) d'un fichier qu'elle que soit son origine géographique les dates sont toujours enregistrées avec sa valeur GMT(fuseau horaire d'origine : +0) et bien sûr sans correction pour l'heure d'été (si le fichier est dans la période de l'heure d'été).​

Pour ma part, je ne connaissais pas cette spécificité avant de me lancer sur un petit projet sur lequel j'ai remarqué des décalages entre les dates affichées sous DOS et celles affichées dans l'explorateur de Windows. Pour corriger ses erreurs de date, j'ai trouvé un tutoriel publié par C. Pearson, et la fonction qui permet de réaliser parfaitement cette conversion est SystemTimeToTzSpecificLocalTime, et il existe sa fonction inverse TzSpecificLocalTimeToSystemTime. Ces fonctions sont capables d'utiliser les données systèmes pour connaître le décalage horaire propre à notre installation de Windows ainsi que de déterminer si la Date convertie fait partie ou non d'une période de l'heure d'été quelque soit l'année concernée !​

I - Simple Conversion
Mise en oeuvre d'une fonction de conversion d'une date GMT vers une date local dans un module que je nomme 'LibTime' :
VB:
'''''''''''''''''''''''''''''''''''''''''''''''''''''
' Types
'''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Type SYSTEMTIME
    wYear As Integer
    wMonth As Integer
    wDayOfWeek As Integer
    wDay As Integer
    wHour As Integer
    wMinute As Integer
    wSecond As Integer
    wMilliseconds As Integer
End Type

Private Type TIME_ZONE_INFORMATION
    Bias As Long
    StandardName(0 To 31) As Integer
    StandardDate As SYSTEMTIME
    StandardBias As Long
    DaylightName(0 To 31) As Integer
    DaylightDate As SYSTEMTIME
    DaylightBias As Long
End Type

'''''''''''''''''''''''''''''''''''''''''''''''''''''
' Windows API Declares
'''''''''''''''''''''''''''''''''''''''''''''''''''''
#If VBA7 Then
   Private Declare PtrSafe Function GetTimeZoneInformation Lib "kernel32" (lpTimeZoneInformation As TIME_ZONE_INFORMATION) As Long
   Private Declare PtrSafe Function SystemTimeToTzSpecificLocalTime Lib "kernel32" (lpTimeZoneInformation As TIME_ZONE_INFORMATION, lpUniversalTime As SYSTEMTIME, lpLocalTime As SYSTEMTIME) As Long
#Else
   Private Declare Function GetTimeZoneInformation Lib "kernel32" (lpTimeZoneInformation As TIME_ZONE_INFORMATION) As Long
   Private Declare Function SystemTimeToTzSpecificLocalTime Lib "kernel32" (lpTimeZoneInformation As TIME_ZONE_INFORMATION, lpUniversalTime As SYSTEMTIME, lpLocalTime As SYSTEMTIME) As Long
#End If

'Converti une date dDate en type SYSTEMTIME
Private Function DateToSystemTime(dDate As Date) As SYSTEMTIME
    With DateToSystemTime
        .wYear = VBA.Year(dDate)
        .wMonth = VBA.Month(dDate)
        .wDay = VBA.Day(dDate)
        .wHour = VBA.Hour(dDate)
        .wMinute = VBA.Minute(dDate)
        .wSecond = VBA.Second(dDate)
        .wMilliseconds = 0
    End With
End Function

'Converti une date complète de type SYSTEMTIME en Date
Private Function SystemTimeToDate(stDate As SYSTEMTIME) As Date
    With stDate
        SystemTimeToDate = DateSerial(.wYear, .wMonth, .wDay) + TimeSerial(.wHour, .wMinute, .wSecond)
    End With
End Function

'*****************
'** P U B L I C **
'*****************
'Converti une date dateGMT universelle(GMT) en Date Local.
'(tenant compte du fuseau horaire et du changement d'heure)
'  Préalable : lancer 'InitDosCorAndTZI'
Function GMTDateToLocalDate(dateGMT As Date) As Date
Dim localST As SYSTEMTIME, gmtST As SYSTEMTIME
Dim parTZI As TIME_ZONE_INFORMATION
   'Paramètres utiles pour la fonction SystemTimeToTzSpecificLocalTime
   GetTimeZoneInformation parTZI
   'Conversion
   gmtST = DateToSystemTime(dateGMT)
   SystemTimeToTzSpecificLocalTime parTZI, gmtST, localST
   GMTDateToLocalDate = SystemTimeToDate(localST)
End Function
Test de la fonction dans un module "Samples" :​
VB:
Sub ExConvDateToLocalDate()
Dim dGMT As Date
   dGMT = "07/02/2025 10:00"  '+1H pour le fuseau de France
   Debug.Print "Date Locale : " & GMTDateToLocalDate(dGMT)
   dGMT = "07/04/2025 10:00"  '+1H pour le fuseau de France, +1H pour l'heure d'été
   Debug.Print "Date Locale : " & GMTDateToLocalDate(dGMT)
End Sub


II - Correction d'une date issue d'une commande sous DOS

Pour préciser, il s'agit de corriger des dates extraites via l'interpréteur de commande DOS à partir de la commande 'DIR'. Avant de passer à la solution, je vous propose une petite séance d'observation d'une liste de fichier appartenant à un répertoire "D:\Test".​

Tout d'abord vue depuis l'explorateur Windows :

FilesInExplorer.jpg


Puis depuis l'interpréteur de commande :

D:\>date (Cette commande donne la date du jour)
05/02/2025
D:\>dir


Répertoire de D:\Test\

20/03/2020 17:12 1 182 190 AutorisationTravaux.pdf
29/03/2023 23:38 13 824 Classeur2.xls
20/03/2020 09:57 24 576 EMAIL_PRO.doc
22/07/2019 16:04 127 Lixxbail.txt
15/05/2020 15:39 72 030 Masques_Tissus.png


Et enfin depuis l'interpréteur de commande à une date du jour ultérieure :

D:\Test\>date
05/04/2025
D:\Test\>dir


Répertoire de D:\Test\

20/03/2020 18:12 1 182 190 AutorisationTravaux.pdf
30/03/2023 00:38 13 824 Classeur2.xls
20/03/2020 10:57 24 576 EMAIL_PRO.doc
22/07/2019 17:04 127 Lixxbail.txt
15/05/2020 16:39 72 030 Masques_Tissus.png


Avant de lire la suite je vous propose d'essayer de comprendre par vous-même quelles sont les raisons des décalages d'heure et de jour ...


Analyse du problème :

Le problème sur l'interpréteur Dos n'est pas dû au fait qu'il ne fait pas la conversion date GMT vers date locale mais qu'il le fait mal. Je précise également que j'ai pu faire ces mêmes obervations sous Windows 7 et 10. L'ajout du décalage en fonction du fuseau horaire est bien fait mais par contre la prise en compte du décalage en fonction du passage à l'heure d'été se fait non pas en considérant la date du fichier mais la date du jour !! C'est pour cela que dans la dernière sortie de l'interpréteur Dos du 05/04/2025, tous les fichiers ont une date décalée de +1h par rapport à la sortie Dos du 05/02/2025.​

Solution :
Pour corriger le problème étant donnée que la fonction système SystemTimeToTzSpecificLocalTime est parfaitement adaptée, il est préférable d'annuler la conversion faite par l'interpréteur de commande et convertir la date que je nommerai dDos en date GMT que je nommerai dGMT. Ensuite on converti simplement la date dGMT en date local ou dLoc. Mais avant tout, il faut déterminer la correction à appliquer qui permet de passer d'une date dDos à dGMT. Cette correction est toujours là même quelque soit la date à convertir car elle dépend du fuseau horaire qui ne change pas et de l'appartenance de la période de l'instant(Now) à l'heure d'été(+1h) ou d'hiver(0) qui ne change que deux fois par an. Pour cela il suffit de déterminer l'écart pour une date d = Now() entre sa conversion en date locale GMTDateToLocalDate(d) et elle même.

VB:
'Permet d'initialiser la correction à appliquer à une date DOS(cmd Dir) pour revenir à
'une date universelle(GMT).
Function GetDosDateCorrect() As Integer
Dim dGMT As Date, dLoc As Date
   dLoc = Now: dGMT = GMTDateToLocalDate(dLoc)
   GetDosDateCorrect = DateDiff("n", dGMT, dLoc)  'Détermine la diff. en minute
End Function

'Permet de corriger une date vDosDate généré par la fonction Dir sous DOS et
'renvoie sa valeur universelle (GMT)
Function DosDateToGMTDate(vDosDate As Variant) As Date
Dim dosCor As Integer
   'Récupérer la correction DOS à ajouter pour revenir à une Date GMT
   dosCor = GetDosDateCorrect
   'Ajoute la correction en minute
   DosDateToGMTDate = DateAdd("n", dosCor, vDosDate)
End Function

'Corrige une chaîne de date DOS(ex.:cmd Dir) vDosDate et la converti en Date Local.
'(tenant compte du fuseau horaire et du changement d'heure)
'  Préalable : lancer 'InitDosCorAndTZI'
Function DosDateToLocalDate(vDosDate As Variant) As Date
Dim localST As SYSTEMTIME, gmtST As SYSTEMTIME, dosCor As Integer, parTZI As TIME_ZONE_INFORMATION
   'Dos Date vers GMT Date
   gmtST = DateToSystemTime(DosDateToGMTDate(vDosDate))
   'Paramètres utiles pour la fonction SystemTimeToTzSpecificLocalTime
   GetTimeZoneInformation parTZI
   'Conversion Date GMT vers Date Local
   SystemTimeToTzSpecificLocalTime parTZI, gmtST, localST
   DosDateToLocalDate = SystemTimeToDate(localST)
End Function
Teste pour vérifier la fiabilité de la fonction de conversion. Attention si vous l'utilisez, pensez à rajouter un BreakPoint à l'endroit signalé dans la procédure afin de changer la date système :​
VB:
Sub ExConvDosDateToLocalDate()
Dim dDos As Date, sDos As String 'Date ou String, au choix.
'I/   Changer la Date Windows : 07/02/2025 (Heure d'Hiver)
   Debug.Print Now
   '1)'dGMT = "07/02/2015 10:00" '+1H pour le fuseau France
      dDos = "07/02/2015 11:00"
      Debug.Print "I/   1) " & DosDateToLocalDate(dDos)   '=> Loc = 07/02/2015 11:00
   '2)'dGMT = "07/07/2015 10:00" '+1H pour le fuseau France, +1H pour l'heure d'été
      dDos = "07/07/2015 11:00"  'Erreur !
      Debug.Print "     2) " & DosDateToLocalDate(dDos)   '=> Loc = 07/02/2015 12:00
Debug.Print "BREAKPOINT ! Changement de date du système"


'II/  Changer la Date Windows : 07/04/2025 (Heure d'Eté)
   Debug.Print Now
   '1)'dGMT = "07/02/2015 10:00" '+1H pour le fuseau France
      sDos = "07/02/2015 12:00"  'Erreur !
      Debug.Print "II/  1) " & DosDateToLocalDate(sDos)   '=> Loc = 07/02/2015 11:00
   '2)'dGMT = "07/07/2015 10:00" '+1H pour le fuseau France, +1H pour l'heure d'été
      sDos = "07/07/2015 12:00"
      Debug.Print "     2) " & DosDateToLocalDate(sDos)   '=> Loc = 07/02/2015 12:00
'==>    On retrouve les mêmes résultats entre le point I et II
End Sub
Optimisation :
Si on désire utiliser la fonction de conversion DosDateToLocalDate dans le cadre d'un traitement de masse, il sera préférable de passer les variables parTZI et dosCor en variables privées du module et de les déterminer par une procédure d'initialisation qui sera appelé une seule fois avant le traitement de masse.​
 
Dernière édition:
- Navigue sans publicité
- Accède à Cléa, notre assistante IA experte Excel... et pas que...
- Profite de fonctionnalités exclusives
Ton soutien permet à Excel Downloads de rester 100% gratuit et de continuer à rassembler les passionnés d'Excel.
Je deviens Supporter XLD
Retour