Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Dates 1900 -> 1970

20 réponses
Avatar
candide
Bonjour,

La Norme propose en exemple la recherche du jour de la semaine du 4 juillet 2001
(le C est américain jusqu'au bout ;) mais je les félicite de leur choix
d'exemple, à nouveau la Norme est beaucoup plus didactique qu'on ne le dit ne
général). Voici leur code mais adapté pour la recherche du jour de la semaine
pour un siècle plutôt :

/* -------------------------------------------------- */
#include <stdio.h>
#include <time.h>

static const char *const wday[] =
{ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
"Saturday", "-unknown-"
};


int main(void)
{
struct tm time_str;

time_str.tm_year = 1901 - 1900;
time_str.tm_mon = 7 - 1;
time_str.tm_mday = 4;
time_str.tm_hour = 0;
time_str.tm_min = 0;
time_str.tm_sec = 1;
time_str.tm_isdst = -1;

if (mktime(&time_str) == (time_t) (-1))
time_str.tm_wday = 7;

printf("%s\n", wday[time_str.tm_wday]);
return 0;
}
/* -------------------------------------------------- */


Et quelle n'est pas ma surprise de voir l'affichage suivant :

-unknown-

Vérification faite, sur ma machine, le dernier jour qui ne marche pas est le
vendredi 13 (!!) décembre 1901 et ça me renvoie bien Sunday pour le 14 décembre
1901, on dirait le bug de 2038 avec des nombres négatifs (2038-1970=62 et
1970-62= 1902 et en fait environ décembre 1901 car le bug est en janvier 2038).

Je suis très étonné de cette impossibilité de répondre car je pensais que la
conversion était assurée pour les dates postérieures à 1900, cf. ce que dit la
Norme :

7.23 Date and time <time.h> 7.23.1 Components of time
1 (...) The semantics of the members and their normal ranges are expressed in
the comments.

tm_year; // years since 1900

[Au passage, je trouve assez curieux de donner des informations de spécification
dans des commentaires de code].

Sous Windows chez moi, c'est encore pire, ça ne marche qu'à partir du 2 janvier
1970 (Mingw et Visual C++).

Un compilateur conforme est-il censé traiter de toutes les dates depuis 1900 ?
[si je regarde le code de Plauger dans son livre, il fait attention à ce que ces
dates soient traitées entre 1801 et 2099].

10 réponses

1 2
Avatar
Antoine Leca
Le 06/03/2009 17:32, Xavier Roche écrivit :
candide a écrit :
Sous Windows chez moi, c'est encore pire, ça ne marche qu'à partir du
2 janvier 1970 (Mingw et Visual C++).



A priori c'est un bug de la libc (enfin, de la couche de
""compatibilité"" POSIX) sous Windows,



Je te souhaite bien du plaisir pour essayer de faire valoir ce point de vue.

