Ceci est une page optimisée pour les mobiles. Cliquez sur ce texte pour afficher la vraie page.

XL 2019 Age sur deux siècles

Caninge

XLDnaute Accro
Bonjour à tous,

j'ai réussi à calculer le nombre d'années entre deux dates, mais seulement s'ils sont sur un même siècle.
Mais deux dates sur deux siècles je n'arrive pas.
Pouvez-vous m'aider s'il vous plait.
CANINGE
 

Pièces jointes

  • Age sur deux siècles.xlsx
    9 KB · Affichages: 28

eriiic

XLDnaute Barbatruc
Re,

- remarques hors calendrier :
VB:
If Year(dat2) > 9999 Or Year(dat1) < 1700 Then ...
pour moi, une fonction susceptible d'être appelée des milliers de fois se doit d'être la plus légère possible.
Chaque test fini par coûter cher au final, je supprimerais ces deux là que je trouve inutiles.
Avec dat2 As Date on a l'erreur à l'appel de la fonction, et tu as ajouté le traitement des dates juliennes.
Ainsi que celui-ci : If Year(dat1) < 1900 Then

Code:
yeardécalée = 2000
Tant qu'à faire autant la mettre en constante
Elle sera évaluée une fois plutôt qu'à chaque passage, tous les gains sont bienvenus.

Code:
If dat1 < CDate("09/12/1760") Then dat1 = dat1 - 11
Bien (bien que corrigée plus bas).
Mais dat2 peut aussi être une date julienne à corriger

-sur le calendrier :
Dans la France d'alors (sans l'Artois, sans les Trois Évêchés, sans la Lorraine, sans l'Alsace, sans la Franche-Comté, sans la Savoie, sans le Roussillon…), le passage se fit du 9 au 20 décembre 1582
Ton année de bascule est incorrecte, c'est majoritairement 1582 pour la france.
Pour moi il faut lire : le lendemain du 09/12 (donc le 10/12) est devenu le 20/12.
10 jours d'écart à cette date et non 11. Le 09/12 est à traiter, donc <= et non <
Par ailleurs, si tu veux avoir 1 jour d'écart entre le 09/12 julien et le nouveau 20/12 grégorien (ex 10/12 julien), il faut donc faire 09/12 + 10 jours et non soustraire (dis-moi si tu es d'accord, on a vite fait de s'embrouiller sur les dates)
Ce qui donnerait si je ne me trompe pas :
Code:
If dat1 <= CDate("09/12/1582") Then dat1 = dat1 + 10
If dat2 <= CDate("09/12/1582") Then dat2 = dat2 + 10
eric

PS : je n'ai fait que lire, pas testé la fonction
 
Dernière édition:

patricktoulon

XLDnaute Barbatruc
re
ouaip !!

la constante pas besoins en fait elle peut être en dur "+2000" tout court
le test 1 me permet de sortir gentiment et ne pas gérer d'erreur et renvoyer une réponse explicite
le 10 +10 a la place du 9+11 ok


en effet la date2 peut être julienne aussi
après je peut pas faire pour toute les date d'adoption ce serait un vrai calvaire
mais perso je l'avais limité au début a 1800 c'est pas pour rien
 

eriiic

XLDnaute Barbatruc
la constante pas besoins en fait elle peut être en dur "+2000" tout court
Si tu veux, mais détrompe-toi, il y a quand même un gain.
2000 est analysé et converti une seule fois en constante, alors qu'écrit en dur c'est à chaque tour. Petit gain, mais gain quand même

le test 1 me permet de sortir gentiment
Si je fais DATEDIFF_AMJ4$("28/02/16000", "01/03/16000") j'ai l'erreur au moment de l'appel de la fonction,le test n'est pas exécuté.
Et combien même il le serait, tu paies du temps de calcul à chaque tour pour un test qui ne sera jamais utile avec un utilisateur sensé. Les autres, ils auront l'erreur et ils ne la feront pas 2 fois...

après je peut pas faire pour toute les date d'adoption
Entièrement d'accord, ça n'aurait pas de sens. Mais 1582 est la date généralement retenue pour la france.
A la limite une option Alsace-Lorraine peut être ajoutée si qq'un en exprime le besoin
eric
 
Dernière édition:

patricktoulon

XLDnaute Barbatruc
re
le calcul doit être fait de toute façon ca m'ettonerai que x+2000 soit plus lourd que x+y (y etant la constante a 2000)
mais il me vient une idée vraiment toute bête a la quelle je n'ai pas pensé
et j'ajoutais 2000 d'office sans test ou quoi que ce soit après avoir résolu le problème des date julienne bien sur
comme ça économie de if etc.....
je fait une esquisse et reviens
 

patricktoulon

