OVH Cloud OVH Cloud

Weekday, bug si 1904

17 réponses
Avatar
Michel Gaboly
Bonjour,

Je viens de découvrir un bug lié aux options de classeur 1900/1904 ;-((

Je viens de l'évoquer dans un message précédent.

La fonction Weekday, native en VBA, pas celle de la feuille de calcul, JOURSEM()
renvoie un résultat erronné si dans les options de classeur, "Calendrier depuis
1904" est coché, ce qui est l'option par défaut dans les versions Mac d'Excel et
pas dans les versions Windows.

Weekday(Range("Réf")) renvoie le numéro d'un jour donné dans la semaine :
par défaut, 1 pour le dimanche, 2 pour le lundi, ...

Pour avoir une semaine commençant le lundi, il faut utiliser un second argument,
facultatif, et lui donner 2 comme valeur : Weekday(Range("Réf"), 2).

Tout va bien si le classeur est basé sur le calendrier 1900, mais s'il est basé sur
1904, on récupère la valeur attendue + 1 ;-((


L'explication est probablement la suivante : Excel considère les dates comme une
série de nombres, où une unité représente 24 heures.

Avec l'option 1900, les jours sont numérotés depuis début 1900, et le lundi 1er
décembre correspond au nombre (ou numéro de série) 37956.

Avec l'option 1904, cette même date est représentée par 36494. Il y a un écart
de1462 jours entre les 2 séries, soit 208 semaines et 6 jours.

Plus de détails ici : http://minilien.com/?WCiYNb8JqU

En ce qui concerne le numéro de jour dans la semaine, peu importent les 208
semaines d'écart ; seuls comptent les 6 jours. Par ailleurs - 6jours, c'est équi-
valent à + 1 jour (7 jours d'écart entre les 2, donc même jour de la semaine.

Il est probable que la fonction Weekday est basée sur la série de nombre associée
à l'option 1900. Dans un classeur basé sur 1904, c'est comme si la même date
était située 6 jours avant, ou, nous l'avons vu, le lendemain, ce qui expliquerait
le résultat obtenu, + 1 par rapport au résultat attendu.

Pour corriger cette anomalie, il faut donc retrancher 1 au résultat si le classeur
est basé sur 1904.

La propriété "Date1904" de l'objet "WorkBook" renvoie True si le classeur est
basé sur 1904, False, sinon.

Par ailleurs VBA interprête True comme égal à -1 et False comme égal à 0. Voici
donc une solution (la cellule active doit contenir une date) :

Private Sub Worksheet_Calculate()
Dim Delta As Integer
Delta = ThisWorkbook.Date1904
MsgBox WeekDay(ActiveCell, 2) + Delta)
End Sub

Le résultat sera correct dans tous les cas, grâce à la variable "Delta" qui permet de
retrancher 1 si nécessaire.


--
Cordialement,

Michel Gaboly
http://www.gaboly.com

10 réponses

1 2
Avatar
Daniel.M
Salut Michel,


Je viens de découvrir un bug lié aux options de classeur 1900/1904 ;-((


Il n'y a pas véritablement de bug.
VBA fonctionne avec SON propre système de représentation des dates (qui vont au
delà de 1900, soit dit en passant).

Pour une même date donnée D (important), le VBA.Weekday(D,1) te retournera
TOUJOURS le même nombre (de 1 à 7) PEU IMPORTE tes options de calendrier.
Pour t'en convaincre:
En A1: ÚTE(2003;12;1)

Sub Test
Dim d as Date
d = Range("A1")
MsgBox Weekday(d)
End Sub

Si tu alternes entre calendriers 1900/1904 et tu roules la proc, tu obtiens
toujours 2 (un Lundi). CQFD.

Évidemment, si tu mets ta date en dur, le changement de calendrier fera VARIER
cette date et la fonction weekday te retournera un chiffre différent.

Salutations,

Daniel M.

Avatar
Michel Gaboly
Bonsoir Daniel,

J'ai refait des essais, et cela semble marcher.

Cependant, mon fichier test de ce matin continue à me renvoyer une valeur
erronnée.

Si cela t'amuse, je peux te l'envoyer en Bal.

Par ailleurs, je sais bien que si on changes de référence de calendrier, on
modifie les dates de 1462 jours, ce n'est pas à cela que je faisais allusion.

Mes tests de ce matin faisaient intervenir 2 classeurs deifférents, un basé
sur 1900, l'autre sur 1904, avec dans chacun, dans la même cellule,
"1/12/2003", et Weekdays me renvoyait la bonne valeur pour celui basé
sur 1900 et pas pour l'autre.




Salut Michel,


Je viens de découvrir un bug lié aux options de classeur 1900/1904 ;-((


Il n'y a pas véritablement de bug.
VBA fonctionne avec SON propre système de représentation des dates (qui vont au
delà de 1900, soit dit en passant).

Pour une même date donnée D (important), le VBA.Weekday(D,1) te retournera
TOUJOURS le même nombre (de 1 à 7) PEU IMPORTE tes options de calendrier.
Pour t'en convaincre:
En A1: ÚTE(2003;12;1)

Sub Test
Dim d as Date
d = Range("A1")
MsgBox Weekday(d)
End Sub

Si tu alternes entre calendriers 1900/1904 et tu roules la proc, tu obtiens
toujours 2 (un Lundi). CQFD.

Évidemment, si tu mets ta date en dur, le changement de calendrier fera VARIER
cette date et la fonction weekday te retournera un chiffre différent.

Salutations,

Daniel M.


--
Cordialement,

Michel Gaboly
http://www.gaboly.com


Avatar
Daniel.M
Salut Michel,

Mes tests de ce matin faisaient intervenir 2 classeurs deifférents, un basé
sur 1900, l'autre sur 1904, avec dans chacun, dans la même cellule,
"1/12/2003", et Weekdays me renvoyait la bonne valeur pour celui basé
sur 1900 et pas pour l'autre.



Si tu as vraiment 2 classeurs avec la MÊME date (et des calendriers différents)
et que VBA.Weekday() retourne deux valeurs différentes, envoie-les moi, je veux
voir ça!

Tu remplaces 'prenom' par daniel et tu enlèves '.inutil' dans le nom de domaine.

Salutations,

Daniel M.

Avatar
Michel Gaboly
Re,

"Si tu as vraiment" : tu n'as peut-être pas remarqué, mais je ne suis pas
exactement un débutant. Si je signale un bug, ce n'est sûrement pas parce
que je ne me suis pas rendu compte que les dates varient quand on modifie
les options de calendrier.

Fin du préambule.

Je te confirme l'existence du bug.

Comme souvent, il n'apparaît que dans certaines circonstances, liées ici à
un formatage particulier demandé dans la ficelle "tranformer le jour de la
semaine en Lu,Ma, ect..."

Il touche uniquement les classeurs basés sur 1904.

Je viens de t'envoyer 2 classeurs exemples.



Salut Michel,

Mes tests de ce matin faisaient intervenir 2 classeurs deifférents, un basé
sur 1900, l'autre sur 1904, avec dans chacun, dans la même cellule,
"1/12/2003", et Weekdays me renvoyait la bonne valeur pour celui basé
sur 1900 et pas pour l'autre.



Si tu as vraiment 2 classeurs avec la MÊME date (et des calendriers différents)
et que VBA.Weekday() retourne deux valeurs différentes, envoie-les moi, je veux
voir ça!

Tu remplaces 'prenom' par daniel et tu enlèves '.inutil' dans le nom de domaine.

Salutations,

Daniel M.


--
Cordialement,

Michel Gaboly
http://www.gaboly.com


Avatar
Daniel.M
Michel,

Je te confirme l'existence du bug.


Le "vraiment" visait à ce que tu t'en tiennes à l'exemple le plus simple (deux
dates identiques dans 2 classeurs) de façon à ce qu'on ne s'égare pas dans les
programmes. Comme c'est le cas ici. ;-)
Car, en _toute logique_, pour prétendre qu'il y a un bug dans VBA.Weekday selon
les
calendriers, il faudrait que le simple test que je t'ai proposé échoue. Or, il
fonctionne très bien. N'est-ce pas? ;-)

Donc, regardons du côté de ta proc événementielle Calculate.
Parce que VBA a son propre système de date, il lui faut interpréter les dates
correctement selon les différents classeurs.
En formattant des nombres en String "Lu", "Ma" etc., tu ne permets pas à VBA de
traiter les entrées de la ligne 3 en date: ceci est fondamental (IsDate sur les
entrées Dates retourne False).
Il les interprète en nombre (et son système est compatible 1900) ce qui donne
rigoureusement 1999-11-30 pour B3 (vérifie par une instruction VBA.Format()).

Avec ce petit changement (récupère la valeur à partir de la ligne 1, qui elle
est formattée en Date), cela baigne :

Application.WorksheetFunction.Index(Mat, Weekday(c(-1, 1), 2))

C'est pas un bug : c'est le comportement attendu de VBA au complet (Weekday
compris). Parce que les systèmes 1900 et 1904 sont incompatibles au niveau des
nombres, il lui faut un critère pour savoir si une cellule représente une date
ou un simple nombre (pour faire les corrections appropriées selon les
calendriers), IsDate() donne ce critère. Ton formatage en ligne 3 rend cette
différence impossible à déterminer.

Tu peux toujours utiliser MOD 7, qui lui traite toujours son argument comme un
nombre (mais là, ça devient beaucoup plus compliqué pour d'autres calculs
calendaires).
Une autre solution consiste à s'acheter un VRAI micro et à travailler en
calendrier 1900. :-))

Salutations,

Daniel M.

Avatar
Michel Gaboly
Daniel,

Je ne suis pas d'accord avec toi ;-))

Si tu utilises la fonction TYPE() dans la feuille de calcul, elle renvoie bien 1,
qui correspond à du numérique.

D'ailleurs, si on cherche à appliquer un forat de type Date à la cellule, cela ne
pose aucun problème.

Si cela te convient mieux, disons que c'est la confirmation de la faiblesse d'Excel
à manipuler les dates formatées (vieux problème (antérieur à VBA) des
recherches qui fonctionnent sur une date non formatée, mais qui échouent en
cas de formatage).

L'un des principes de base des tableurs, non respecté ici, est que la valeur d'une
cellule est indépendante de de son formatage.

Que le IsDate renvoie une information qui varie en fonction du formatage de la
cellule ne paraît pas vraiment satisfaisant ;-)) Surtout quand la cellule contient
la formule "±", et que B1 est formatée en date.

Que le problème ne survienne qu'avec les classeurs ayant un calendrier basé sur
1904 n'est pas plus satisfaisant.

Si la contrainte est liée à l'existence des 2 types de calendrier, il faut les unifier
et proposer un outil pour traiter les classeurs lors d'un changement de version

Quant au concept de VRAI micro, s'il s'agit d'un truc agressé en permanence par
des virus, nécessitant des mises à jour de sécurité plus d'une fois par mois en
moyenne, avec des polices à la lisibilité médiocre (le "l" (comme "lourd") et le
1 (2/2) ne se distinguent pas quand on utilise la police proposée par défaut dans
l'éditeur VBA), très peu pour moi :-((

Sans parler des plantages fréquents au bout de quelques jours ou quelques semai-
nes, quand on développe une appli un peu lourde, qui obligent regulièrement à
transférer les feuilles du classeur, les UserForms et les modules dans un nouveau
classeur, qui pèse couramment 30% de moins que le précédent dont, pourtant il
devrait être la copie, sous peine d'un plantage dans les minutes qui suivent l'ou-
verture du fichier si on est dans VBA.

Sans parler non plus du "plug and pray" et de multiples autres choses ;-(((


Michel,

Je te confirme l'existence du bug.


Le "vraiment" visait à ce que tu t'en tiennes à l'exemple le plus simple (deux
dates identiques dans 2 classeurs) de façon à ce qu'on ne s'égare pas dans les
programmes. Comme c'est le cas ici. ;-)
Car, en _toute logique_, pour prétendre qu'il y a un bug dans VBA.Weekday selon
les
calendriers, il faudrait que le simple test que je t'ai proposé échoue. Or, il
fonctionne très bien. N'est-ce pas? ;-)

Donc, regardons du côté de ta proc événementielle Calculate.
Parce que VBA a son propre système de date, il lui faut interpréter les dates
correctement selon les différents classeurs.
En formattant des nombres en String "Lu", "Ma" etc., tu ne permets pas à VBA de
traiter les entrées de la ligne 3 en date: ceci est fondamental (IsDate sur les
entrées Dates retourne False).
Il les interprète en nombre (et son système est compatible 1900) ce qui donne
rigoureusement 1999-11-30 pour B3 (vérifie par une instruction VBA.Format()).

Avec ce petit changement (récupère la valeur à partir de la ligne 1, qui elle
est formattée en Date), cela baigne :

Application.WorksheetFunction.Index(Mat, Weekday(c(-1, 1), 2))

C'est pas un bug : c'est le comportement attendu de VBA au complet (Weekday
compris). Parce que les systèmes 1900 et 1904 sont incompatibles au niveau des
nombres, il lui faut un critère pour savoir si une cellule représente une date
ou un simple nombre (pour faire les corrections appropriées selon les
calendriers), IsDate() donne ce critère. Ton formatage en ligne 3 rend cette
différence impossible à déterminer.

Tu peux toujours utiliser MOD 7, qui lui traite toujours son argument comme un
nombre (mais là, ça devient beaucoup plus compliqué pour d'autres calculs
calendaires).
Une autre solution consiste à s'acheter un VRAI micro et à travailler en
calendrier 1900. :-))

Salutations,

Daniel M.


--
Cordialement,

Michel Gaboly
http://www.gaboly.com


Avatar
Daniel.M
Salut Michel,

Je ne suis pas d'accord avec toi ;-))
Pas de problème.


Si cela te convient mieux, disons que c'est la
confirmation de la faiblesse d'Excel
à manipuler les dates formatées (vieux problème (antérieur à VBA) des
recherches qui fonctionnent sur une date non formatée, mais qui échouent en
cas de formatage).


Avoir et maintenir 2 systèmes de représentation impose de faire des choix assez
difficiles (quand est-ce qu'une entrée numérique constitue une date ou non?)
lors des différentes opérations numériques sur celles-ci (addition,
soustraction) dans le language de programmation (VBA).
Je trouve plus problématique les incapacités des recherches de dates avec .Find
(selon les formats).


L'un des principes de base des tableurs, non respecté ici, est que la valeur
d'une

cellule est indépendante de de son formatage.


Un bon point: l'interprétation par VBA met à mal ce principe.

Mais:
1-Elle est indépendante au niveau de la feuille de calcul: JOURSEM(B3;2)
retourne la bonne info.
2-Sans vouloir t'offusquer, les exemples fournis ne sont pas si fréquents que
ça. Il arrive rarement qu'on formate une date en une string comme "Lun". On
passe par TEXTE() habituellement.

Quoiqu'il en soit, il est vrai que l'interprétation par VBA requiert certaines
précautions (prudence si on formate une date sous un format non-date).


Que le IsDate renvoie une information qui varie en fonction du formatage de la
cellule ne paraît pas vraiment satisfaisant ;-))
Surtout quand la cellule contient
la formule "±", et que B1 est formatée en date.


Le rôle de IsDate() est strictement d'essayer de savoir si la cellule est une
date ou autre chose. Dans le système d'Excel, en présence d'un _nombre_, la
seule autre info disponible pour savoir si le système a affaire à une date est
le format. Sauf au moment de la saisie: et là, s'il n'y a pas eu préformatage,
on est correct.

Que le problème ne survienne qu'avec les classeurs ayant un calendrier basé
sur

1904 n'est pas plus satisfaisant.
Si la contrainte est liée à l'existence des
2 types de calendrier, il faut les unifier
et proposer un outil pour traiter les classeurs lors
d'un changement de version


D'accord.
Même si l'outil de conversion se heurterait aux mêmes problèmes que VBA
(difficultés à reconnaître de façon 100% précise, les dates d'un classeur): mais
c'est vrai que ça serait un 'one-time operation' (au moment de la conversion).


Quant au concept de VRAI micro, ...
... *n


Une corde sensible? ;-) Les propriétaires de Mac sont tellement susceptibles
;-))

Salutations,

Daniel M.

Avatar
Michel Gaboly
Rebonsoir,

Je crois qu'on a plus ou moins fait le tour de la question ;-))

Je suis d'accord que ce type de formatage n'est pas fréquent ;-))

Mais la demande initiale ne l'était pas non plus ; je ne sais pas si tu as suivi le
fil initial; il s'agissait de quelqu'un qui avait une version d'Excel en anglais,
mais voulait pouvoir afficher le jour de semaine sous la forme "Lu", "Ma", ...
TOUT EN VOULANT pouvoir continuer à faire des calculs de dates sur le contenu
des cellules.

Par conséquent TEXTE() était exclu.

C'est pourquoi je lui ai proposé 2 options, l'insertion d'une ligne avec le forma-
tage voulu, en conservant masquée la ligne avec les dates pour pouvoir faire les
calculs désirés, ou ce formatage très inhabituel, qui a conduit à notre discussion.

Bonne soirée. ;-))



