calendar.cpp 11 KB

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