XLDnaute Barbatruc
re
j'ai supprimer les limites en fait
tu en pense quoi?
VB:
Function DATEDIFF_AMJ5$(ByVal dat1 As Date, Optional ByVal dat2 As Date = 0, Optional JustYear As Boolean = False)
'**************************************
'fonction DateDiff_AMJ V°5 temporaire 
'auteur:patricktoulon avec Eriiic sur Exceldownloads
'date 05/07/2021
'*************************************
    Dim A$, M$, J$, Dtemp$, et$, yeardécalée&, y
    If dat2 = 0 Then dat2 = Date
    If dat1 > dat2 Then Dtemp = dat2: dat2 = dat1: dat1 = Dtemp

    If Month(dat1) = 12 And Day(dat1) <= 9 And Year(dat1) <= 1562 Then dat1 = dat1 + 10
    If Month(dat2) = 12 And Day(dat2) <= 9 And Year(dat2) <= 1562 Then dat2 = dat2 + 10

    dat1 = DateSerial(Year(dat1) + 2000, Month(dat1), Day(dat1))
    dat2 = DateSerial(Year(dat2) + 2000, Month(dat2), Day(dat2))

    A = Evaluate("=DATEDIF(" & CLng(dat1) & "," & CLng(dat2) & ",""y"")")
    M = Evaluate("=DATEDIF(" & CLng(dat1) & "," & CLng(dat2) & ",""ym"")")
    J = Evaluate("=DATEDIF(" & CLng(dat1) & "," & CLng(dat2) & ",""md"")")
    A = IIf(A = 0, "", IIf(A = 1, A & " an", A & " ans"))
    M = IIf(M = 0, "", IIf(M >= 1, IIf(Val(J) = 0, " et ", "") & M & " mois", M & " mois"))
    J = IIf(J = 0, "", IIf(J = 1, "1  jour", J & " jours"))
    et = IIf(Val(A) > 0 Or Val(M) > 0, IIf(Val(J) > 0, " et ", " "), "")
    DATEDIFF_AMJ5 = Application.Trim(A & IIf(Not JustYear, " " & M & " " & et & J, ""))
End Function
 

patricktoulon

XLDnaute Barbatruc
une version légèrement différente

VB:
Function DATEDIFF_AMJ5$(ByVal dat1 As Date, Optional ByVal dat2 As Date = 0, Optional JustYear As Boolean = False)
'**************************************
'fonction DateDiffAMJ V°5
'auteur:patricktoulon avec Eriiic sur Exceldownloads
'date de mise en jour V°4:04/07/2021
' mise a jour supplementaire
' ajout de l'argument boolean "JustYear" pour ne récuprérer que les années
'*************************************
    Dim A$, M$, J$, Dtemp$, et$, yeardécalée&, y
    If dat2 = 0 Then dat2 = Date
    If dat1 > dat2 Then Dtemp = dat2: dat2 = dat1: dat1 = Dtemp

    'If Month(dat1) = 12 And Day(dat1) <= 9 And Year(dat1) <= 1562 Then dat1 = dat1 + 10
    'If Month(dat2) = 12 And Day(dat2) <= 9 And Year(dat2) <= 1562 Then dat2 = dat2 + 10
    If dat1 <= CDate("10/12/1562") Then dat1 = dat1 + 10
    If dat2 <= CDate("10/12/1562") Then dat2 = dat2 + 10
    
    dat1 = DateSerial(Year(dat1) + 2000, Month(dat1), Day(dat1))
    dat2 = DateSerial(Year(dat2) + 2000, Month(dat2), Day(dat2))

    A = Evaluate("=DATEDIF(" & CLng(dat1) & "," & CLng(dat2) & ",""y"")")
    M = Evaluate("=DATEDIF(" & CLng(dat1) & "," & CLng(dat2) & ",""ym"")")
    J = Evaluate("=DATEDIF(" & CLng(dat1) & "," & CLng(dat2) & ",""md"")")
    A = IIf(A = 0, "", IIf(A = 1, A & " an", A & " ans"))
    M = IIf(M = 0, "", IIf(M >= 1, IIf(Val(J) = 0, " et ", "") & M & " mois", M & " mois"))
    J = IIf(J = 0, "", IIf(J = 1, "1  jour", J & " jours"))
    et = IIf(Val(A) > 0 Or Val(M) > 0, IIf(Val(J) > 0, " et ", " "), "")
    DATEDIFF_AMJ5 = Application.Trim(A & IIf(Not JustYear, " " & M & " " & et & J, ""))
End Function

 

eriiic