Salut Michel,

Je ne suis pas d'accord avec toi ;-))
Pas de problème.


Si cela te convient mieux, disons que c'est la
confirmation de la faiblesse d'Excel
à manipuler les dates formatées (vieux problème (antérieur à VBA) des
recherches qui fonctionnent sur une date non formatée, mais qui échouent en
cas de formatage).


Avoir et maintenir 2 systèmes de représentation impose de faire des choix assez
difficiles (quand est-ce qu'une entrée numérique constitue une date ou non?)
lors des différentes opérations numériques sur celles-ci (addition,
soustraction) dans le language de programmation (VBA).
Je trouve plus problématique les incapacités des recherches de dates avec .Find
(selon les formats).

L'un des principes de base des tableurs, non respecté ici, est que la valeur
d'une

cellule est indépendante de de son formatage.


Un bon point: l'interprétation par VBA met à mal ce principe.

Mais:
1-Elle est indépendante au niveau de la feuille de calcul: JOURSEM(B3;2)
retourne la bonne info.
2-Sans vouloir t'offusquer, les exemples fournis ne sont pas si fréquents que
ça. Il arrive rarement qu'on formate une date en une string comme "Lun". On
passe par TEXTE() habituellement.

Quoiqu'il en soit, il est vrai que l'interprétation par VBA requiert certaines
précautions (prudence si on formate une date sous un format non-date).


Que le IsDate renvoie une information qui varie en fonction du formatage de la
cellule ne paraît pas vraiment satisfaisant ;-))
Surtout quand la cellule contient
la formule "±", et que B1 est formatée en date.


