source: XIOS/trunk/src/calendar_util.cpp @ 550

Last change on this file since 550 was 550, checked in by rlacroix, 6 years ago

Add a new user defined calendar type.

A new calendar type "user_defined" is now available. This allows the users to create a custom calendar that we can configured to be suitable for planets other than the Earth.

An user defined calendar is always defined by two mandatory attributes:

  • day_length: the duration of a day, in seconds
  • and either:
    • month_length: an array containing the duration of each month, in days (the number of elements in the array is the number of months in a year)
    • or year_length: the duration of a year, in seconds (in that case, the calendar does not have months).

If the calendar has months (i.e. month_length attribute is set) and only in that case, it is possible to define leap years in order to compensate for the duration of an astronomical year not being a multiple of the day length. The leap years are defined by two mandatory attributes:

  • leap_year_month: the month to which the extra day will be added in case of leap year, expressed as an integer number in the range [1, numberOfMonths]
  • and leap_year_drift: the fraction of a day representing the yearly drift between the calendar year and the astronomical year, expressed as a real number in the range [0, 1).

Optionally, one can define the leap_year_drift_offset attribute to set the original drift at the beginning of the time origin's year, again expressed as a real number in the range [0, 1). If leap_year_drift_offset + leap_year_drift is greater or equal to 1, then the first year will be a leap year.

For example, the following configuration creates a Gregorian-like calendar:

<calendar type="user_defined" start_date="2012-03-01 15:00:00" time_origin="2012-02-28 15:00:00 + 1d" day_length="86400" month_lengths="(1, 12) [31 28 31 30 31 30 31 31 30 31 30 31]" leap_year_month="2" leap_year_drift="0.25" leap_year_drift_offset="0.75" />

Note that dates attributes must be written differently in the configuration file when using an user defined calendar without months:

  • if the year length is greater than the day length, the input format is year-day hh:min:sec instead of year-month-day hh:min:sec
  • if the day length is greater or equal to the year length, the input format is year hh:min:sec.

In all cases, it is still possible to use the date + duration notation to build a date (with both the date and duration parts being optional).

The Fortran interface has been updated accordingly so that xios_define_calendar can accept the new attributes necessary to define custom calendars.

  • 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: 6.9 KB