qui ne gère pas correctement les valeurs négatives
(time_t est signé, même si ce n'est pas toujours explicitement dit)



Comment comprendre cette phrase ?
Veux-tu dire, « dans toutes les normes, le genre signé ou pas de time_t
n'est pas précisé, mais pour être bien, il faut être signé » ?
Ou encore, « dans mon interprétation des normes, time_t doit être signé,
mais je n'arrive pas à retrouver le verset des Écritures où c'est dit »?


A noter que, en général, sizeof(time_t) == sizeof(void*) (la limite de
2038/1902 n'est ainsi vraie qu'en 32-bit -- on peut ainsi espérer éviter
le bug de l'an 2038 avec le remplacement progressif des 32-bit par du
64-bit pur)



Ah oui ? Et quand l'espace d'adressage est de 16 bits, time_t avec ses
32767 valeurs positives ne permettrait d'avoir qu'à peine 8 heures pour
bosser ? ceci expliquerait-il les timestamps sur 2 secondes de MS-Dog
pour toi ?


Antoine
Avatar
Xavier Roche
Antoine Leca a écrit :
Je te souhaite bien du plaisir pour essayer de faire valoir ce point de vue.



Disons que la moitié de l'espace adressable est invalide, ce qui est une
implémentation fort curieuse - de surcroit quand le système
d'exploitation est capable de gérer des dates bien plus étendues. De là,
j'en ai déduit un petit souci d'implémentation, d'autant plus que tous
les autres OS de la terre ont fait le même choix.

Veux-tu dire, « dans toutes les normes, le genre signé ou pas de time_t
n'est pas précisé, mais pour être bien, il faut être signé » ?



Non, ce n'est précisé nul part. Mais de fait, toute l'informatique non
embarquée gère les dates antérieures à 1970.

Ah oui ? Et quand l'espace d'adressage est de 16 bits, time_t avec ses



J'ai bien précisé "en général". Pas "systématiquement".
(Ce n'est certainement pas le cas pour les petits embarqués)
Avatar
Antoine Leca
Le 06/03/2009 18:54, Xavier Roche écrivit :
Hélas sizeof(long int) == 4 dans tous les cas sous WIN32,



Pas vraiment. En fait c'est LONG qui est toujours sur 32 bits. Il est
parfaitement possible d'avoir une implémentation qui tourne sous Windows
avec LONG sur 32-bits et long correspondant à la logique *nix actuelle ;
en fait, cela marche même plutôt bien a posteriori (on utilise LONG
lorsqu'on utilise l'API Windows, long pour les variables du programme,
c'est ce que font naturellement les programmeurs sans y penser), cela
permet (toujours a posteriori) de pêcher des bogues de typage.
Par contre, à la conception c'est plus difficile à faire comprendre.

De plus mais alors là cela devient très irrégulier, grâce à Unicode tu
peux monter des implémentations WIN32 avec sizeof(long) == 2...



Antoine
Avatar
Xavier Roche
Antoine Leca a écrit :
Pas vraiment. En fait c'est LONG qui est toujours sur 32 bits.



Non, "long" aussi.

Il est parfaitement possible d'avoir une implémentation qui tourne sous Windows
avec LONG sur 32-bits et long correspondant à la logique *nix actuelle ;



De mémoire, "long" avait été introduit pour ne pas augmenter la taille
de "int", à l'époque, utilisé pour à peu près tout et n'importe quoi
(comme des compteurs de boucle)

en fait, cela marche même plutôt bien a posteriori (on utilise LONG



Nous sommes d'accord, rien n'empêche d'avoir sizeof(int)==sizeof(long
int)<sizeof(void*), mais c'est une spécificité sous WIN32 que n'ai
jamais vu autre part.
Avatar
Antoine Leca
Le 07/03/2009 16:54, Xavier Roche écrivit :
Antoine Leca a écrit :
Pas vraiment. En fait c'est LONG qui est toujours sur 32 bits.



Non, "long" aussi.



Bin non. Win32 définit LONG parce que cela partie de l'API. Par contre,
long est définit par le fournisseur du compilateur (de
l'implémentation), et ce dernier n'est pas obligé de respecter les
oukases de Microsoft, surtout lorsque :
- le produit sortit avant que MS ne publie plus ou moins officiellement
ses specs (1999, pour le futur XP Itanic),
ou
- les clients de la dite implémentation préfèrent avoir la
compatibilité *nix _et_ fonctionner sous Win32 au fait d'être 100%
compatible Windows mais perdre en compatibilité *nix
ou
- cela sert à se différencier de l'offre MS.


Il est parfaitement possible d'avoir une implémentation qui tourne
sous Windows avec LONG sur 32-bits et long correspondant à la
logique *nix actuelle ;



De mémoire, "long" avait été introduit pour ne pas augmenter la taille
de "int", à l'époque, utilisé pour à peu près tout et n'importe quoi
(comme des compteurs de boucle)



De mémoire, long a été inventé (1975?) parce que les registres du PDP11
étaient sur 16 bits mais que certaines opérations nécessitaient plus de
bits, donc Dennis Ritchie a rajouté dans la bibliothèque standard le
support des opérations en double précision (en utilisant si possible une
unité optionelle de calcul arithmétique), et dans le compilateur un mot
clé pour définir des objets à ce format, long (suivi de près par short).
À l'époque (jusque vers 1980) utiliser ce type "long int" signifiait un
réel impact sur les performances, donc exprimait un compromis.
Une des premières utilisations de ce truc a été les compteurs de temps,
et le type time_t a été transformé de ce fait d'un tableau de deux int
au nouveau type ; on en voit encore des traces, en particulier le fait
que la fonction time() prend comme argument un pointeur.

Ce qui a été utilisé pour tout et n'importe quoi, c'est bien les int
mais plus tard, à l'époque des Vax, de l'explosion Unix et de
l'architecture ILP32, tout-est-sur-32-bits ; et le problème fut que
l'on a alors oublié qu'utiliser long signifiait sacrifier un peu de
performances (même problème que i386)...


en fait, cela marche même plutôt bien a posteriori (on utilise LONG



Nous sommes d'accord, rien n'empêche d'avoir sizeof(int)==sizeof(long
int)<sizeof(void*),



Vu comme cela d'accord

mais c'est une spécificité sous WIN32 que n'ai jamais vu autre part.



Cela s'appelle le modèle LLP64, aussi appelé P64 au début (vers 1992).
Je n'ai pas d'exemple sous la main, mais d'après les propos de J.Mashey
(entre autres) rapportant les débats de l'époque, cette option était une
alternative réelle à LP64 (DEC, qui s'est imposé ensuite) ou à ILP32LL
(l'option de SGI, suivi un temps par Sun) dans la diffusion des
implémentations 64 bits ; et à l'époque Microsoft ne rentrait pas dans
ce débat (il est clair que NT a été conçu sans penser au 64 bits, par
exemple).


Antoine
Avatar
Antoine Leca
Le 07/03/2009 16:46, Xavier Roche écrivit :
Antoine Leca a écrit :
Je te souhaite bien du plaisir pour essayer de faire valoir ce point
de vue.



Disons que la moitié de l'espace adressable est invalide, ce qui est une
implémentation fort curieuse



En fait c'est encore plus curieux que tu ne le penses.
À la fin des années 80, lorsque est sortit la définition finale de la
norme ANSI, les implémenteurs de Microsoft ont révisé leur produit
(hérité en partie de Lattice) pour le rendre conforme ; et ils ont
décidé (les détails ne sont pas clairs, cela pourrait bien avoir une
relation avec OLE/Basic) d'implémenter time_t comme un entier non signé
basé sur... 1900 !
Et le produit (C/C++ 7, 1990) est sortit comme cela !

Évidemment, cela a cassé pas mal de code (il y avait une vieille page de
la base de connaissances à ce sujet, mais elle n'est plus en ligne) ;
surtout qu'à l'époque MS ne régnait pas en maître, le produit de
référence était plutôt BC++ 3.x.

Donc ils sont revenus en arrière (dès la version suivante, Visual C++
v.1, 1992?) ; mais probablement pour pouvoir éviter de créer des bogues
de compatibilité à répétition, ou alors parce qu'ils n'ont pas enlevé le
test pour empêcher time_t de devenir négatif (mais je doute beaucoup, vu
le code et en particulier la constante _BASE_YEAR introduite alors), le
domaine de mktime() s'est réduit à la période 1970-2037, les valeurs
positives du nouveau time_t.

Depuis, le code pour la version 32 bits de time_t est resté en l'état, y
compris dans MSVCRT.DLL (utilisé par Mingw). À noter que Microsoft a
rajouté un type time64_t, et même des options de compilateur pour avoir
time_t sur 64 bits, avec un domaine étendu jusqu'en l'an 3000 (mais
commençant toujours en 1970).

Conclusion, utiliser time_t pour gérer des dates pouvant être
antérieures à 1970 est une mauvaise idée en général.


- de surcroit quand le système
d'exploitation est capable de gérer des dates bien plus étendues. De là,
j'en ai déduit un petit souci d'implémentation, d'autant plus que tous
les autres OS de la terre ont fait le même choix.



Mmmm. Je n'en suis pas sûr à consulter le code dit "Olson", certes pas
de prime jeunesse mais utilisé dans la plupart des *nix, qui prend des
précautions pour fonctionner aussi bien avec time_t signé que non signé
(chose que tu peux d'ailleurs configurer).

Par ailleurs, les OS n'ont rien à voir là-dedans, il s'agit purement
d'un problème d'implémentation de la bibliothèque standard : même
lorsqu'ils manipulent directement des time_t comme compte de secondes
depuis l'Époque, les OS n'ont pas à se soucier de savoir si time_t est
signé ou pas, du moins jusqu'en 2038 ; et à ce moment-là, s'il reste du
code qui nécessite d'avoir des time_t sur 32 bits, la bonne option pour
l'*OS* sera souvent de renvoyer une valeur non signée plutôt qu'une
erreur ou une exception, en partant du principe que le code « de
qualité» aura lui été convertit à des time_t sur 64 bits depuis
longtemps (autrement dit, je ne cherche pas à couvrir les cas « type
Ariane-5 »).


Antoine
Avatar
-ed-
On 9 mar, 12:33, Antoine Leca wrote:
<...>
Antoine


<...>

Ce qui est bien, c'est que grâce à Google, ce genre de connaissance
est archivée pour toujours...

Merci Antoine.
Avatar
listes
-ed- wrote:

On 9 mar, 12:33, Antoine Leca wrote:
<...>
> Antoine
<...>

Ce qui est bien, c'est que grâce à Google, ce genre de connaissance
est archivée pour toujours...

Merci Antoine.



Jusqu'a ce que Google disparaisse....

--
Membre de MacInside
http://www.macinside.be/
Avatar
-ed-
On 10 mar, 08:04, (David Remacle) wrote:
-ed- wrote:
> On 9 mar, 12:33, Antoine Leca wrote:
> <...>
> > Antoine
> <...>

> Ce qui est bien, c'est que grâce à Google, ce genre de connaissance
> est archivée pour toujours...

> Merci Antoine.

Jusqu'a ce que Google disparaisse....



L'humanité aura disparu avant...
Avatar
listes
-ed- wrote:

On 10 mar, 08:04, (David Remacle) wrote:
> -ed- wrote:
> > On 9 mar, 12:33, Antoine Leca wrote:
> > <...>
> > > Antoine
> > <...>
>
> > Ce qui est bien, c'est que grâce à Google, ce genre de connaissance
> > est archivée pour toujours...
>
> > Merci Antoine.
>
> Jusqu'a ce que Google disparaisse....

L'humanité aura disparu avant...



probablement :)
--
Membre de MacInside
http://www.macinside.be/
1 2