Le rôle de IsDate() est strictement d'essayer de savoir si la cellule est une
date ou autre chose. Dans le système d'Excel, en présence d'un _nombre_, la
seule autre info disponible pour savoir si le système a affaire à une date est
le format. Sauf au moment de la saisie: et là, s'il n'y a pas eu préformatage,
on est correct.

Que le problème ne survienne qu'avec les classeurs ayant un calendrier basé
sur

1904 n'est pas plus satisfaisant.
Si la contrainte est liée à l'existence des
2 types de calendrier, il faut les unifier
et proposer un outil pour traiter les classeurs lors
d'un changement de version


D'accord.
Même si l'outil de conversion se heurterait aux mêmes problèmes que VBA
(difficultés à reconnaître de façon 100% précise, les dates d'un classeur): mais
c'est vrai que ça serait un 'one-time operation' (au moment de la conversion).


Quant au concept de VRAI micro, ...
... *n


Une corde sensible? ;-) Les propriétaires de Mac sont tellement susceptibles
;-))

Salutations,

Daniel M.


--
Cordialement,

Michel Gaboly
http://www.gaboly.com


Avatar
Daniel.M
Michel,

Je crois qu'on a plus ou moins fait le tour de la question ;-))


En effet. :-)

fil initial; il s'agissait de quelqu'un qui avait une version d'Excel en
anglais,