XLDnaute Barbatruc
mais il me vient une idée vraiment toute bête
C'est ce que j'essaie de t'expliquer depuis samedi : ajouter un multiple de 400 ans pour recadrer parfaitement les dates dans un intervalle traité par vba.
400 ans c'est le cycle du calendrier grégorien, ça ne peut être que bon pour faire une différence de dates. Sans prises de têtes, ni aucun tests, ni cas particuliers à traiter.
Seulement, têtu comme tu es, ça prend du temps...

VB:
If dat1 <= CDate("10/12/1562") Then dat1 = dat1 + 10
non
En étant puriste ça devrait être <= 09/12/1582 ou < 10/12/1582
Mais les dates du 10/12/1582 au 19/12/1582 n'ayant jamais existé (chez nous), ça ne gêne pas.
Par contre 1562 à la place de 1582, là ça gêne beaucoup

Une constante est analysée et convertie une seule fois à la compilation. Elle est prête à l'utilisation.
VBA étant semi-compilé, une valeur écrite en dur est convertie à chaque utilisation.
Le gain est minime, difficilement mesurable, mais réel. Enfin c'est ce qui se dit.
C'est surtout que là tu n'avais que la déclaration à reprendre, ça donnait moins de travail avec une certitude de ne pas avoir de perte.
eric

Idem, juste lu, pas testé
 

patricktoulon

XLDnaute Barbatruc
re
je préfère 2000 parce que aucun des multiple de 400 en dessous ne couvrirais la marge
400 pas bon en dessous 1499
800 pas bon en dessous 1100
donc c'est mieux de passer par dessus + 2000 on est sur d’être après 1900
j'ai modifié les deux if (1582)
en effet quand le mois de décembre 1582 est englobé totalement dans l'intervalle des deux date c'est un mois tout court donc on récupère pas les 10 jours enfin je crois
voir tableau
VB:
Const year400 As Long = 2000
Function DATEDIFF_AMJ5$(ByVal dat1 As Date, Optional ByVal dat2 As Date = 0, Optional JustYear As Boolean = False)
'**************************************
'fonction DateDiffAMJ V°5
'auteur:patricktoulon avec Eriiic sur Exceldownloads
'date de mise en jour V°4:04/07/2021
' mise a jour supplementaire
' ajout de l'argument boolean "JustYear" pour ne récuprérer que les années
'*************************************
    Dim A$, M$, J$, Dtemp$, et$, yeardécalée&, y
    If dat2 = 0 Then dat2 = Date
    If dat1 > dat2 Then Dtemp = dat2: dat2 = dat1: dat1 = Dtemp

    If dat1 <= CDate("10/12/1582") Then dat1 = dat1 + IIf(Month(dat1) > 11, 10, 1)
    If dat2 <= CDate("10/12/1582") Then dat2 = dat2 + IIf(Month(dat1) > 11, 10, 1)
If dat2 > CDate("09/12/1582") And dat2 < CDate("31/12/1582") Then dat2 = dat2 + IIf(Month(dat1) = 12, -10, 1)

    dat1 = DateSerial(Year(dat1) + year400, Month(dat1), Day(dat1))
    dat2 = DateSerial(Year(dat2) + year400, Month(dat2), Day(dat2))

    A = Evaluate("=DATEDIF(" & CLng(dat1) & "," & CLng(dat2) & ",""y"")")
    M = Evaluate("=DATEDIF(" & CLng(dat1) & "," & CLng(dat2) & ",""ym"")")
    J = Evaluate("=DATEDIF(" & CLng(dat1) & "," & CLng(dat2) & ",""md"")")
    A = IIf(A = 0, "", IIf(A = 1, A & " an", A & " ans"))
    M = IIf(M = 0, "", IIf(M >= 1, M & " mois", M & " mois"))
    J = IIf(J = 0, "", IIf(J = 1, "1  jour", J & " jours"))
    et = IIf(Val(A) > 0 Or Val(M) > 0, IIf(Val(J) > 0, " et ", " "), "")
    DATEDIFF_AMJ5 = Application.Trim(A & IIf(Not JustYear, " " & M & " " & et & J, ""))
End Function


 

eriiic

XLDnaute Barbatruc
Bonjour,
400 que je citais est la longueur du cycle, tout multiple est bon.
Je ne cherchais pas à te le faire prendre.

Pourquoi + IIf(Month(dat1) > 11, 10, 1) ??
C'est faux, c'est +10, point final
eric
 

patricktoulon

XLDnaute Barbatruc
Bonjour @eriiic
ce truc c'est pour compter un mois (complet quand les deux date englobe décembre en entier )
voir tableau
je te joint le fichier de test

sinon ça donne
30/11/156201/01/156322 jours

alors oui c'est juste mais j'aurais préféré un mois
30/11/156201/01/15631 mois
 

Pièces jointes

  • DATEDIFF_AMJ5 beta.xlsm
    19.6 KB · Affichages: 4

