Module de gestion des dates (comptage, férié, ...)

Partagez votre expérience de PureBasic avec les autres utilisateurs.
Avatar de l’utilisateur
GallyHC
Messages : 1703
Inscription : lun. 17/déc./2007 12:44

Module de gestion des dates (comptage, férié, ...)

Message par GallyHC »

Bonjour,

Voila une petite adaptation de certain code pour la gestion des dates. (peu être un petit problème au niveau du comptage des jours ouvrables), aucun site que j'ai regardé ne donne les mêmes information.

Code : Tout sélectionner

DisableASM
EnableExplicit

; ****************************************************************************

DeclareModule toDate
  
  Enumeration cDayCount
    #NoOption       = 0
    #NoWeekDay      = 1
    #BusinessDay    = 2
    #NoWorkingDay   = 3
    #PublicHoliday  = 4
  EndEnumeration  
  Enumeration cDayOfWeek
    #Sunday         = 0
    #Monday         = 1
    #Tuesday        = 2
    #Wednesday      = 3
    #Thursday       = 4
    #Friday         = 5
    #Saturday       = 6
  EndEnumeration
  
  Declare.i DayofDate             (DateDebut.s, DateFin.s, option.l = #NoOption, DayOff.l = #Sunday)
  Declare.b IsBisextile           (year.i)
  Declare.i ToDayInMonth          (month.i, year.i)
  Declare.b IsEndOfMonth          ()
  Declare.b IsPublicHoliday       (date.s)
   
EndDeclareModule

Module toDate
  
  DisableASM
  EnableExplicit

  ; ****************************************************************************
  
  ; Permet de savoir si une date est valide ou non.
  ;
  ; @author GallyHomeCorp
  ; @param Date
  ; @return
  Procedure.b IsValidDate(Date.s)
    
    Date = FormatDate("%dd/%mm/%yyyy", ParseDate("%dd/%mm/%yyyy", Date))
    If ParseDate("%dd/%mm/%yyyy", Date) > 0
      ProcedureReturn #True
    EndIf
    ProcedureReturn #False
    
  EndProcedure
  
  ; Donne le nombre de jour entre deux dates (Total, Ouvré, Ouvrable).
  ;
  ; @author GallyHomeCorp
  ; @param DateDebut (dd/MM/yyyy)
  ; @param DateFin (dd/MM/yyyy)
  ; @param option
  ; @param DayOff
  ; @return
  Procedure.i DayofDate(DateDebut.s, DateFin.s, option.l = #NoOption, DayOff.l = #Sunday)
    
    Define.i number, count, iDate, samedi
    Define.s sDate
    
    If IsValidDate(DateDebut) = #False Or IsValidDate(DateFin) = #False
      ProcedureReturn -1
    EndIf
    
    If ParseDate("%dd/%mm/%yyyy", DateDebut) > ParseDate("%dd/%mm/%yyyy", DateFin)
      Define.s tmpDate = DateDebut
      DateDebut = DateFin
      DateFin   = tmpDate
    EndIf
 
    Repeat
      sDate = FormatDate("%dd/%mm/%yyyy", AddDate(ParseDate("%dd/%mm/%yyyy", DateDebut), #PB_Date_Day, count))
      iDate = DayOfWeek(AddDate(ParseDate("%dd/%mm/%yyyy", DateDebut), #PB_Date_Day, count))
      number + 1
      If option <> #NoOption
        If option <> #PublicHoliday
          If option = #NoWorkingDay
            If iDate = DayOff Or IsPublicHoliday(sDate)
              number - 1
            EndIf
          Else
            If option <> #NoOption 
              If ((option = #NoWeekDay Or option = #BusinessDay) And (iDate = #Sunday Or iDate = #Saturday)) Or (option = #BusinessDay And IsPublicHoliday(sDate) And (iDate <> #Sunday Or iDate <> #Saturday))
                number - 1
              EndIf
            EndIf
          EndIf
        Else
          If IsPublicHoliday(sDate) = 0
            number - 1
          EndIf
        EndIf
      EndIf
      count + 1
    Until sDate = DateFin
    
    ProcedureReturn number
    
  EndProcedure

  ; ****************************************************************************
  
  ; Indique si une année est Bixextile (mois de Février).
  ;
  ; @author GallyHomeCorp
  ; @param text (yyyy)
  ; @return
  Procedure.b IsBisextile(year.i)
  
    ProcedureReturn Bool((year % 4) = 0 And (year % 100) > 0 Or (year % 400))
  
  EndProcedure
  
  ; Indique si une date est un jour férié ou non.
  ;
  ; @author GallyHomeCorp
  ; @param date (dd/MM/yyyy)
  ; @return
  Procedure.b IsPublicHoliday(date.s)
    
    Define.i easter
    Define.s easterDay
    Define.s publicHoliday = "01/01,01/05,08/05,14/07,15/08,01/11,11/11,25/12"
    Define.b pHoliday = Bool(CountString(publicHoliday, Mid(date, 1, 5)) > 0)

    If Not pHoliday
      Define.i tmp = 0, dom = 0, pfm = 0 , year = Val(Mid(date, 7))
      ;If (year + (year / 4) - (year / 100) + (year / 400)) % 7 < 0
      ;  dom = ((year + (year / 4) - (year / 100) + (year / 400)) % 7) + 7 
      ;Else
        dom = (year + (year / 4) - (year / 100) + (year / 400)) % 7
      ;EndIf
      If ((3 - (11 * ((year % 19) + 1)) + ((year - 1600) / 100 - (year - 1600) / 400) - ((((year - 1400) / 100) * 8) / 25)) % 30) < 0
        pfm = ((3 - (11 * ((year % 19) + 1)) + ((year - 1600) / 100 - (year - 1600) / 400) - ((((year - 1400) / 100) * 8) / 25)) % 30) + 30 
      Else
        pfm = ((3 - (11 * ((year % 19) + 1)) + (year - 1600) / 100 - (year - 1600) / 400) - ((((year - 1400) / 100) * 8) / 25)) % 30
      EndIf
      If pfm = 29 Or (pfm = 28 And ((year % 19) + 1) > 11)
         pfm-1
      EndIf
      ;If (4 - pfm - dom) % 7 < 0
      ;  tmp = ((4 - pfm - dom) % 7) + 7 
      ;Else
        tmp = (4 - pfm - dom) % 7
      ;EndIf
      easter = pfm + tmp + 1
      If easter < 11
        easterDay = Str(easter + 21) + "/03/" + Str(year)
      Else
        easterDay = Str(easter - 10) + "/04/" + Str(year)
      EndIf
      Define.s publicPaques = FormatDate("%dd/%mm", AddDate(ParseDate("%dd/%mm/%yyyy", easterDay), #PB_Date_Day, 1)) + "," + FormatDate("%dd/%mm", AddDate(ParseDate("%dd/%mm/%yyyy", easterDay), #PB_Date_Day, 39)) + "," + FormatDate("%dd/%mm", AddDate(ParseDate("%dd/%mm/%yyyy", easterDay), #PB_Date_Day, 50))
      
      pHoliday = Bool(CountString(publicPaques, Mid(date, 1, 5)) > 0)
    EndIf
    ProcedureReturn pHoliday
    
  EndProcedure
    
  ; ****************************************************************************
  
  ; Indique si le jour en cours et le dernier du mois.
  ;
  ; @author GallyHomeCorp
  ; @return
  Procedure.b IsEndOfMonth()

    If ToDayInMonth(Month(Date()), Year(Date())) = Day(Date())
      ProcedureReturn #True
    EndIf
    ProcedureReturn #False
    
  EndProcedure
  
  ; Nombre de jour dans un Mois en fontion du Mois/Année.
  ;
  ; @author GallyHomeCorp
  ; @param month (DD)
  ; @param year (yyyy)
  ; @return
  Procedure.i ToDayInMonth(month.i, year.i)
  
    If  month = 2
      If IsBisextile(year)
        ProcedureReturn 29
      Else
        ProcedureReturn 28
      EndIf
    Else
      If month = 4 Or month = 6 Or month = 9 Or month = 11
        ProcedureReturn 30
      Else
        ProcedureReturn 31
      EndIf      
    EndIf
    
  EndProcedure
    
EndModule

; ****************************************************************************

Debug Str(toDate::DayofDate("01/02/2021", "31/02/2021", toDate::#NoOption)) + " jour(s) Total (vérification de la date)"
Debug "----------------"
Debug Str(toDate::DayofDate("01/01/2021", "31/01/2021", toDate::#NoOption)) + " jour(s) Total"
Debug Str(toDate::DayofDate("01/01/2021", "31/01/2021", toDate::#NoWeekDay)) + " jour(s) hors WE"
Debug Str(toDate::DayofDate("01/01/2021", "31/01/2021", toDate::#BusinessDay)) + " jour(s) Ouvré(s)"
Debug Str(toDate::DayofDate("01/01/2021", "31/01/2021", toDate::#NoWorkingDay)) + " jour(s) Ouvrable(s)"
Debug Str(toDate::DayofDate("01/01/2021", "31/01/2021", toDate::#PublicHoliday)) + " jour(s) Férié(s)"
Debug Str(toDate::DayofDate("01/01/2021", "31/01/2021", toDate::#NoWeekDay) - toDate::DayofDate("01/01/2021", "31/01/2021", toDate::#BusinessDay)) + " Jour(s) Férié(s) hors WE"

; Debug "----------------"
; Debug Str(toDate::DayofDate("05/03/1974", "04/02/2021", toDate::#BusinessDay))
; Debug "----------------"

; Debug "2016 = " + toDate::IsBisextile (2016)
; Debug "2017 = " + toDate::IsBisextile (2017)
; Debug "2018 = " + toDate::IsBisextile (2018)
; Debug "2019 = " + toDate::IsBisextile (2019)
; Debug "2020 = " + toDate::IsBisextile (2020)
; Debug "2020 = " + toDate::IsBisextile (2021)
; 
; Debug toDate::ToDayInMonth(2, 2016)
; 
; Debug "Dernier jour du mois ? " + toDate::IsEndOfMonth()
; 
; Debug "Jour férié ? " + toDate::IsPublicHoliday(FormatDate("%dd/%mm/%yyyy", Date()))
C'est juste pour donné un coup de main si un jour quelqu'un en aurait le besoin. Il y a surement des optimisations à faire ou même des correction, je verrais à le faire petit à petit.

Cordialement,
GallyHC
Dernière modification par GallyHC le mar. 09/févr./2021 14:32, modifié 4 fois.
Configuration : Tower: Windows 10 (Processeur: i7 "x64") (Mémoire: 16Go) (GeForce GTX 760 - 2Go) - PureBasic 5.72 (x86 et x64)
Avatar de l’utilisateur
falsam
Messages : 7244
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Module de gestion des dates (comptage, férié, ...)

Message par falsam »

Merci pour ce partage Gally. La fonction ToDayInMonth() est particulièrement intéressante pour compter le nombre de jour dans un mois d'une année ;)
Configuration : Windows 11 Famille 64-bit - PB 6.03 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
Kwai chang caine
Messages : 6962
Inscription : sam. 23/sept./2006 18:32
Localisation : Isere

Re: Module de gestion des dates (comptage, férié, ...)

Message par Kwai chang caine »

Bonjour GallyHC,

Ca fait plaisir de te lire, à mon goût pas assez souvent :wink:
Je ne sais pas si c'est normal les zéros de la fin :oops:
365 jour Total
254 jour Ouvré
----------------
10061 jour Ouvré
----------------
2016 = 1
2017 = 0
2018 = 0
2019 = 0
2020 = 1
2020 = 0
29
Dernier jour du mois ? 0
Jour férié ? 0
En tout cas merci pour le partage 8)
ImageLe bonheur est une route...
Pas une destination

PureBasic Forum Officiel - Site PureBasic
Avatar de l’utilisateur
GallyHC
Messages : 1703
Inscription : lun. 17/déc./2007 12:44

Re: Module de gestion des dates (comptage, férié, ...)

Message par GallyHC »

Bonjour,

@Falsam > Merci

@KCC > en fait "2016 = 1" veut dire que c'est une année Bissextile (0 sison).
Dernier jour du mois ? 0 > veut dire non (on est pas le dernier jour du mois, sinon c'est 1).
Jour férié ? 0 > on est pas un jour férié non plus ^^.

Cordialement,
GallyHC
Configuration : Tower: Windows 10 (Processeur: i7 "x64") (Mémoire: 16Go) (GeForce GTX 760 - 2Go) - PureBasic 5.72 (x86 et x64)
Avatar de l’utilisateur
Micoute
Messages : 2522
Inscription : dim. 02/oct./2011 16:17
Localisation : 35520 La Mézière

Re: Module de gestion des dates (comptage, férié, ...)

Message par Micoute »

Merveilleux ce module et merci GallyHC pour le partage, j'adore et j'adopte.
Microsoft Windows 10 Famille 64 bits : Carte mère : ASRock 970 Extreme3 R2.0 : Carte Graphique NVIDIA GeForce RTX 3080 : Processeur AMD FX 6300 6 cœurs 12 threads 3,50 GHz PB 5.73 PB 6.00 LTS (x64)
Un homme doit être poli, mais il doit aussi être libre !
Avatar de l’utilisateur
Kwai chang caine
Messages : 6962
Inscription : sam. 23/sept./2006 18:32
Localisation : Isere

Re: Module de gestion des dates (comptage, férié, ...)

Message par Kwai chang caine »

Dernier jour du mois ? 0 > veut dire non (on est pas le dernier jour du mois, sinon c'est 1).
Jour férié ? 0 > on est pas un jour férié non plus ^^.
Aaaah ok !!! j'ai compris, merci beaucoup 8)
ImageLe bonheur est une route...
Pas une destination

PureBasic Forum Officiel - Site PureBasic
Avatar de l’utilisateur
Naheulf
Messages : 191
Inscription : dim. 10/mars/2013 22:22
Localisation : France

Re: Module de gestion des dates (comptage, férié, ...)

Message par Naheulf »

Bonjour,

J'ai voulu donner un petit coup de main pour compléter ce bout de code. Du coup, j'ai voulu avoir quelques précisions sur les différents calculs sous-jacents liés à la gestion des dates : TRÈS MAUVAISE IDÉE.

Entre :
— les différents types d’années (calendaire, tropique (dite aussi équinoxiale ou solaire), sidérale, anomalistique, draconitique)
— les différents types de jours (stellaire, sidéral, solaire, moyen)
— les différents types de temps (universel (et ses variantes), terrestre, atomique international, dynamique barycentrique, solaire moyen, vrai)
… qui n’ont bien évidement PAS la même durée, voir une durée variable pour la plupart d’entre elles

Mais aussi :
— les secondes intercalaires (en plus ou en moins et leurs modes d’intégrations)
— les années bissextiles (en fait c’est presque ça le plus simple à gérer)
— les représentations/comptages POSIX, ISO 8601 ou autre
— les variations des dates importantes (premier jour de l’année, solstices, équinoxes) qui

Et tout le lexique utilisé quotidiennement :
— périhélie, aphélie, obliquité, périastre, point vernal, précession, nutation

Je m’suis pris un mal de crâne…
Avatar de l’utilisateur
venom
Messages : 3071
Inscription : jeu. 29/juil./2004 16:33
Localisation : Klyntar
Contact :

Re: Module de gestion des dates (comptage, férié, ...)

Message par venom »

Merci GallyHC pour ce partage. 8)
Par contre, tu n'a pas pris en compte les mois de février parfait. Comme celui de 2021... :roll: :lol:






@++
Windows 10 x64, PureBasic 5.73 x86 & x64
GPU : radeon HD6370M, CPU : p6200 2.13Ghz
Avatar de l’utilisateur
Micoute
Messages : 2522
Inscription : dim. 02/oct./2011 16:17
Localisation : 35520 La Mézière

Re: Module de gestion des dates (comptage, férié, ...)

Message par Micoute »

Bonjour GallyHc, il y a un petit problème, car quand je pose la question "Combien il y a t'il de jours entre le 01/01/2021 et le 31/01/2021, il répond comme on s'y attend 31 jours.
Mais il répond "Ce qui nous donne : 20 jours ouvrés et 21 jours fériés", tu comprends qu'il y a forcément une erreur.
Microsoft Windows 10 Famille 64 bits : Carte mère : ASRock 970 Extreme3 R2.0 : Carte Graphique NVIDIA GeForce RTX 3080 : Processeur AMD FX 6300 6 cœurs 12 threads 3,50 GHz PB 5.73 PB 6.00 LTS (x64)
Un homme doit être poli, mais il doit aussi être libre !
Avatar de l’utilisateur
GallyHC
Messages : 1703
Inscription : lun. 17/déc./2007 12:44

Re: Module de gestion des dates (comptage, férié, ...)

Message par GallyHC »

Bonjour Micoute,

Je ne vois pas vraiment le problème a pars que je n'ai pas expliquer comment cela fonctionne, donc voila un exemple pour la date que tu donne en exemple :

Code : Tout sélectionner

Debug Str(toDate::DayofDate("01/01/2021", "31/01/2021", #NoOption)) + " jour Total"
Debug Str(toDate::DayofDate("01/01/2021", "31/01/2021", #NoWeekDay)) + " jour hors WE"
Debug Str(toDate::DayofDate("01/01/2021", "31/01/2021", #BusinessDay)) + " jour Ouvré"
Debug Str(toDate::DayofDate("01/01/2021", "31/01/2021", #NoWorkingDay)) + " jour Ouvrable"
Debug Str(toDate::DayofDate("01/01/2021", "31/01/2021", #NoWeekDay) - toDate::DayofDate("01/01/2021", "31/01/2021", #BusinessDay)) + " Jour Férié"
J'ai ajouté le calcul du nombre de jour Férié qui n'été pas présent actuellement (voir premier topic).

Cordialement,
GallyHC
Configuration : Tower: Windows 10 (Processeur: i7 "x64") (Mémoire: 16Go) (GeForce GTX 760 - 2Go) - PureBasic 5.72 (x86 et x64)
Avatar de l’utilisateur
Micoute
Messages : 2522
Inscription : dim. 02/oct./2011 16:17
Localisation : 35520 La Mézière

Re: Module de gestion des dates (comptage, férié, ...)

Message par Micoute »

Veuille bien m'excuser, c'est surtout moi qui me suis mal expliqué, car évidemment j'ai exposé le problème comme toi-même tu as fait ci-dessus, je me suis plutôt emmêlé avec les samedis et surtout les dimanches qui du temps où j'étais en activité n'étaient pas ouvrables, mais fériés.
Microsoft Windows 10 Famille 64 bits : Carte mère : ASRock 970 Extreme3 R2.0 : Carte Graphique NVIDIA GeForce RTX 3080 : Processeur AMD FX 6300 6 cœurs 12 threads 3,50 GHz PB 5.73 PB 6.00 LTS (x64)
Un homme doit être poli, mais il doit aussi être libre !
Avatar de l’utilisateur
GallyHC
Messages : 1703
Inscription : lun. 17/déc./2007 12:44

Re: Module de gestion des dates (comptage, férié, ...)

Message par GallyHC »

@Micoute : Pas de problème comme cela j'ai ajouté les jours fériés ^^

Cordialement,
GallyHC
Configuration : Tower: Windows 10 (Processeur: i7 "x64") (Mémoire: 16Go) (GeForce GTX 760 - 2Go) - PureBasic 5.72 (x86 et x64)
Avatar de l’utilisateur
Micoute
Messages : 2522
Inscription : dim. 02/oct./2011 16:17
Localisation : 35520 La Mézière

Re: Module de gestion des dates (comptage, férié, ...)

Message par Micoute »

Du coup, merci pour le partage.
Microsoft Windows 10 Famille 64 bits : Carte mère : ASRock 970 Extreme3 R2.0 : Carte Graphique NVIDIA GeForce RTX 3080 : Processeur AMD FX 6300 6 cœurs 12 threads 3,50 GHz PB 5.73 PB 6.00 LTS (x64)
Un homme doit être poli, mais il doit aussi être libre !
Avatar de l’utilisateur
GallyHC
Messages : 1703
Inscription : lun. 17/déc./2007 12:44

Re: Module de gestion des dates (comptage, férié, ...)

Message par GallyHC »

Bonjour,

Mise à jour du code dans le premier Topic, j'avais fait une erreur en ajoutant les jours férié.

Cordialement,
GallyHC
Configuration : Tower: Windows 10 (Processeur: i7 "x64") (Mémoire: 16Go) (GeForce GTX 760 - 2Go) - PureBasic 5.72 (x86 et x64)
Avatar de l’utilisateur
Micoute
Messages : 2522
Inscription : dim. 02/oct./2011 16:17
Localisation : 35520 La Mézière

Re: Module de gestion des dates (comptage, férié, ...)

Message par Micoute »

Merci pour le partage, j'ai quand même été surpris par le 31 février.
Microsoft Windows 10 Famille 64 bits : Carte mère : ASRock 970 Extreme3 R2.0 : Carte Graphique NVIDIA GeForce RTX 3080 : Processeur AMD FX 6300 6 cœurs 12 threads 3,50 GHz PB 5.73 PB 6.00 LTS (x64)
Un homme doit être poli, mais il doit aussi être libre !
Répondre