mais voulait pouvoir afficher le jour de semaine sous la forme "Lu", "Ma", ...
TOUT EN VOULANT pouvoir continuer à faire des calculs de dates sur le contenu
des cellules.


Il y en a qui sont tellement exigeants: ils veulent le beurre et l'argent du
beurre. :-)

Moi aussi j'ai une version anglaise. S'il a lu ce fil, je lui propose la
solution suivante.

1-Se définir un tableau de strings {"Lun";"Mar"; etc.}
2-Faire appel à un index(tab,weekday(c,2),0)) pour l'affichage et conserver les
vraies dates pour les calculs.

Pour 1 cellule de plus par date entrée, c'est le bonheur.

Bonne continuation sur Mac ;-)

Daniel M. (ancien Mac-proprio)

Avatar
isabelle

Rebonsoir,
Mais la demande initiale ne l'était pas non plus ; je ne sais pas si tu as suivi le
fil initial; il s'agissait de quelqu'un qui avait une version d'Excel en anglais,
mais voulait pouvoir afficher le jour de semaine sous la forme "Lu", "Ma", ...
TOUT EN VOULANT pouvoir continuer à faire des calculs de dates sur le contenu
des cellules.


justement la formule qui a été proposé ne fait pas disparaitre la
colonne contenant les dates, alors messieurs vous voulez bien
messeuplipliquer le fondement de se débat face à la question initiale,
juste question de remettre du chimblick :-))

isabelle

1 2