source: Sophya/trunk/SophyaLib/NTools/dates.cc@ 3858

Last change on this file since 3858 was 3587, checked in by ansari, 17 years ago

Adaptation suite nettoyage/suppression TRY/CATCH... , Reza 05/03/2009

File size: 19.5 KB
Line 
1#include "sopnamsp.h"
2#include "machdefs.h"
3#include <stdlib.h>
4#include <string.h>
5#include <stdio.h>
6#include <iostream>
7#include <time.h>
8#include <ctype.h>
9#include <math.h>
10#include "perrors.h"
11#include "dates.h"
12
13/*!
14 \class TimeZone
15 \ingroup NTools
16 Management of time zones - This class is used with class Date.
17 \warning Unless necessary, DO NOT USE this class.
18 \sa SOPHYA::TimeStamp
19
20 \verbatim
21
22 Classe de fuseau horaire. Permet les conversion
23 GMT <-> temps local, en gérant les changements
24 d'heure hiver-été.
25 Deux fuseaux horaires sont prédéfinis, "France"
26 et "Chili".
27 \endverbatim
28*/
29
30TimeZone* gTimeZone = NULL;
31
32
33/*!
34 Constructeur par défaut. Il lit la variable
35 d'environnement ACQ_TZ pour choisir le fuseau
36 horaire. Si la variable n'est pas définie, nous
37 sommes en France...
38*/
39TimeZone::TimeZone()
40{
41 const char* p = getenv("ACQ_TZ");
42#if defined(__DECCXX) || defined(__KCC__) || defined(__aCC__)
43 if (!p) p = const_cast<char *>("France");
44#else
45 if (!p) p = "France";
46#endif
47 SetZone(p);
48}
49
50//! Constructeur à partir du nom d'un fuseau horaire.
51TimeZone::TimeZone(const char* nom)
52{
53 SetZone(nom);
54}
55
56/*!
57 Choisit un fuseau horaire. Contient la définition
58 du fuseau "France" (GMT+1, DST : dernier dimanche
59 de mars - dernier dimanche de septembre, c'est-à-dire
60 pré-gouvernement Juppé), et Chili (GMT-4, DST :
61 deuxième dimanche d'octobre - deuxième dimanche de mars).
62*/
63void TimeZone::SetZone(const char* nom)
64{
65 if (!strcmp(nom,"France")) {
66 strcpy(code,"MET");
67 strcpy(name,nom);
68 gmtOffset = 1;
69 hasDST = 1;
70 dstByWeekDay = 1;
71 dstStartDay = Date::jour_Dimanche; // dernier dimanche de mars
72 dstStartNum = -1;
73 dstStartMonth = Date::mois_Mars;
74 dstStopDay = Date::jour_Dimanche; // dernier dimanche de septembre
75 dstStopNum = -1;
76 dstStopMonth = Date::mois_Septembre;
77 dstOffset = 1;
78 } else if (!strcmp(nom,"Chili") || !strcmp(nom,"Chile")) {
79// # Chile has 2nd Sunday in October to 2nd Sunday in March DST
80 strcpy(code,"CST");
81 strcpy(name,"Chili");
82 gmtOffset = -4;
83 hasDST = 1;
84 dstByWeekDay = 1;
85 dstStartDay = Date::jour_Dimanche; // 2e dimanche d'octobre
86 dstStartNum = 2;
87 dstStartMonth = Date::mois_Octobre;
88 dstStopDay = Date::jour_Dimanche; // 2e dimanche de mars
89 dstStopNum = 2;
90 dstStopMonth = Date::mois_Mars;
91 dstOffset = 1;
92 } else throw ParmError("TimeZone::SetZone() ");
93}
94
95//! Teste si une date est en heure d'été (DST).
96int TimeZone::IsDst(const Date& date)
97{
98 Date dt = date;
99 if (dt.MM < 0 || dt.JJ < 0) throw ParmError(PExcLongMessage(""));
100 if (dt.hh >= 0) dt += gmtOffset/24.0; // date "fictive" en local d'hiver
101 else dt.ss = dt.hh = dt.mm = 0; // minuit local si heure indeterminee
102 // On est en-dehors des mois frontiere ?
103 if (dstStartMonth < dstStopMonth) {
104 if (dt.MM < dstStartMonth) return 0;
105 if (dt.MM > dstStopMonth) return 0;
106 if (dt.MM > dstStartMonth && dt.MM < dstStopMonth) return 1;
107 } else {
108 if (dt.MM < dstStopMonth) return 1;
109 if (dt.MM > dstStartMonth) return 1;
110 if (dt.MM > dstStopMonth && dt.MM < dstStartMonth) return 0;
111 }
112
113 // Nous sommes dans un mois-frontiere
114 ASSERT(dt.MM == dstStopMonth || dt.MM == dstStartMonth);
115
116 if (dt.MM == dstStartMonth) {
117 int jour;
118 if (dstByWeekDay) jour = Date::NthMonthDay(dstStartNum,dstStartDay, dt.MM, dt.AA);
119 else jour = (dstStartNum>0) ? dstStartNum : Date::MonthDays(dt.MM, dt.AA)+1-dstStartNum;
120 if (dt.JJ < jour) return 0;
121 if (dt.JJ > jour) return 1;
122 if (dt.hh > 1) return 1;
123 return 0;
124 } else {
125 int jour;
126 if (dstByWeekDay) jour = Date::NthMonthDay(dstStopNum,dstStopDay, dt.MM, dt.AA);
127 else jour = (dstStopNum>0) ? dstStopNum : Date::MonthDays(dt.MM, dt.AA)+1-dstStopNum;
128 if (dt.JJ < jour) return 1;
129 if (dt.JJ > jour) return 0;
130 if (dt.hh < 2) return 0;
131 return 1;
132 }
133}
134
135/*!
136 Retourne la difference TL-GMT pour une date donnée,
137 en tenant compte de l'heure d'été éventuelle.
138*/
139int TimeZone::GetOffset(const Date& date)
140{
141 return IsDst(date) ? gmtOffset+dstOffset : gmtOffset;
142}
143
144
145
146/*!
147 \class Date
148 \ingroup NTools
149 Date manipulation classe
150 \warning Unless necessary, DO NOT USE this class.
151 Use SOPHYA::TimeStamp instead.
152
153 \verbatim
154
155 Une classe date comme une autre, avec gestion
156 temps local / GMT / changement d'heure, et un
157 jour temps sidéral.
158
159 Une partie de la date (heure, jour...) peut être
160 indéterminée. Les comparaisons sont alors faites
161 de façon astucieuse...
162
163 La date peut être déterminée de minuit à minuit
164 ou de midi à midi (nuit d'observation). Logique
165 complexe et peut-être foireuse pour passer de
166 l'un à l'autre, mais pas encore d'ennuis pour le
167 moment... Une date-nuit doit avoir une heure
168 indéterminée.
169
170 Il faut que Date::gTimeZone soit initialisé pour
171 éviter des gros pépins, mais PeidaInit() le fait.
172
173 An 2000 : Lorsqu'on gère des dates sous forme de chaine :
174 * En sortie, 2 caractères pour l'année entre 1950 et 1999
175 et 4 caractères sinon
176 * En entrée, si AA<100 on ajoute 1900.
177
178*/
179//! Retourne le nombre de jours dans le mois
180short Date::MonthDays(short mois, short annee)
181{
182 if (mois<1 || mois>12) throw ParmError(PExcLongMessage(""));
183
184 switch(mois) {
185 case mois_Janvier:
186 case mois_Mars:
187 case mois_Mai:
188 case mois_Juillet:
189 case mois_Aout:
190 case mois_Octobre:
191 case mois_Decembre:
192 return 31;
193 case mois_Avril:
194 case mois_Juin:
195 case mois_Septembre:
196 case mois_Novembre:
197 return 30;
198 case mois_Fevrier:
199 return (((annee%4 == 0) && (annee%100 != 0)) || (annee%400 == 0)) ? 29 : 28;
200 }
201 return -1;
202}
203
204//! Retourne le nombre de jours dans l'année
205short Date::YearDays(short annee)
206{
207 return (((annee%4 == 0) && (annee%100 != 0)) || (annee%400 == 0)) ? 366 : 365;
208}
209
210bool Date::UndetDate() const
211/*!
212 Retourne true si une partie de la date (jour
213 ou mois ou année) est indéterminée.
214*/
215{
216 return ((AA == -1) || (MM == -1) || (JJ == -1));
217}
218
219/*!
220 Retourne true si toute la date (jour
221 et mois et année) est indéterminée.
222*/
223bool Date::AllUndetDate() const
224{
225 return ((AA == -1) && (MM == -1) && (JJ == -1));
226}
227
228bool Date::UndetTime() const
229/*!
230 Retourne true si une partie de l'heure (heure
231 ou minutes ou secondes) est indéterminée.
232*/
233{
234 return ((hh == -1) || (mm == -1) || (ss == -1));
235}
236
237
238/*!
239 Retourne true si toute l'heure (heure
240 et minutes et secondes) est indéterminée.
241*/
242bool Date::AllUndetTime() const
243{
244 return ((hh == -1) && (mm == -1) && (ss == -1));
245}
246
247//Date::operator double() const
248
249//! Jours écoulés depuis le 0 janvier 1901 0h TU
250double
251Date::GetDays() const
252{
253 if (UndetTime() && !AllUndetTime()) throw ParmError(PExcLongMessage(""));
254 if (UndetDate() && !AllUndetDate()) throw ParmError(PExcLongMessage(""));
255 double t=0;
256 if (!UndetDate()) {
257 int nban = AA-1901;
258 if (nban >= 0)
259 t = nban*365 + (nban/4) - (nban/100) + ((nban+300)/400);
260 else
261 t = nban*365 + (nban/4) - (nban/100) + ((nban-100)/400);
262 for (int i=1; i<MM; i++) t += Date::MonthDays(i,AA);
263 t += JJ;
264 }
265 if (!UndetTime()) t += hh/24.0 + mm/1440.0 + ss/86400.0;
266 else if (nuit) t += 0.5;
267 return t;
268}
269
270//! Initialisation a partir jours écoulés depuis le 0 janvier 1901 0h TU
271void Date::Set(double t)
272{
273 t += 1/8640000.0;
274 int nban = int(floor((t/*-1*/) / 365.2425));
275 if (nban >= 0)
276 t -= nban*365 + ((nban)/4) - ((nban)/100) + ((nban+300)/400);
277 else
278 t -= nban*365 + ((nban)/4) - ((nban)/100) + ((nban-100)/400);
279
280 AA = 1901 + nban;
281 if (t > Date::YearDays(AA)+1) {
282 t -= Date::YearDays(AA);
283 AA++;
284 } else if (t<1) {
285 AA--;
286 t += Date::YearDays(AA);
287 }
288
289 MM = 1;
290 while (t > Date::MonthDays(MM,AA)+1) {
291 t -= Date::MonthDays(MM,AA);
292 MM++;
293 }
294
295 JJ = int(t);
296 t -= JJ;
297
298 t *= 24;
299 hh = int(t);
300
301 t = (t-hh)*60;
302 mm = int(t);
303
304 t = (t-mm)*60;
305 ss = t;
306
307 nuit = 0;
308}
309
310//! Constructeur. Prend l'heure courante...
311Date::Date()
312: timeZone(gTimeZone)
313{
314 time_t t = time(NULL);
315 struct tm* TM = gmtime(&t);
316
317 AA = TM->tm_year + 1900;
318 MM = TM->tm_mon+1;
319 JJ = TM->tm_mday;
320 hh = TM->tm_hour;
321 mm = TM->tm_min;
322 ss = TM->tm_sec;
323 nuit = 0;
324}
325
326//! Constructeur simple.
327Date::Date(int J, int M, int A, int h, int m, double s)
328: JJ(J), MM(M), AA(A), hh(h), mm(m), ss(s), timeZone(gTimeZone), nuit(0)
329{
330}
331
332//! Constructeur à partir des jours écoulés depuis le 0 janvier 1901 0h TU
333Date::Date(double t)
334: timeZone(gTimeZone)
335{
336 Set(t);
337}
338
339//! On change de fuseau horaire.
340void Date::SetTimeZone(TimeZone* tz)
341{
342 timeZone = tz;
343}
344
345/*!
346 Constructeur à partir de la date sous la forme
347 'DD/MM/YYYY' 'HH/MM/SS', et tOpt est Date::kGMTTime
348 (par défaut) ou Date::kLocalTime.
349*/
350Date::Date(const char* date, const char* heure, int tOpt)
351: timeZone(gTimeZone)
352{
353 Set(date,heure,tOpt);
354}
355
356/*!
357 Constructeur à partir de la date sous la forme
358 'DD/MM/YYYY' 'HH/MM/SS', et tOpt est Date::kGMTTime
359 (par défaut) ou Date::kLocalTime.
360
361 Tout ou partie de la date peut être indéterminée ('??').
362*/
363Date::Date(string const& date, string const& heure, int tOpt)
364: timeZone(gTimeZone)
365{
366 Set(date,heure,tOpt);
367}
368
369/*!
370 Positionne la date sous la forme
371 'DD/MM/YYYY' 'HH/MM/SS', et tOpt est Date::kGMTTime
372 (par défaut) ou Date::kLocalTime.
373
374 Tout ou partie de la date peut être indéterminée ('??').
375*/
376void Date::Set(string const& date, string const& heure, int tOpt)
377{
378 Set(date.c_str(), heure == "" ? (char*)NULL : heure.c_str(), tOpt);
379}
380
381/*!
382 Positionne la date sous la forme
383 'DD/MM/YYYY' 'HH/MM/SS', et tOpt est Date::kGMTTime
384 (par défaut) ou Date::kLocalTime.
385
386 Tout ou partie de la date peut être indéterminée ('??').
387*/
388void Date::Set(const char* date, const char* heure, int tOpt)
389{
390 nuit = 0;
391 if (date) {
392 if (strlen(date) >= 5) { // J(J)/M(M)/AA(AA), ?/?/?, combinaison
393 const char* p = date;
394 if (p[0] == '?' && (p[1] == '?' || p[1] == '/')) JJ = -1;
395 else {
396 if (!isdigit(p[0])) throw ParmError(PExcLongMessage(""));
397 if (!isdigit(p[1]) && p[1] != '/') throw ParmError(PExcLongMessage(""));
398 JJ = atoi(p);
399 if (JJ <= 0) throw ParmError(PExcLongMessage(""));
400 }
401
402 if (p[1] == '/') p += 2;
403 else if (p[2] == '/') p+= 3;
404 else throw ParmError(PExcLongMessage(""));
405
406 if (p[0] == '?' && (p[1] == '?' || p[1] == '/')) MM = -1;
407 else {
408 if (!isdigit(p[0])) throw ParmError(PExcLongMessage(""));
409 if (!isdigit(p[1]) && p[1] != '/') throw ParmError(PExcLongMessage(""));
410 MM = atoi(p);
411 if (MM <= 0 || MM >12) throw ParmError(PExcLongMessage(""));
412 }
413
414 if (p[1] == '/') p += 2;
415 else if (p[2] == '/') p+= 3;
416 else throw ParmError(PExcLongMessage(""));
417
418 if (p[0] == '?') AA = -1;
419 else {
420 if (!isdigit(p[0])) throw ParmError(PExcLongMessage(""));
421 if (!isdigit(p[1])) throw ParmError(PExcLongMessage(""));
422 AA = atoi(p);
423 if (AA < 100 && AA >= 0 && date[6] != '0') AA += 1900;
424 }
425
426 if (AA > 0 && MM > 0 && JJ > 0 && JJ > MonthDays(MM,AA))
427 throw ParmError(PExcLongMessage(""));
428
429 } else if (strlen(date)==4) { // Code EROS de date
430 if (date[0] == '?') AA = -1;
431 else {
432 if (!isdigit(date[0])) throw ParmError(PExcLongMessage(""));
433 AA = 1990 + date[0] - '0';
434 }
435
436 if (date[1] == '?') MM = -1;
437 else {
438 if (!isalpha(date[1])) throw ParmError(PExcLongMessage(""));
439 if (islower(date[1]))
440 MM = date[1] - 'a' + 1;
441 else
442 MM = date[1] - 'A' + 1;
443 if (MM<1 || MM>12) throw ParmError(PExcLongMessage(""));
444 }
445
446 if (date[2] == '?' && date[3] == '?') JJ = -1;
447 else {
448 if (!isdigit(date[2])) throw ParmError(PExcLongMessage(""));
449 if (!isdigit(date[3])) throw ParmError(PExcLongMessage(""));
450 JJ = atoi(date+2);
451 }
452
453 if (AA > 0 && MM > 0 && JJ > 0 && JJ > MonthDays(MM,AA))
454 throw ParmError(PExcLongMessage(""));
455 nuit = 1;
456 } else throw ParmError(PExcLongMessage("")); // Mauvaise longueur
457 } else { // Pas de date
458 JJ = MM = AA = -1;
459 }
460
461 if (heure) {
462 const char* p = heure;
463 if (p[0] == '?' && (p[1] == '?' || p[1] == ':')) hh = -1;
464 else {
465 if (!isdigit(p[0])) throw ParmError(PExcLongMessage(""));
466 if (!isdigit(p[1]) && p[1] != ':') throw ParmError(PExcLongMessage(""));
467 hh = atoi(p);
468 }
469
470 if (p[1] == ':') p += 2;
471 else if (p[2] == ':') p+= 3;
472 else throw ParmError(PExcLongMessage(""));
473
474 if (p[0] == '?' && (p[1] == '?' || p[1] == ':')) mm = -1;
475 else {
476 if (!isdigit(p[0])) throw ParmError(PExcLongMessage(""));
477 if (!isdigit(p[1]) && p[1] != '/') throw ParmError(PExcLongMessage(""));
478 mm = atoi(p);
479 }
480
481 if (p[1] == ':') p += 2;
482 else if (p[2] == ':') p+= 3;
483 else throw ParmError(PExcLongMessage(""));
484
485 if (p[0] == '?') ss = -1;
486 else {
487 if (!isdigit(p[0])) throw ParmError(PExcLongMessage(""));
488 ss = atoi(p);
489 }
490 } else {
491 ss = hh = mm = -1;
492 }
493
494 if (tOpt == kLocalTime) {
495 ASSERT(timeZone != NULL);
496 operator -= (timeZone->gmtOffset/24.0);
497 if (timeZone->IsDst(*this))
498 operator -= (timeZone->dstOffset/24.0); // A VERIFIER SANS DOUTE INEXACT
499 }
500
501 if (nuit && !UndetTime() && hh < 12)
502 *this += 1;
503}
504
505/*!
506 Récupère la date sous la forme d'une chaîne 'DD/MM/YYYY'
507 en tOpt = Date::kGMTTime ou Date::kLocalTime.
508*/
509void Date::GetDateStr(char* s, int tOpt) const
510{
511 Date dt(*this);
512 if (tOpt == kLocalTime && !UndetTime()) {
513 ASSERT(timeZone != NULL);
514 dt += timeZone->GetOffset(*this)/24.0;
515 }
516
517 if (dt.AA < 1950 || dt.AA > 1999)
518 sprintf(s, "%02d/%02d/%04d", dt.JJ, dt.MM, dt.AA);
519 else
520 sprintf(s, "%02d/%02d/%02d", dt.JJ, dt.MM, dt.AA-1900);
521
522 if (dt.JJ == -1)
523 s[0] = s[1] = '?';
524 if (dt.MM == -1)
525 s[3] = s[4] = '?';
526 if (dt.AA == -1) {
527 s[6] = s[7] = '?';
528 s[8] = '\0';
529 }
530}
531
532//! Code EROS de la date.
533void Date::GetDateCode(char* s, int tOpt) const
534{
535 Date dt(*this);
536 if (tOpt == kLocalTime && !UndetTime()) {
537 ASSERT(timeZone != NULL);
538 dt += timeZone->GetOffset(*this)/24.0;
539 }
540
541 if (!dt.UndetTime() && dt.hh<12) dt -= 1;
542
543 if (dt.AA != -1) {
544 if (dt.AA < 1990 || dt.AA > 2016) throw ParmError(PExcLongMessage(""));
545 int i = dt.AA - 1990;
546 if (i<10)
547 s[0] = '0' + i;
548 else
549 s[0] = 'a' + i - 10;
550 } else
551 s[0] = '?';
552
553 if (dt.MM != -1)
554 s[1] = 'a' + dt.MM - 1;
555 else
556 s[1] = '?';
557
558 if (dt.JJ != -1)
559 sprintf(s+2, "%02d", dt.JJ);
560 else
561 s[2] = s[3] = '?';
562
563 s[4] = 0;
564}
565
566//! Récupère l'heure sous la forme 'HH:MM:SS'
567void Date::GetTimeStr(char* s, int tOpt) const
568{
569 Date dt(*this);
570 if (tOpt == kLocalTime) {
571 ASSERT(timeZone != NULL);
572 dt += timeZone->GetOffset(*this)/24.0;
573 }
574
575 sprintf(s, "%02d:%02d:%02d", dt.hh, dt.mm, int(dt.ss));
576 if (dt.hh == -1)
577 s[0] = s[1] = '?';
578 if (dt.mm == -1)
579 s[3] = s[4] = '?';
580 if (dt.ss == -1)
581 s[6] = s[7] = '?';
582}
583
584//! Récupèrera un jour le temps sidéral.
585void Date::GetSidTStr(char* s) const
586{
587 strcpy(s,"TOBEDONE!!");
588}
589
590string Date::DateStr(int tOpt) const
591/*!
592 Récupère la date sous la forme d'une chaîne 'DD/MM/YYYY'
593 en tOpt = Date::kGMTTime ou Date::kLocalTime.
594*/
595{
596 char s[20];
597 GetDateStr(s,tOpt);
598 return s;
599}
600
601//! Code EROS de la date.
602string Date::DateCode(int tOpt) const
603{
604 char s[20];
605 GetDateCode(s,tOpt);
606 return s;
607}
608
609//! Récupère l'heure sous la forme 'HH:MM:SS'
610string Date::TimeStr(int tOpt) const
611{
612 char s[20];
613 GetTimeStr(s,tOpt);
614 return s;
615}
616
617//! Récupèrera un jour le temps sidéral.
618string Date::SidTStr() const
619{
620 char s[20];
621 GetSidTStr(s);
622 return s;
623}
624
625//! Retourne le jour dans la semaine, 0-6 avec 0 = Date::jour_Lundi.
626int Date::DayOfWeek(int tOpt) const
627{
628 double t = GetDays();
629 if (tOpt == kLocalTime && hh >=0) {
630 ASSERT(timeZone != NULL);
631 t += timeZone->GetOffset(*this)/24.0;
632 }
633 int ndays = int(t); // nb de jours depuis 0 janvier 1901
634 ndays = (ndays + 1) % 7;
635 if (ndays<0) ndays += 7;
636 return ndays;
637}
638
639/*!
640 Retourne la date correspondant au ieme joursem dans le mois
641 correspondant (exemple, 2e dimanche de mars 1960).
642*/
643short Date::NthMonthDay(short i, short joursem, short mois, short annee)
644{
645 if (i>0) {
646 int jprem = Date(1, mois, annee, 0, 0, 0).DayOfWeek();
647 int d = (joursem - jprem);
648 if (d<0) d+=7;
649 return d + 1 + (i-1)*7;
650 } else {
651 int ider = MonthDays(mois, annee);
652 int jder = Date(ider, mois, annee, 0, 0, 0).DayOfWeek();
653 int d = (joursem - jder);
654 if (d>0) d-=7;
655 return d + ider + (i+1)*7;
656 }
657}
658
659//! Ajout un nombre \b dt en jours
660Date& Date::operator += (double dt)
661{
662 int u = UndetTime();
663 Set(GetDays()+dt);
664 if (u) ss = hh = mm = -1;
665 return *this;
666}
667
668//! retranche un intervalle de temps \b dt en jours
669Date& Date::operator -= (double dt)
670{
671 int u = UndetTime();
672 Set(GetDays()-dt);
673 if (u) ss = hh = mm = -1;
674 return *this;
675}
676
677Date operator + (Date const& d, double dt)
678{
679 Date a(d);
680 a += dt;
681 return a;
682}
683
684Date operator - (Date const& d, double dt)
685{
686 Date a(d);
687 a -= dt;
688 return a;
689}
690
691//! Résultat en jours
692double operator - (Date const& a, Date const& b)
693{
694 if (a.UndetTime() != b.UndetTime()) throw ParmError(PExcLongMessage(""));
695 if (a.UndetDate() != b.UndetDate()) throw ParmError(PExcLongMessage(""));
696 return a.GetDays() - b.GetDays();
697}
698
699//! On n'a pas égalite dès que des éléments déterminés sont différents
700bool operator == (Date const& a, Date const& b)
701{
702 if (a.nuit && a.UndetTime() && !b.nuit && !b.UndetTime() && b.hh<12)
703 {Date d = a+1; d.nuit = 0; return d == b;}
704 else if (b.nuit && b.UndetTime() && !a.nuit && !a.UndetTime() && a.hh<12)
705 {Date d = b+1; d.nuit = 0; return a == d;}
706
707 if (a.AA != -1 && b.AA != -1 && a.AA != b.AA) return false;
708 if (a.MM != -1 && b.MM != -1 && a.MM != b.MM) return false;
709 if (a.JJ != -1 && b.JJ != -1 && a.JJ != b.JJ) return false;
710 if (a.hh != -1 && b.hh != -1 && a.hh != b.hh) return false;
711 if (a.mm != -1 && b.mm != -1 && a.mm != b.mm) return false;
712 if (a.ss != -1 && b.ss != -1 && a.ss != b.ss) return false;
713 return true;
714}
715
716bool operator != (Date const& a, Date const& b)
717{
718 return !(a == b);
719}
720
721//! Inégalité large. Pas de subtilités
722bool operator <= (Date const& a, Date const& b)
723{
724 if (a.nuit && a.UndetTime() && !b.nuit && !b.UndetTime() && b.hh<12)
725 {Date d = a+1; d.nuit = 0; return d <= b;}
726 else if (b.nuit && b.UndetTime() && !a.nuit && !a.UndetTime() && a.hh<12)
727 {Date d = b+1; d.nuit = 0; return a <= d;}
728
729 if (a.AA != -1 && b.AA != -1) {
730 if (a.AA < b.AA) return true;
731 if (a.AA > b.AA) return false;
732 }
733 if (a.MM != -1 && b.MM != -1) {
734 if (a.MM < b.MM) return true;
735 if (a.MM > b.MM) return false;
736 }
737 if (a.JJ != -1 && b.JJ != -1) {
738 if (a.JJ < b.JJ) return true;
739 if (a.JJ > b.JJ) return false;
740 }
741 if (a.hh != -1 && b.hh != -1) {
742 if (a.hh < b.hh) return true;
743 if (a.hh > b.hh) return false;
744 }
745 if (a.mm != -1 && b.mm != -1) {
746 if (a.mm < b.mm) return true;
747 if (a.mm > b.mm) return false;
748 }
749 if (a.ss != -1 && b.ss != -1) {
750 if (a.ss < b.ss) return true;
751 if (a.ss > b.ss) return false;
752 }
753 return true;
754}
755
756/*!
757 Inégalité stricte, codée à partir de la large pour résoudre
758 sans cas particuliers les subtilités
759 01/02/95 < ??/03/95 mais pas 01/02/95 < ??/02/95
760*/
761bool operator < (Date const& a, Date const& b)
762{
763 return (a <= b) && !(a == b);
764}
765
766bool operator >= (Date const& a, Date const& b)
767{
768 return (b <= a);
769}
770
771bool operator > (Date const& a, Date const& b)
772{
773 return (b < a);
774}
775
776ostream& operator << (ostream& s, Date const& d)
777{
778 char x[20];
779 d.GetDateStr(x);
780 s << x << " ";
781 d.GetTimeStr(x);
782 s << x;
783 return s;
784}
785
Note: See TracBrowser for help on using the repository browser.