Page 1 sur 2

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

Publié : mer. 27/janv./2021 11:22
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

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

Publié : mer. 27/janv./2021 14:47
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 ;)

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

Publié : mer. 27/janv./2021 17:03
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)

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

Publié : mer. 27/janv./2021 17:55
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

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

Publié : ven. 29/janv./2021 17:34
par Micoute
Merveilleux ce module et merci GallyHC pour le partage, j'adore et j'adopte.

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

Publié : dim. 31/janv./2021 16:47
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)

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

Publié : mar. 02/févr./2021 16:56
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…

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

Publié : mar. 02/févr./2021 22:33
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:






@++

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

Publié : mer. 03/févr./2021 8:32
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.

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

Publié : mer. 03/févr./2021 9:15
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

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

Publié : mer. 03/févr./2021 16:20
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.

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

Publié : mer. 03/févr./2021 17:38
par GallyHC
@Micoute : Pas de problème comme cela j'ai ajouté les jours fériés ^^

Cordialement,
GallyHC

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

Publié : jeu. 04/févr./2021 11:17
par Micoute
Du coup, merci pour le partage.

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

Publié : ven. 05/févr./2021 11:04
par GallyHC
Bonjour,

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

Cordialement,
GallyHC

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

Publié : ven. 05/févr./2021 14:58
par Micoute
Merci pour le partage, j'ai quand même été surpris par le 31 février.