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

Last change on this file since 2650 was 2615, checked in by cmv, 21 years ago

using namespace sophya enleve de machdefs.h, nouveau sopnamsp.h cmv 10/09/2004

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