Line 
1#include "calendar_util.hpp"
2
3namespace xios
4{
5    /// ////////////////////// Définitions ////////////////////// ///
6
7    CDuration operator*(const double& scal, const CDuration& ddr)
8    { return (ddr * scal); }
9
10    CDuration operator-(const CDuration& ddr, const CDuration& dr)
11    {
12      CDuration dur(ddr);
13      dur.year -= dr.year; dur.month  -= dr.month;  dur.day    -= dr.day;
14      dur.hour -= dr.hour; dur.minute -= dr.minute; dur.second -= dr.second; dur.timestep -= dr.timestep;
15      return dur;
16    }
17
18    CDuration operator+(const CDuration& ddr, const CDuration& dr)
19    {
20      CDuration dur(ddr);
21      dur.year += dr.year; dur.month  += dr.month;  dur.day    += dr.day;
22      dur.hour += dr.hour; dur.minute += dr.minute; dur.second += dr.second; dur.timestep += dr.timestep;
23      return dur;
24    }
25
26    CDuration operator*(const CDuration& ddr, const double& scal)
27    {
28      CDuration dur(ddr);
29      dur.year *= scal; dur.month  *= scal; dur.day    *= scal;
30      dur.hour *= scal; dur.minute *= scal; dur.second *= scal; dur.timestep *= scal;
31      return dur;
32    }
33
34    CDuration operator-(const CDuration& ddr)
35    {
36      CDuration dur(ddr);
37      dur.year     = -dur.year;
38      dur.month    = -dur.month;
39      dur.day      = -dur.day;
40      dur.hour     = -dur.hour;
41      dur.minute   = -dur.minute;
42      dur.second   = -dur.second;
43      dur.timestep = -dur.timestep;
44      return dur;
45    }
46
47    //-----------------------------------------------------------------
48
49    CDate operator+(const CDate& dt, const CDuration& dr)
50    {
51      CDuration drr(dr);
52      int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0;
53      const CCalendar& c = dt.getRelCalendar();
54      const bool calendarHasMonths = (c.getYearLength() > 0);
55
56      drr.timestep = 0;
57      if (dr.timestep)
58      {
59        if (c.getTimeStep() == NoneDu)
60          ERROR("operator+(const CDate& dt, const CDuration& dr)",
61                << "Impossible to use the timestep before it is set.");
62        drr = drr + dr.timestep * c.getTimeStep();
63      }
64
65      // Handle the time part of the date
66      drr.second += dt.getSecond();
67      drr.minute += dt.getMinute();
68      drr.hour   += dt.getHour();
69
70      if (!calendarHasMonths) // Handle the day and year immediately if there is no months
71      {
72        drr.day  += dt.getDay() - 1;
73        drr.year += dt.getYear();
74      }
75
76      drr.resolve(c, true); // Force the time to be positive
77
78      second = drr.second;
79      minute = drr.minute;
80      hour   = drr.hour;
81
82      if (calendarHasMonths)
83      {
84        // Ajustement des mois en fonction des jours.
85        CDate dtt(dt);
86        drr.day += dtt.getDay() - 1;
87        dtt.setDay(1);
88
89        if (drr.day >= 0)
90        {
91          for(; c.getMonthLength(dtt) <= drr.day; dtt.addMonth(1))
92          { drr.day -= c.getMonthLength(dtt); drr.month += 1; }
93
94          day = drr.day + 1;
95        }
96        else
97        {
98          dtt.addMonth(-1);
99          drr.month -= 1;
100          for(; c.getMonthLength(dtt) < -drr.day; dtt.addMonth(-1))
101          { drr.day += c.getMonthLength(dtt); drr.month -= 1; }
102          day = c.getMonthLength(dtt) + drr.day + 1;
103        }
104
105        drr.resolve(c);
106
107        // Ajustement des années en fonction des mois.
108        month += dt.getMonth() + drr.month;
109        if (month < 0) { drr.year--; month += c.getYearLength(); }
110        if (month > c.getYearLength()) { drr.year++; month -= c.getYearLength(); }
111        if (month == 0){ month = c.getYearLength(); drr.year--; }
112
113        year += dt.getYear() + drr.year;
114      }
115      else // if (!calendarHasMonths)
116      {
117        day   = drr.day + 1;
118        month = 1;
119        year  = drr.year;
120      }
121
122      return (CDate(c, year, month, day, hour, minute, second));
123    }
124
125    CDate operator-(const CDate& dt, const CDuration& dr) { return (dt + (-dr)); }
126
127    //-----------------------------------------------------------------
128
129    CDuration operator-(const CDate& dt0, const CDate& dt1)
130    {
131      // TODO :: Vérifier que les deux dates (dt0 et dt1) ont une référence vers le même calendrier.
132      CDuration dur =
133      { dt0.getYear() - dt1.getYear(), dt0.getMonth()  - dt1.getMonth() , dt0.getDay()   - dt1.getDay(),
134        dt0.getHour() - dt1.getHour(), dt0.getMinute() - dt1.getMinute(), dt0.getSecond() - dt1.getSecond() };
135      return (dur.resolve(dt0.getRelCalendar()));
136    }
137
138    //-----------------------------------------------------------------
139
140    /// Les opérateurs de comparaison. (Non testés pour le moment)
141
142    bool operator==(const CDuration& ddr, const CDuration& dr)
143    {
144      return ((ddr.year == dr.year) && (ddr.month  == dr.month)  && (dr.day    == ddr.day) &&
145              (ddr.hour == dr.hour) && (ddr.minute == dr.minute) && (dr.second == ddr.second) &&
146              (ddr.timestep == dr.timestep));
147    }
148
149    bool operator!=(const CDuration& ddr, const CDuration& dr)
150    {
151      return !(ddr == dr);
152    }
153
154    bool operator==(const CDate& dt0, const CDate& dt1)
155    {
156      // TODO :: Vérifier que les deux dates (dt0 et dt1) ont une référence vers le même calendrier.
157      return ((dt0.getYear() == dt1.getYear()) && (dt0.getMonth()  == dt1.getMonth())  && (dt1.getDay()    == dt0.getDay()) &&
158              (dt0.getHour() == dt1.getHour()) && (dt0.getMinute() == dt1.getMinute()) && (dt1.getSecond() == dt0.getSecond()));
159    }
160
161    bool operator<(const CDate& dt0, const CDate& dt1)
162    {
163      // TODO :: Vérifier que les deux dates (dt0 et dt1) ont une référence vers le même calendrier.
164      if (dt0.getYear() < dt1.getYear())
165      {
166        return true;
167      }
168      else if (dt0.getYear() == dt1.getYear())
169      {
170        if (dt0.getMonth() < dt1.getMonth())
171        {
172          return true;
173        }
174        else if (dt0.getMonth() == dt1.getMonth())
175        {
176          if (dt0.getDay() < dt1.getDay())
177          {
178             return true;
179          }
180          else if (dt0.getDay() == dt1.getDay())
181          {
182            if (dt0.getHour() < dt1.getHour())
183            {
184              return true;
185            }
186            else if (dt0.getHour() == dt1.getHour())
187            {
188              if (dt0.getMinute() < dt1.getMinute())
189              {
190                return true;
191              }
192              else if (dt0.getMinute() == dt1.getMinute())
193              {
194                if (dt0.getSecond() < dt1.getSecond())
195                  return true;
196              }
197            }
198          }
199        }
200      }
201      return false;
202    }
203
204    //-----------------------------------------------------------------
205
206    bool operator!=(const CDate& dt0, const CDate& dt1) { return !(dt1 == dt0); }
207    bool operator> (const CDate& dt0, const CDate& dt1) { return (dt1 < dt0); }
208    bool operator>=(const CDate& dt0, const CDate& dt1) { return (dt0 > dt1 || dt1 == dt0); }
209    bool operator<=(const CDate& dt0, const CDate& dt1) { return (dt0 < dt1 || dt1 == dt0); }
210
211    ///----------------------------------------------------------------
212
213} // namespace xios
214
215
216
217
218
219
Note: See TracBrowser for help on using the repository browser.