source: XIOS/trunk/src/calendar.cpp @ 2314

Last change on this file since 2314 was 1357, checked in by rlacroix, 7 years ago

Add some extra checks when switching to the next timestep.

  • 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.4 KB
Line 
1#include "calendar.hpp"
2#include "duration.hpp"
3#include "date.hpp"
4#include "calendar_util.hpp"
5
6namespace xios
7{
8      /// ////////////////////// Définitions ////////////////////// ///
9      CCalendar::CCalendar(void)
10         : CObject()
11         , step(0)
12         , initDate(*this)
13         , timeOrigin(*this)
14         , currentDate(*this)
15      {}
16
17      CCalendar::CCalendar(const StdString& id)
18               : CObject(id)
19               , step(0)
20               , initDate(*this)
21               , timeOrigin(*this)
22               , currentDate(*this)
23      {}
24
25      CCalendar::CCalendar(const StdString& id,
26                           int yr, int mth, int d,
27                           int hr /*= 0*/, int min /*= 0*/, int sec /*= 0*/)
28               : CObject(id)
29               , step(0)
30               , initDate(*this)
31               , timeOrigin(*this)
32               , currentDate(*this)
33      {
34        initializeDate(yr, mth, d, hr, min, sec);
35      }
36
37      CCalendar::CCalendar(const StdString& id, const CDate& startDate)
38               : CObject(id)
39               , step(0)
40               , initDate(startDate)
41               , timeOrigin(startDate)
42               , currentDate(startDate)
43      {
44        // Initialize the dates only in the derivated classes
45        // since we want to use the overloaded virtual functions
46      }
47
48      CCalendar::CCalendar(const StdString& id, const CDate& startDate, const CDate& timeOrigin)
49               : CObject(id)
50               , step(0)
51               , initDate(startDate)
52               , timeOrigin(timeOrigin)
53               , currentDate(startDate)
54      {
55        // Initialize the dates only in the derivated classes
56        // since we want to use the overloaded virtual functions
57      }
58
59      void CCalendar::initializeDate()
60      {
61        if (!initDate.setRelCalendar(*this))
62          ERROR("CCalendar::initializeDate()",
63                "initDate: Bad format or date not conform to the calendar");
64        if (!timeOrigin.setRelCalendar(*this))
65          ERROR("CCalendar::initializeDate()",
66                "timeOrigin: Bad format or date not conform to the calendar");
67        if (!currentDate.setRelCalendar(*this))
68          ERROR("CCalendar::initializeDate()",
69                "currentDate: Bad format or date not conform to the calendar");
70      }
71
72      void CCalendar::initializeDate(int yr, int mth, int d,
73                                     int hr /*= 0*/, int min /*= 0*/, int sec /*= 0*/)
74      {
75        initDate = CDate(*this, yr, mth, d, hr, min, sec);
76        timeOrigin = initDate;
77        currentDate = initDate;
78      }
79
80      void CCalendar::initializeDate(const StdString& dateStr)
81      {
82        initDate = CDate::FromString(dateStr, *this);
83        timeOrigin = initDate;
84        currentDate = initDate;
85      }
86
87      void CCalendar::initializeDate(const StdString& dateStr, const StdString& timeOriginStr)
88      {
89        initDate = CDate::FromString(dateStr, *this);
90        timeOrigin = CDate::FromString(timeOriginStr, *this);
91        currentDate = initDate;
92      }
93
94      CCalendar::~CCalendar(void)
95      { /* Ne rien faire de plus */ }
96
97      ///---------------------------------------------------------------
98
99      StdString CCalendar::toString(void) const
100      {
101         StdOStringStream oss;
102         oss <<   "[type: "   << this->getId()
103             << ", start: "   << this->initDate
104             << ", current: " << this->currentDate << "]";
105         return (oss.str());
106      }
107
108      void CCalendar::fromString(const StdString& str)
109      { ERROR("CCalendar::fromString(str)",
110               << "[ str = " << str << "] Not implemented yet !"); }
111
112      //-----------------------------------------------------------------
113
114      void CCalendar::setTimeStep(const CDuration& timestep)
115      {
116        if (timestep.timestep)
117          ERROR("CCalendar::setTimeStep(const CDuration& timestep)",
118                << "Circular definition of the timestep: the timestep cannot refer to itself.");
119        this->timestep = timestep;
120      }
121
122      int CCalendar::getStep(void) const
123      {
124        return step;
125      }
126
127      const CDate& CCalendar::update(int step)
128      {
129        info(20) << "update step : " << step << " timestep " << this->timestep << std::endl;
130        this->step = step;
131        return (this->currentDate = this->getInitDate() + step * this->timestep);
132      }
133
134      //-----------------------------------------------------------------
135
136      void CCalendar::setInitDate(const CDate& initDate)
137      {
138        if (&initDate.getRelCalendar() != this)
139          ERROR("CCalendar::setInitDate(const CDate& initDate)",
140                << "The init date cannot be attached to another calendar.");
141        this->initDate = initDate;
142      }
143
144      void CCalendar::setTimeOrigin(const CDate& timeOrigin)
145      {
146        if (&timeOrigin.getRelCalendar() != this)
147          ERROR("CCalendar::setInitDate(const CDate& timeOrigin)",
148                << "The time origin cannot be attached to another calendar.");
149        this->timeOrigin = timeOrigin;
150      }
151
152      //-----------------------------------------------------------------
153
154      const CDuration& CCalendar::getTimeStep(void) const { return this->timestep; }
155      const CDate& CCalendar::getInitDate(void) const     { return this->initDate; }
156      const CDate& CCalendar::getTimeOrigin(void) const   { return this->timeOrigin; }
157      const CDate& CCalendar::getCurrentDate(void) const  { return this->currentDate; }
158
159      //-----------------------------------------------------------------
160
161      int CCalendar::getMonthLength(const CDate& date) const
162      { // Retourne la durée du mois en jour.
163        static const int NoLeapMonthLength[] =
164          { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
165        return NoLeapMonthLength[date.getMonth() - 1];
166      }
167
168      StdString CCalendar::getType(void) const { return StdString(this->getId()); }
169
170      int CCalendar::getYearTotalLength(const CDate& date) const { return (365 * 86400); }
171
172      int CCalendar::getYearLength  (void) const { return 12; }
173      int CCalendar::getDayLength   (void) const { return 24; }
174      int CCalendar::getHourLength  (void) const { return 60; }
175      int CCalendar::getMinuteLength(void) const { return 60; }
176      int CCalendar::getDayLengthInSeconds(void) const { return getDayLength() * getHourLength() * getMinuteLength(); }
177
178      bool CCalendar::hasLeapYear() const { return false; }
179
180      StdString CCalendar::getMonthName(int monthId) const
181      {
182        static const StdString MonthNames[] =
183          { "january", "february", "march",     "april" ,  "may",      "june",
184            "july",    "august",   "september", "october", "november", "december" };
185        return MonthNames[monthId - 1];
186      }
187
188      const StdString CCalendar::getMonthShortName(int monthId) const
189      { StdString value = this->getMonthName(monthId); value.resize(3); return value; }
190
191      CDuration& CCalendar::resolve(CDuration& dur, bool noNegativeTime /*= false*/) const
192      {
193        const int hourLengthInSeconds = getHourLength() * getMinuteLength();
194
195        // Simplify the days, hours, minutes and seconds.
196        // First convert them to seconds
197        Time t = Time(modf(dur.day, &dur.day) * getDayLengthInSeconds()
198                        + (dur.hour * getHourLength() + dur.minute) * getMinuteLength() + dur.second);
199        // Then convert back to days
200        dur.day += int(t / getDayLengthInSeconds());
201        t %= getDayLengthInSeconds();
202
203        // Do we allow hour, minute, second to be negative?
204        if (noNegativeTime)
205        {
206          // If we don't, we remove some days until the time is positive
207          while (t < 0)
208          {
209            t += getDayLengthInSeconds();
210            dur.day -= 1.0;
211          }
212        }
213
214        // hours
215        dur.hour = int(t / hourLengthInSeconds);
216        t %= hourLengthInSeconds;
217        // minutes
218        dur.minute = int(t / getMinuteLength());
219        // secondes
220        dur.second = int(t % getMinuteLength());
221
222        // Nothing to do for the months yet since this depends on an actual date
223
224        // Simplify the years
225        dur.month  += modf(dur.year, &dur.year) * getYearLength();
226        dur.year   += int(dur.month) / getYearLength(); dur.month = int(dur.month) % getYearLength();
227
228        return dur;
229      }
230
231      /*! Parse a date using a generic parser. */
232      void CCalendar::parseDateDefault(StdIStream& in, CDate& date)
233      {
234        char sep = '-'; // Le caractÚre c est utilisé pour "recueillir" les séparateurs "/" et ":".
235        char c;
236
237        // Default initialize the date
238        int year = 00, month  = 01, day    = 01;
239        int hour = 00, minute = 00, second = 00;
240
241        in >> year >> c;
242        if (c == sep)
243        {
244          in >> month >> c;
245          if (c == sep)
246          {
247            in >> day;
248            c = in.get();
249            sep = ' ';
250            if (c == sep)
251            {
252              in >> hour >> c;
253              sep = ':';
254              if (c == sep)
255              {
256                in >> minute >> c;
257                if (c == sep)
258                {
259                  in >> second;
260                  in >> c;
261                }
262              }
263            }
264          }
265        }
266
267        date.setDate(year, month, day, hour, minute, second);
268
269        // Delay the verification until we get a calendar we can compare the date to
270        if (date.hasRelCalendar() && !date.checkDate())
271          ERROR("void parseDateDefault(StdIStream& in, CDate& date)",
272                << "Bad date format or not conform to calendar");
273
274        if (c == '+') // We will be adding a duration to the date
275        {
276          CDuration dur;
277          in >> dur;
278          date = date + dur;
279        }
280        else if (!in.eof())
281          ERROR("void parseDateDefault(StdIStream& in, CDate& date)",
282                << "Invalid date format: unexpected trailing character(s)");
283      }
284
285      /*! Parse a date using the calendar's parser. */
286      void CCalendar::parseDate(StdIStream& in, CDate& date) const
287      {
288        parseDateDefault(in, date);
289      }
290
291      /*! Test if a date is valid with regard to the current calendar. */
292      bool CCalendar::checkDate(CDate& date) const
293      {
294        bool isValid = true;
295
296        // Vérification de la valeur du mois.
297        if (date.getMonth() < 1)
298        { isValid = false; date.setMonth(1); }
299        else if (date.getMonth() > getYearLength())
300        { isValid = false; date.setMonth(getYearLength()); }
301
302        // Vérification de la valeur du jour.
303        if (date.getDay() < 1)
304        { isValid = false; date.setDay(1); }
305        else if (date.getDay() > getMonthLength(*this))
306        { isValid = false; date.setDay(getMonthLength(*this)); }
307
308        // Vérification de la valeur de l'heure.
309        if (date.getHour() < 0)
310        { isValid = false; date.setHour(0); }
311        else if (date.getHour() >= getDayLength())
312        { isValid = false; date.setHour(getDayLength() - 1); }
313
314        // Vérification de la valeur des minutes.
315        if (date.getMinute() < 0)
316        { isValid = false; date.setMinute(0); }
317        else if (date.getMinute() >= getHourLength())
318        { isValid = false; date.setMinute(getHourLength() - 1); }
319
320        // Vérification de la valeur des secondes.
321        if (date.getSecond() < 0)
322        { isValid = false; date.setSecond(0); }
323        else if (date.getSecond() >= getMinuteLength())
324        { isValid = false; date.setSecond(getMinuteLength() - 1); }
325
326        return isValid;
327      }
328} // namespace xios
Note: See TracBrowser for help on using the repository browser.