Check if a date value was in DST or not?

Windows specific forum
oO0XX0Oo
User
User
Posts: 78
Joined: Thu Aug 10, 2017 7:35 am

Check if a date value was in DST or not?

Post by oO0XX0Oo »

Hi,

E.g. DirectoryEntryDate(hDir, #PB_Date_Modified) gets the date for a file / folder
without correcting it when the file / folder was created during the DaylightSaving time
(first sunday in april through the last sunday in october) so this date is one hour off.

Is it possible to check if such a date is in the range of DST for that year so that I could
add one hour to the date read by DirectoryEntryDate(hDir, #PB_Date_Modified) or GetFileDate()?

E.g.

Code: Select all

file name:_Serialized Data.txt | last modified date: 17.04.2016 13:26:24 | PB date: 1460899584

Code: Select all

Procedure.b IsDateInDayLightSavingTime(date)
  Protected.b result = #False
  ; Pseudocode
  If date >= DaylightDate for 2016 and date <= StandardDate for 2016
    result = #True
  EndIf

  ProcedureReturn result
EndProcedure

Code: Select all

Debug IsDateInDayLightSavingTime(1460899584)
Output: 1
User avatar
Sicro
Enthusiast
Enthusiast
Posts: 538
Joined: Wed Jun 25, 2014 5:25 pm
Location: Germany
Contact:

Re: Check if a date value was in DST or not?

Post by Sicro »

Calculations with date is a very caotic topic. As with the changeover from the julian calendar to the gregorian calendar,
there are also different regulations in many countries for the changeover from summer to winter time.

I don't know how far back in time you can go with native OS API date functions. Perhaps, the operating systems have
only for a limited period of time the regulations for changeover.

Maybe someone can use this as a base code and add support for arbitrary times to the function:
https://github.com/SicroAtGit/PureBasic ... ngTime.pbi
Image
Why OpenSource should have a license :: PB-CodeArchiv-Rebirth :: Pleasant-Dark (syntax color scheme) :: RegEx-Engine (compiles RegExes to NFA/DFA)
Manjaro Xfce x64 (Main system) :: Windows 10 Home (VirtualBox) :: Newest PureBasic version
User avatar
Pierre Bellisle
User
User
Posts: 35
Joined: Wed Jun 27, 2018 5:12 am

Re: Check if a date value was in DST or not?

Post by Pierre Bellisle »

"Is it possible to check if such a date is in the range of DST for that year"

To some extent: Yes.

First, if the file system where the file reside is NTFS then the time will be UTC.
If it's a FAT file system, the time will be the computer local time.
GetVolumeInformation() give file system.

See GetTimeZoneInformation() to get computer time zone.
Lets use "Eastern Standard Time" for now...
In the registry, at
"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\Eastern Standard Time\"
you will see a "TZI" value that represent the current daylight start and end in REG_TZI_FORMAT.
In the sub key "Dynamic DST" you will see for many time zone a "FirstEntry" and a "LastEntry"
representing the years covered by this registry branches.
For each year entry, like "2006", "2007",
you will get a "TZI" value that represent the new daylight dates for that year and up.

A "TZI" registry entry is related to TIME_ZONE_INFORMATION.
Read: https://msdn.microsoft.com/en-us/librar ... s.85).aspx
Creating a Tzi function to parse all elements is a good idea in my view.
An important thing about TZI is that both SYSTEMTIME\wDay means the week of the month, from 1 to 5.
If 5, this indicates the last week of the month, Fifth week or fourth week if there is no fifth.
So you can have something like: The first Sunday of the third week in may.

So, long story short:
Is disk FAT or NTFS?
Get File date.
Current year is current "TZI" else for previous year,
enumerate and check "Dynamic DST" registry entry for a valid year span.
If the file year is within a "Dynamic DST" year range then
you know the start and ending daylight date plus the offset time in minutes.

Depending on the OS compatibility you want, some APIs may make life easier...
GetSystemTimeAdjustment 2000+ Determines whether the system is applying periodic time adjustments to its time-of-day clock.
SystemTimeToTzSpecificLocalTime 2000+ Converts a UTC time to a specified time zone's corresponding local time.
SystemTimeToTzSpecificLocalTimeEx Win7+ Converts a UTC time with dynamic daylight saving time settings to a specified time zone's corresponding local time.
TzSpecificLocalTimeToSystemTime XP+ Converts a local time to a UTC time.
TzSpecificLocalTimeToSystemTimeEx Win7+ Converts a local time with dynamic daylight saving time settings to UTC time.
EnumDynamicTimeZoneInformation Win8+ Enumerates dynamic daylight saving time information entries stored in the registry.
GetDynamicTimeZoneInformation Vista+ Retrieves the current time zone and dynamic daylight saving time settings.
GetTimeZoneInformationForYear Vista+ Retrieves the time zone settings for the specified year and time zone.
Last edited by Pierre Bellisle on Thu Jun 28, 2018 3:43 pm, edited 1 time in total.
Micoute
User
User
Posts: 24
Joined: Sat Jun 22, 2013 4:06 pm
Location: La Mézière FRANCE

Re: Check if a date value was in DST or not?

Post by Micoute »

Good morning,
The code is written in French, but I think you'll understand the basics.

Code: Select all

Macro Bissextile(Annee)
  Bool(((Not Year(Annee)%4)And Year(Annee)%100)Or(Not Year(Annee)%400))
EndMacro
Procedure.b JoursDansMois(Annee=-1,Mois=-1)
  ;Retourne le nombre de jours dans le mois donné (28..31)
  ;Si l'année est absente, l'année en cours est utilisée
  ;Si l'année est présente mais le mois est absent,février est utilisé
  ;Si l'année et le mois sont tous deux absents, le mois courant de l'année en cours est utilisé
  
  Protected Jours
  
  If Annee = -1
    Annee=Year(Date())
    If Mois = -1
      Mois=Month(Date())
    EndIf
  Else
    If Mois <= 0 : Mois = 2 : EndIf
  EndIf
  
  If Mois=2
    If Bissextile(Annee)
      Jours=29
    Else
      Jours=28
    EndIf
  Else
    jours=31 - $A55 >> Mois & 1
  EndIf
  
  NbjoursMois=Jours
  
  ProcedureReturn NbjoursMois
EndProcedure
Procedure TrouverPremierDimanche(Annee,Mois)
  Protected Jour=1
  Protected DatePremierDimanche=Date(Annee,Mois,Jour,0,0,0)
  
  ;Cherche le premier dimanche
  While DayOfWeek(DatePremierDimanche)<>0
    
    Jour+1
    DatePremierDimanche=Date(Annee,Mois,Jour,0,0,0)
  Wend
  
  ProcedureReturn DatePremierDimanche
  
EndProcedure
Procedure TrouverDeuxiemeDimanche(Annee,Mois)
  Protected Jour=8
  Protected DateDeuxiemeDimanche=Date(Annee,Mois,Jour,0,0,0)
  
  ;Cherche le deuxième dimanche
  While DayOfWeek(DateDeuxiemeDimanche)<>0
    
    Jour+1
    DateDeuxiemeDimanche=Date(Annee,Mois,Jour,0,0,0)
  Wend
  
  ProcedureReturn DateDeuxiemeDimanche
  
EndProcedure
Procedure TrouverTroisiemeDimanche(Annee,Mois)
  Protected Jour=15
  Protected DateTroisiemeDimanche=Date(Annee,Mois,Jour,0,0,0)
  
  ;Cherche le Troisième dimanche
  While DayOfWeek(DateTroisiemeDimanche)<>0
    
    Jour+1
    DateTroisiemeDimanche=Date(Annee,Mois,Jour,0,0,0)
  Wend
  
  ProcedureReturn DateTroisiemeDimanche
  
EndProcedure
Procedure TrouverQuatriemeDimanche(Annee,Mois)
  Protected Jour=22
  Protected DateQuatriemeDimanche=Date(Annee,Mois,Jour,0,0,0)
  
  ;Cherche le Quatrième dimanche
  While DayOfWeek(DateQuatriemeDimanche)<>0
    
    Jour+1
    DateQuatriemeDimanche=Date(Annee,Mois,Jour,0,0,0)
  Wend
  
  ProcedureReturn DateQuatriemeDimanche
  
EndProcedure
Procedure TrouverDernierDimanche(Annee,Mois)
  Protected Jour=JoursDansMois() - 6
  Protected DateDernierDimanche=Date(Annee,Mois,Jour,0,0,0)
  
  ;Cherche le dernier dimanche
  While DayOfWeek(DateDernierDimanche)<>0
    
    Jour+1
    DateDernierDimanche=Date(Annee,Mois,Jour,0,0,0)
  Wend 
  ProcedureReturn DateDernierDimanche 
  
EndProcedure
Procedure Heure_d_ete(Annee=-1)
  Protected Resultat = TrouverDernierDimanche(Annee,3)
  If Resultat = -1
    Resultat = TrouverQuatriemeDimanche(Annee,3)
  EndIf  
  ProcedureReturn Resultat
EndProcedure
Procedure Heure_d_hiver(Annee=-1)
  Protected Resultat
  Resultat = TrouverDernierDimanche(Annee,10)
  If Resultat = -1
    Resultat = TrouverQuatriemeDimanche(Annee,10)
  EndIf  
  ProcedureReturn Resultat
EndProcedure

Debug FormatDate("%dd/%mm/%yyyy", Heure_d_ete(2018))
Debug FormatDate("%dd/%mm/%yyyy", Heure_d_hiver(2018))
Post Reply