IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Voir le flux RSS

User

Petit défi : déterminer l'année d'une date à partir de sa valeur entière

Noter ce billet
par , 31/12/2020 à 22h35 (923 Affichages)
Objectif : réaliser un petit défi consistant à déterminer une année à partir d'un entier correspondant à une date en utilisant uniquement des opérations arithmétiques et des comparaisons.

Les dates sont stockées dans des numériques, dont la partie entière représente la date et la partie décimale l'heure. En fait cet entier est égal au nombre de jours écoulés depuis une date de référence.

On se propose d'écrire une fonction permettant d'obtenir l'année d'une date à partir de sa valeur entière en effectuant des divisions entières successives.

Pour cela, on aura besoin de comprendre les règles de notre calendrier grégorien :

Nom : Calendrier_Gregorien.jpg
Affichages : 79
Taille : 16,6 Ko

Le calendrier grégorien reste un calendrier solaire, qui se fonde non sur la révolution de la Terre autour du Soleil (hypothèse non validée à l'époque), mais sur le retour du Soleil au point vernal à chaque printemps, permettant le calcul du début de l'année quelques jours après le solstice d'hiver, en 365,2421898 jours de 24 heures. Le calendrier grégorien donne un temps moyen de l'année de 365,2425 jours.
Pour assurer un nombre entier de jours à l'année, on y ajoute tous les 4 ans (années dont le millésime est divisible par 4) un jour intercalaire, le 29 février (voir année bissextile), à l'exception des années séculaires, qui ne sont bissextiles que si leur millésime est divisible par 400.

On considéra donc comme années communes (années de 365 jours) les millésimes qui sont multiples de 100 sans être multiples de 400. Ainsi 1600 et 2000 furent bissextiles, mais pas 1700, 1800, 1900 qui furent communes. De même, 2100, 2200, 2300 seront communes, alors que 2400 sera une année bissextile.
En résumé, l'année n’est bissextile (avec 366 jours) que dans l’un des deux cas suivants :

  • si l'année est divisible par 4 et non divisible par 100 ;
  • si l'année est divisible par 400 (« divisible » signifie que la division donne un nombre entier, sans reste).


Découpage du calendrier en blocs de 400 années :

Les groupes de 400 années commençant par une année bissextile multiple de 400 (exemple l'an 1600) comportent donc en particulier 3 années non bissextiles débutant les 3 derniers siècles de ce groupe.

Dans les blocs de 100 années contenus dans les blocs de 400 années, on à donc une première centaine comportant 25*(366+3*365) = 36525 jours, et les 3 autres centaines contenant 1 jour de moins, soit 25*(366+3*365) - 1 = 36524 jours.

Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
'----------------------------------------------------Groupe de 400--------------------------------------------------
'-----------1er groupe de 100-------2ème groupe de 100-----------3ème groupe de 100-----------4ème groupe de 100----
TotalJours = 25*(366 + 3*365) + (4*365 + 24*(366 + 3*365)) + (4*365 + 24*(366 + 3*365)) + (4*365 + 24*(366 + 3*365))

Par conséquent, ces groupes de 400 années débutant le 1er janvier d'une année divisible par 400 contiennent :

Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
100*(366 + 3*365) - 3  = 146097 jours

Si on divise le nombre total de jours contenus dans ces groupes par 400, on obtient bien :

146097 / 400 = 365,2425 qui représente le nombre moyen de jours par an dans le calendrier grégorien.

Cependant, comme il s'agit d'une approximation, il est très compliqué d'obtenir, même en arrondissant, le nombre exact d'années écoulées, depuis par exemple le 1er janvier de l'an 1600, à partir du nombre de jours passés depuis cette date et du nombre moyen de jours par an.

C'est pourquoi, on propose pour obtenir ce résultat d'utiliser plutôt des divisions entières successives.

Déroulé des différentes étapes :

  1. détermination du nombre de jours écoulés depuis le 1er jour de l'année de référence multiple de 400 ;
  2. découpage de ce nombre de jours en blocs de 400 années ;
  3. découpage du reste des jours obtenu en groupes de 100 années ;
  4. division à nouveau du reste en groupes de 4 années ;
  5. enfin, découpage du reste des jours en groupe de 365 jours.

L'addition des années contenues dans nos différents groupes nous permettra finalement d'obtenir le nombre d'années écoulées depuis le 1er jour de l'année de référence.


Description de la fonction Annee :

Commençons par déterminer le nombre de jours écoulés depuis le 1er janvier de l'an 0 jusqu'à la date dt passée en argument de la fonction :

Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
nbJours = dt - #1/1/400# + 4*146097  ' nombre de jours écoulés entre le 1er jour de l'an 0 (1er janvier 1600 - 1600 ans ou 4*146097 jours) et le jour passé en argument

On part de l'an 0 qui n'existe en réalité pas dans les calendriers chrétiens, pour éviter d'avoir à gérer des valeurs négatives pour les dates antérieures à l'année 1600 (cf. calendrier grégorien proleptique).

Evaluons ensuite le nombre de groupes de 400 années depuis le 1er janvier de l'an 0 en réalisant une division entière du nombre de jours écoulés par le nombre de jours contenu dans un groupe de 400 :

Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
nbGroupes400annees = (nbJours \ 146097)  ' groupe de 400 années comportant 100* (366 + 3* 365) - 3 = 146097 jours

Puis, utilisons le modulo pour obtenir le reste des jours après division :

Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
nbJours = (nbJours Mod 146097) ' nombre de jours restant après division

Divisons encore ce reste en groupes de 100 années si le nombre de jours restant est supérieur ou égal à un siècle :

Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
 ' division en groupes de 100 années
    If nbJours >= 36525 Then ' si le nombre des jours restant est supérieur ou égal au 1er siècle suivant les groupes de 400 années
        ' on ôte un jour au reste pour découper le nombre de jours restant en groupes de 100 années avec le même nombre de jours
        nbGroupes100annees = ((nbJours - 1) \ 36524) ' nombre de groupes de 100 années comportant 36524 jours
        nbJours = ((nbJours - 1) Mod 36524)  ' nombre de jours restant, après avoir soustrait les groupes de 100 années
 
        If nbJours >= 365 Then ' si le nombre de jours restant est supérieur ou égal à 365 jours
            ' on ajoute ensuite un jour pour permettre de diviser le nombre de jours restant en groupes constants de 365 jours ou de 4 années commençant par une année bissextile : (366+3*365)=1461
            nbJours = nbJours + 1
        End If
    End If
        ...

Puis, découpons encore le reste des jours en groupes de 4 années, si celui-ci est supérieur ou égal à 4 années :

Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
' division en groupes de 4 années
    If (nbJours >= 1461) Then  ' si le reste des jours est supérieur ou égal à un groupe de 4 années, commençant lui-même par une année bissextile et comportant (366 + 3*365)=1461 jours
        nbGroupes4annees = (nbJours \ 1461) ' nombre de groupes de 4 années
        nbJours = (nbJours Mod 1461)  ' nombre de jours restant, après avoir soustrait les groupes de 4 années
    End If

Enfin, si le reste des jours est supérieur à une année, découpons le encore en blocs de 365 jours pour obtenir le reste des années :

Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
 If (nbJours >= 366) Then ' si le reste des jours commence par une année bissextile
        ' on ôte un jour au reste pour diviser le nombre de jours restant en groupes constants de 365 jours
        nbAnnees = ((nbJours - 1) \ 365) ' nombre d'années restantes
        'nbJours = ((nbJours - 1) Mod 365)  ' nombre de jours restant, après avoir soustrait les dernières années
    End If

Et renvoyons le résultat final de notre fonction Annee en additionnant les années de nos différents groupes :

Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
   ' on additionne le nombre d'années des groupes de 400, de 100, de 4 avec reste des années obtenu à la fin
    Annee = nbGroupes400annees * 400 + nbGroupes100annees * 100 + nbGroupes4annees * 4 + nbAnnees

Code complet de la fonction :

Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
Public Function Annee(ByVal dt As Date) As Long
    Dim nbJours As Long ' variable contenant le nombre de jours
    Dim nbGroupes400annees As Long ' variable contenant le nombre de groupes de 400 années comportant 100 * (366 + 3 * 365) - 1 = 146097 jours
    Dim nbGroupes100annees As Long ' variable contenant le nombre de groupes de 100 années comportant 25 * (366 + 3 * 365) = 36525 jours ou 36524 jours
    Dim nbGroupes4annees As Long ' variable contenant le nombre de groupes de 4 années avec (366 + 3 * 365) = 1461 jours
    Dim nbAnnees As Long ' nombre d'années restante après les divisions successives
 
    nbJours = dt - #1/1/1600# + 4 * 146097 ' nombre de jours écoulés entre le 1er jour de l'an 0 (1er janvier 1600 - 1600 ans ou 4*146097 jours) et le jour passé en argument
 
    nbGroupes400annees = (nbJours \ 146097)  ' groupe de 400 années comportant 100* (366 + 3* 365) - 3 = 146097 jours
 
    nbJours = (nbJours Mod 146097) ' nombre de jours restant, après avoir retranché les groupes de 400 années
    ' division en groupes de 100 années
    If nbJours >= 36525 Then ' si le nombre des jours restant est supérieur ou égal au 1er siècle suivant les groupes de 400 années
        ' on ôte un jour au reste pour découper le nombre de jours restant en groupes de 100 années avec le même nombre de jours
        nbGroupes100annees = ((nbJours - 1) \ 36524) ' nombre de groupes de 100 années comportant 36524 jours
        nbJours = ((nbJours - 1) Mod 36524)  ' nombre de jours restant, après avoir soustrait les groupes de 100 années
 
        If nbJours >= 365 Then ' si le nombre de jours restant est supérieur ou égal à 365 jours
            ' on ajoute ensuite un jour pour permettre de diviser le nombre de jours restant en groupes constants de 365 jours ou de 4 années commençant par une année bissextile : (366+3*365)=1461
            nbJours = nbJours + 1
        End If
    End If
    ' division en groupes de 4 années
    If (nbJours >= 1461) Then  ' si le reste des jours est supérieur ou égal à un groupe de 4 années, commençant lui-même par une année bissextile et comportant (366 + 3*365)=1461 jours
        nbGroupes4annees = (nbJours \ 1461) ' nombre de groupes de 4 années
        nbJours = (nbJours Mod 1461)  ' nombre de jours restant, après avoir soustrait les groupes de 4 années
    End If
 
    If (nbJours >= 366) Then ' si le reste des jours commence par une année bissextile
        ' on ôte un jour au reste pour diviser le nombre de jours restant en groupes constants de 365 jours
        nbAnnees = ((nbJours - 1) \ 365) ' nombre d'années restantes
        nbJours = ((nbJours - 1) Mod 365)  ' nombre de jours restant, après avoir soustrait les dernières années
    End If
 
    ' on additionne le nombre d'années des groupes de 400, de 100, de 4 avec reste des années obtenu à la fin
    Annee = nbGroupes400annees * 400 + nbGroupes100annees * 100 + nbGroupes4annees * 4 + nbAnnees
 
End Function

Le code peut bien sûr être encore optimisé, mais j'ai voulu le garder le plus lisible possible pour mieux montrer l'enchainement des divisions successives.

Cette méthode permet aussi d'obtenir le reste des jours après avoir retranché les années.

Voilà, il doit certainement exister d'autres façons de faire, mais j'ai trouvé celle-ci intéressante.

Bon réveillon et bonne année à toutes et tous

Envoyer le billet « Petit défi : déterminer l'année d'une date à partir de sa valeur entière » dans le blog Viadeo Envoyer le billet « Petit défi : déterminer l'année d'une date à partir de sa valeur entière » dans le blog Twitter Envoyer le billet « Petit défi : déterminer l'année d'une date à partir de sa valeur entière » dans le blog Google Envoyer le billet « Petit défi : déterminer l'année d'une date à partir de sa valeur entière » dans le blog Facebook Envoyer le billet « Petit défi : déterminer l'année d'une date à partir de sa valeur entière » dans le blog Digg Envoyer le billet « Petit défi : déterminer l'année d'une date à partir de sa valeur entière » dans le blog Delicious Envoyer le billet « Petit défi : déterminer l'année d'une date à partir de sa valeur entière » dans le blog MySpace Envoyer le billet « Petit défi : déterminer l'année d'une date à partir de sa valeur entière » dans le blog Yahoo

Mis à jour 13/01/2021 à 17h57 par User

Catégories
DotNET , VB.NET , Programmation , VBA

Commentaires

  1. Avatar de Pierre Fauconnier
    • |
    • permalink
    Hé hé... Un petit défi pas si petit que ça... Merci Denis de nous proposer d'activer nos méninges. C'est bien mieux que ce qui passait à la télé.

    Je te souhaite une belle année 2021, pleine de tutos et de billets de blog, et pleine aussi de tout ce que tu auras envie d'y mettre...
  2. Avatar de User
    • |
    • permalink
    Citation Envoyé par Pierre Fauconnier
    Hé hé... Un petit défi pas si petit que ça... Merci Denis de nous proposer d'activer nos méninges. C'est bien mieux que ce qui passait à la télé.

    Je te souhaite une belle année 2021, pleine de tutos et de billets de blog, et pleine aussi de tout ce que tu auras envie d'y mettre...
    Merci Pierre

    Je te souhaite également une Excellente année 2021, créative avec surtout la santé pour toi et tes proches
    Mis à jour 01/01/2021 à 15h17 par User