source: XIOS/dev/dev_olga/src/date.cpp @ 983

Last change on this file since 983 was 647, checked in by rlacroix, 9 years ago

Fix a possible overflow when converting a date in seconds since the time origin.

  • Property copyright set to
    Software name : XIOS (Xml I/O Server)
    http://forge.ipsl.jussieu.fr/ioserver
    Creation date : January 2009
    Licence : CeCCIL version2
    see license file in root directory : Licence_CeCILL_V2-en.txt
    or http://www.cecill.info/licences/Licence_CeCILL_V2-en.html
    Holder : CEA/LSCE (Laboratoire des Sciences du CLimat et de l'Environnement)
    CNRS/IPSL (Institut Pierre Simon Laplace)
    Project Manager : Yann Meurdesoif
    yann.meurdesoif@cea.fr
File size: 11.1 KB
Line 
1#include "date.hpp"
2#include "calendar.hpp"
3#include "calendar_type.hpp"
4#include "calendar_util.hpp"
5#include <boost/date_time/gregorian/gregorian.hpp>
6#include <boost/date_time/posix_time/posix_time.hpp>
7
8using namespace boost::posix_time;
9using namespace boost::gregorian;
10
11namespace xios
12{
13      /// ////////////////////// Définitions ////////////////////// ///
14      CDate::CDate(void)
15        : relCalendar(NULL)
16        , year(0), month(1),  day(1)
17        , hour(0), minute(0), second(0)
18      {}
19
20      CDate::CDate(const CCalendar& calendar)
21         : relCalendar(&calendar)
22         , year(0), month(1),  day(1)
23         , hour(0), minute(0), second(0)
24      {}
25
26      CDate::CDate(const CCalendar& calendar,
27                   int yr, int mth, int d,
28                   int hr, int min, int sec)
29         : relCalendar(&calendar)
30         , year(yr), month(mth),  day(d)
31         , hour(hr), minute(min), second(sec)
32      {
33         if (!this->checkDate())
34         {
35            DEBUG(<< "La date initialisée a été modifiée "
36                  << "car elle était incorrecte par rapport au calendrier souhaité.");
37         }
38      }
39
40      CDate::CDate(const CDate& date)
41        : relCalendar(date.relCalendar)
42        , year(date.year), month(date.month),   day(date.day)
43        , hour(date.hour), minute(date.minute), second(date.second)
44      {
45        // Delay the verification until we get a calendar we can compare the date to
46        if (relCalendar && !checkDate())
47        {
48          DEBUG(<< "La date initialisée a été modifiée "
49                << "car elle était incorrecte par rapport au calendrier souhaité.");
50        }
51      }
52
53      CDate::~CDate(void)
54      { /* Ne rien faire de plus */ }
55
56      ///---------------------------------------------------------------
57
58      CDate& CDate::operator=(const CDate& date)
59      {
60         relCalendar = date.relCalendar;
61         year = date.year; month  = date.month; day    = date.day;
62         hour = date.hour; minute = date.minute; second = date.second;
63         return (*this);
64      }
65
66      StdOStream& operator<<(StdOStream& out, const CDate& date)
67      {
68        std::streamsize s;
69        char c;
70
71        int width=4;
72        double maxSize=10000;
73        while (date.year>=maxSize)
74        {
75          maxSize*=10;
76          width++;
77        }
78        s = out.width(width); c = out.fill('0'); out << date.year << '-';
79
80        s = out.width(2); c = out.fill('0'); out << date.month << '-';
81        s = out.width(2); c = out.fill('0'); out << date.day << ' ';
82        s = out.width(2); c = out.fill('0'); out << date.hour << ':';
83        s = out.width(2); c = out.fill('0'); out << date.minute << ':';
84        s = out.width(2); c = out.fill('0'); out << date.second;
85
86        return out;
87      }
88
89      StdIStream& operator>>(StdIStream& in, CDate& date)
90      {
91        if (date.relCalendar)
92          date.relCalendar->parseDate(in, date);
93        else
94          CCalendar::parseDateDefault(in, date);
95
96        return in;
97      }
98
99      CDate::operator Time(void) const // Non vérifiée, pas optimisée ...
100      {
101        // This will check that a calendar was correctly associated to the date
102        const CCalendar& c = getRelCalendar();
103
104        // Todo : Tester si la date courante est supérieure à la date initiale.
105        Time t = getSecondOfYear() - c.getTimeOrigin().getSecondOfYear();
106
107        if (c.hasLeapYear())
108        {
109          for (CDate d(c.getTimeOrigin()); d.getYear() < getYear(); d.setYear(d.getYear() + 1))
110            t += c.getYearTotalLength(d);
111        }
112        else
113          t += Time(getYear() - c.getTimeOrigin().getYear()) * c.getYearTotalLength(*this);
114
115        return t;
116      }
117
118      //----------------------------------------------------------------
119
120      bool CDate::checkDate(void)
121      {
122        // This will also check that a calendar was correctly associated to the date
123        return getRelCalendar().checkDate(*this);
124      }
125
126      //----------------------------------------------------------------
127
128      int CDate::getYear  (void) const { return (this->year  ); }
129      int CDate::getMonth (void) const { return (this->month ); }
130      int CDate::getDay   (void) const { return (this->day   ); }
131      int CDate::getHour  (void) const { return (this->hour  ); }
132      int CDate::getMinute(void) const { return (this->minute); }
133      int CDate::getSecond(void) const { return (this->second); }
134
135      //----------------------------------------------------------------
136
137      const CCalendar& CDate::getRelCalendar(void) const
138      {
139        if (!this->relCalendar)
140          ERROR("const CCalendar& CDate::getRelCalendar(void) const",
141                "Invalid state: The date is not associated with any calendar.");
142        return (*this->relCalendar);
143      }
144
145      bool CDate::hasRelCalendar(void) const
146      { return (this->relCalendar != NULL); }
147
148      //----------------------------------------------------------------
149
150      /*!
151        Get the number of seconds since the beginning of the year.
152        \return the number of seconds since the beginning of the year.
153      */
154      int CDate::getSecondOfYear() const
155      {
156        CDate yearStart(*this);
157        const CCalendar& c = getRelCalendar();
158        int nbDay = 0;
159
160        for (yearStart.setMonth(1); yearStart.getMonth() < getMonth(); yearStart.setMonth(yearStart.getMonth() + 1))
161          nbDay += c.getMonthLength(yearStart);
162
163        // We need to use getDayLengthInSeconds instead of getDayLength since we might
164        // have a non-integral number of hours per day for user defined calendars
165        return ((nbDay + getDay() - 1) * c.getDayLengthInSeconds()
166                  + (getHour() * c.getHourLength() + getMinute()) * c.getMinuteLength() + getSecond());
167      }
168
169      /*!
170        Get the number of days (expressed as a real number) since the beginning of the year.
171        \return the number of days (expressed as a real number) since the beginning of the year.
172      */
173      double CDate::getDayOfYear() const
174      {
175        return double(getSecondOfYear()) / getRelCalendar().getDayLengthInSeconds();
176      }
177
178      /*!
179        Get the fraction of the current year as a real number between 0 and 1.
180        \return the fraction of the current year.
181      */
182      double CDate::getFractionOfYear() const
183      {
184        return double(getSecondOfYear()) / getRelCalendar().getYearTotalLength(*this);
185      }
186
187      /*!
188        Get the number of seconds since the beginning of the day.
189        \return the number of seconds since the beginning of the day.
190      */
191      int CDate::getSecondOfDay() const
192      {
193        const CCalendar& c = getRelCalendar();
194        return ((getHour() * c.getHourLength() + getMinute()) * c.getMinuteLength() + getSecond());
195      }
196
197      /*!
198        Get the fraction of the current day as a real number between 0 and 1.
199        \return the fraction of the current day.
200      */
201      double CDate::getFractionOfDay() const
202      {
203        return double(getSecondOfDay()) / getRelCalendar().getDayLengthInSeconds();
204      }
205
206      //----------------------------------------------------------------
207
208      void CDate::setYear  (int newyear)   { this->year   = newyear; }
209      void CDate::setMonth (int newmonth)  { this->month  = newmonth; }
210      void CDate::setDay   (int newday)    { this->day    = newday; }
211      void CDate::setHour  (int newhour)   { this->hour   = newhour; }
212      void CDate::setMinute(int newminute) { this->minute = newminute; }
213      void CDate::setSecond(int newsecond) { this->second = newsecond; }
214
215      void CDate::setDate(int yr, int mth, int d, int hr, int min, int sec)
216      {
217        this->year   = yr;
218        this->month  = mth;
219        this->day    = d;
220        this->hour   = hr;
221        this->minute = min;
222        this->second = sec;
223      }
224
225      //----------------------------------------------------------------
226
227      void CDate::addMonth(int value)
228      {// Value doit être égale à 1 ou -1.
229        this->month += value;
230        if (this->month == 13) { year++; this->month = 1; }
231        if (this->month == 0)  { year--; this->month = 12; }
232      }
233
234      //----------------------------------------------------------------
235
236      bool CDate::setRelCalendar(const CCalendar& relCalendar)
237      {
238        this->relCalendar = &relCalendar;
239        return this->checkDate();
240      }
241
242      //----------------------------------------------------------------
243
244      CDate CDate::FromString(const StdString& str, const CCalendar& calendar)
245      {
246        CDate dt(calendar);
247        StdIStringStream iss(str);
248        iss >> dt;
249        return dt;
250      }
251
252      //----------------------------------------------------------------
253
254      StdString CDate::getStryyyymmdd(void) const
255      {
256        std::streamsize s;
257        char c;
258
259        ostringstream oss;
260
261        s = oss.width(4); c = oss.fill('0'); oss << year;
262        s = oss.width(2); c = oss.fill('0'); oss << month;
263        s = oss.width(2); c = oss.fill('0'); oss << day;
264
265        return oss.str();
266      }
267
268      string CDate::getStr(const string& str) const
269      {
270        ostringstream oss;
271        int level;
272
273        level=0;
274        for(string::const_iterator it=str.begin();it!=str.end();++it)
275        {
276          if (level==0)
277          {
278            if (*it=='%') level++;
279            else oss<<*it;
280          }
281          else if (level==1)
282          {
283            switch (*it)
284            {
285              case 'y' :
286                oss.width(4); oss.fill('0'); oss << year;
287                level=0;
288                break;
289              case 'm' : // month or minute
290                level++;
291                break;
292              case 'd' :
293                oss.width(2); oss.fill('0'); oss << day;
294                level=0;
295                break;
296              case 'h' :
297                oss.width(2); oss.fill('0'); oss << hour;
298                level=0;
299                break;
300              case 's' :
301                oss.width(2); oss.fill('0'); oss << second;
302                level=0;
303                break;
304              case 'S' : // seconds since time origin
305                oss.width(0); oss << Time(*this);
306                level=0;
307                break;
308              case 'D' : // days since time origin
309                oss.width(0); oss << Time(*this) / getRelCalendar().getDayLengthInSeconds();
310                level=0;
311                break;
312              default :
313                oss<<'%'<<*it;
314                level=0;
315            }
316          }
317          else if (level==2)
318          {
319            switch (*it)
320            {
321              case 'o' : // month
322                oss.width(2); oss.fill('0'); oss << month;
323                level=0;
324                break;
325              case 'i' : //minute
326                oss.width(2); oss.fill('0'); oss << minute;
327                level=0;
328                break;
329              default :
330                oss<<"%m"<<*it;
331                level=0;
332            }
333          }
334        }
335        return oss.str();
336      }
337
338      StdString CDate::toString(void) const
339      {
340        StdOStringStream oss;
341        oss << *this;
342        return oss.str();
343      }
344
345      ///---------------------------------------------------------------
346
347} // namespace xios
Note: See TracBrowser for help on using the repository browser.