eriiic

XLDnaute Barbatruc
Bonjour,

mais c'est normal puisqu'il y a 10 jours qui n'ont jamais existé et qui n'existeront jamais.
Le gars s'est couché le 09/12 pour se réveiller le 20/12, mais il n'a dormi qu'une nuit.
Pour moi, c'est le nombre de jours réels qu'il faut calculer, il n'a pas vieilli de 11 jours en une nuit...

Oui, ce mois de décembre exceptionnel ne faisait pas 31 jours, il faut l'admettre et faire avec. Il peut difficilement compter pour un mois complet dans un calcul de durée, ça serait tricher pour essayer de se ramener à ce qu'on connait. Mais faux à mon avis...
Personnellement je resterais sur le calcul exact, même si ça parait fausser ton nombre de mois.
Déjà, 1 mois n'est pas une durée fixe et ne permet pas une mesure correcte et indiscutable.
Vouloir une précision exacte, au jour près, en année-mois-jours est une gageure parfois impossible à atteindre, d'autant plus si on te pique des jours et que tu te retrouves avec un mois de 21 jours.
Qui ira te contrarier sur cette période exceptionnelle arrivée une fois et qui n'arrivera plus ? C'est une particularité.
Sans compter les durées de quelques jours auxquelles tu vas fausser le résultat si une partie est sur ce fameux mois. Ca va compliquer sérieusement...

De plus, c'est tous les mois de décembre de toutes les années que tu corrigeais (à tort), et non seulement l'année du changement.

Non vraiment, reste simple pour la fonction avec +2000 et ne touche plus à rien.
Sans compter que sur les dates et durées, parfois il n'y a pas de réponse exacte et toutes sont sujettes à caution.

Pourquoi tu as encore remis 1562 au lieu de 1582 ??? Tu ne l'aimes pas cette année 1582 ? Il faut être attentif à tes saisies, c'est important.
eric
 

patricktoulon

XLDnaute Barbatruc
ok on la laisse comme ça
perso un mois de décembre 1582 31 ou 20 jours englobé entièrement dans l'intervalle c'est un mois
comme février 28 ou 29 jour c'est un mois aussi
la fonction est sensée renvoyer en année mois et jour( quand il y en a )


mais bon je la livre comme ça en version secondaire
de toute façon la plus part du temps le besoins ne va pas jusque là
Merci eriiic

pour toi ca c'est bon


pour moi c'est ça
 
Dernière édition:

eriiic

XLDnaute Barbatruc
Voir autre chose que 1 jour du 9/12/1582 au 20/12/1582 m'aurait gêné, donc ça va.
Ca fait parti des problème sans réponse exacte, donc tu choisis ce que tu préfères afficher.
Ce n'est pas le bébé né le 30/11/1582 qui viendra réclamer qu'il n'a pas vécu 1 mois...

La 1ère ligne m'interroge quand même.
On est en juillet, et je lis 8 mois et 29 jours. Pour un début le 09/12, ça nous emmène en septembre...
Ce devrait plutôt être dans les 6 mois et environ (pas recalculé) 29 jours non ?

Et la 2nde, ça ne devrait pas être 4 mois et 2 jours vu qu'on est le 6 ?
eric
 

patricktoulon

XLDnaute Barbatruc
oui leday( incluse) je ne l'ai pas géré
je considère que la date de début commence a 00:00:01: donc le jour compte mais pas le jour de fin qui lui commence aussi a 00:00:01 ou alors on ajoute a la fin "et 1 sec"

et oui pour les dates large intervalle les deux if ne suffisent plus visiblement
quoi que je fasse il faut ajouter des if sinon ça marche dans un sens mais plus dans l'autre avec tes deux if simples
ou alors on la stop à 1583
 

Victor21

XLDnaute Barbatruc
Bonjour, @patricktoulon ,@eriiic.

Je vous présente humblement -mais pas tant que ça, en fait - toutes mes excuses pour avoir déterré le bienheureux pape Grégoire XIII - paix à ses cendres et sa réforme.
Nul doute que s'il avait su quelles difficultés son calendrier occasionnerait aux adeptes d'une autre religion que la sienne - Excel - il se serait abstenu de faire disparaître d'un coup de férule crucifère magique dix jours de décembre 1582 ! On fêterait peut-être Pâques en août ! Et alors ?

Je réserve à plus tard une autre question, concernant un calcul de durées avec un début ou une fin en notation révolutionnaire ( par exemple entre le 15 vendémiaire an VII (année sextile) et le 7 février 1806).
 

Discussions similaires

Réponses
22
Affichages
751
Les cookies sont requis pour utiliser ce site. Vous devez les accepter pour continuer à utiliser le site. En savoir plus…