TECA
The Toolkit for Extreme Climate Analysis
teca_calendar_util.h
Go to the documentation of this file.
1 #ifndef teca_calendar_h
2 #define teca_calendar_h
3 
4 /// @file
5 
6 #include "teca_config.h"
7 #include "teca_variant_array.h"
8 #include "teca_metadata.h"
9 
10 #include <string>
11 #include <ostream>
12 #include <cstring>
13 #include <memory>
14 
15 /// Codes dealing with calendaring
17 {
18 
19 /** @name Gregorian calendar
20  * functions for date computations in gregorian calendar. to use convert the
21  * origin to a gergorian_number do the calculation and convert the number back
22  * into a date useing date_from_gregorian_number. for details about the math
23  * and an explanation of the errors see
24  * http://alcor.concordia.ca/~gpkatch/gdate-algorithm.html
25  */
26 ///@{
27 /** return a date number for the given date that can be used in computations.
28  * input:
29  *
30  * > y : 4 digit year
31  * > m : 2 digit month
32  * > d : 2 digit day
33  *
34  */
36 long gregorian_number(long y, long m, long d);
37 
38 /** input:
39  *
40  * > g : date number computed from gregorian_number
41  *
42  * returns:
43  *
44  * > y : 4 digit year
45  * > m : 2 digit month
46  * > d : 2 digit day
47  *
48  */
50 void date_from_gregorian_number(long g, long &y, long &m, long &d);
51 
52 /**
53  * input:
54  *
55  * > y : 4 digit year
56  * > m : 2 digit month
57  * > d : 2 digit day
58  *
59  * returns:
60  *
61  * true if the date is valid in the gregorian calendar and our conversion
62  * algorithm.
63 */
65 bool valid_gregorian_date(long y, long m, long d);
66 ///@}
67 
68 
69 /// returns one of DJF,MAM,JJA,SON based on the month passed in
71 const char *get_season_name(int month);
72 
73 /** brief
74  * A floating point time value and its corresponding year, month day, hour
75  * minute and second
76  */
78 {
79  time_point() : index(-1), time(0.0), year(0), month(1), day(1),
80  hour(0), minute(0), second(0.0)
81  {}
82 
83  /** Initialize explicitly.
84  * @param[in] i the index of the time value
85  * @param[in] t the time value
86  * @param[in] YYYY the year
87  * @param[in] MM the month
88  * @param[in] DD the day
89  * @param[in] hh the hour
90  * @param[in] mm the minute
91  * @param[in] ss the second
92  */
93  time_point(long i, double t, int YYYY=0, int MM=1, int DD=1,
94  int hh=0, int mm=0, double ss=0.0) : index(i), time(t),
95  year(YYYY), month(MM), day(DD), hour(hh), minute(mm),
96  second(ss)
97  {}
98 
99 
100  /** Initialize from a floating point time value. The calendar and units
101  * must be provided.
102  * @param[in] i the index of the time value
103  * @param[in] t the time value
104  * @param[in] units the units t is in
105  * @param[in] calendar the calendar system the units are in
106  */
107  time_point(long i, double t,
108  const std::string &units, const std::string &calendar);
109 
110  long index;
111  double time;
112  int year;
113  int month;
114  int day;
115  int hour;
116  int minute;
117  double second;
118 };
119 
120 /// An iterator over a series of time intervals
122 {
123 public:
124 
125  interval_iterator() : time(), units(), calendar(),
126  begin(), end(), valid(false)
127  {}
128 
129  virtual ~interval_iterator() {}
130 
131  /** Initialize the iterator from a metadata object following the
132  * conventions defined by the teca_cf_reader.
133  * @returns 0 if successfully initialized
134  */
135  virtual int initialize(const teca_metadata &md);
136 
137  /** Initialize the iterator from a metadata object following the
138  * conventions defined by the teca_cf_reader.
139  * @param[in] md a metadata object
140  * @param[in] first_step the first step to include in the series or 0 to use all
141  * @param[in] last_step the last step to include in the series or -1 to use all
142  * @returns 0 if successfully initialized
143  */
144  virtual int initialize(const teca_metadata &md,
145  long first_step, long last_step);
146 
147  /** Initialize the iterator.
148  * @param[in] t An array of time values
149  * @param[in] units A string units of the time values
150  * @param[in] calendar A string name of the calendar system
151  * @param[in] first_step the first step to include in the series or 0 to use all
152  * @param[in] last_step the last step to include in the series or -1 to use all
153  * @returns 0 if successfully initialized
154  */
156  const std::string &units, const std::string &calendar,
157  long first_step, long last_step) = 0;
158 
159  /// return true if there are more time steps in the sequence
160  virtual bool is_valid() const = 0;
161 
162  /** Get the next interval in the series.
163  * @param[out] first_step The first step in the next element of the series
164  * @param[out] last_step The last step in the next element of the series
165  * @returns 0 if successfully initialized
166  */
167  virtual int get_next_interval(time_point &first_step,
168  time_point &last_step) = 0;
169 
170  /// @returns true if there are more intervals in the series
171  operator bool() const
172  {
173  return this->is_valid();
174  }
175 
176  /// return the first time point in the series
177  const time_point &get_begin() const { return this->begin; }
178 
179  /// return the last time point in the series
180  const time_point &get_end() const { return this->end; }
181 
182 protected:
184  std::string units;
185  std::string calendar;
186  time_point begin;
187  time_point end;
188  bool valid;
189 };
190 
191 /// Enumerate ranges of time steps bracketing seasons
192 /**
193  * An iterator over seasons (DJF, MAM, JJA, SON) between 2 time_point's. A
194  * pair of time steps bracketing the current season are returned at each
195  * iteration. Only full seasonal intervals are processed. If the input data
196  * doesn't start or end on a seasonal boundary, the data from the start to the
197  * first full season, and the data from the end of the last full season to the
198  * end is skipped.
199  */
201 {
202 public:
203  season_iterator() : year(-1), month(-1) {}
204 
205  /// return true if there are more time steps in the sequence
206  bool is_valid() const override;
207 
208  /** Initialize the iterator.
209  *
210  * @param[in] t An array of time values
211  * @param[in] units A string units of the time values
212  * @param[in] calendar A string name of the calendar system
213  * @param[in] first_step the first step to include in the series or 0 to use all
214  * @param[in] last_step the last step to include in the series or -1 to use all
215  * @returns 0 if successfully initialized
216  */
218  const std::string &units, const std::string &calendar,
219  long first_step, long last_step) override;
220 
222 
223  /** return a pair of time steps bracketing the current season.
224  * both returned time steps belong to the current season.
225  */
226  int get_next_interval(time_point &first_step,
227  time_point &last_step) override;
228 
229 private:
230  /** given a year and month, checks that the values fall on a seasonal
231  * boundary. if not, returns the year and month of the start of the next
232  * season.
233  */
234  int get_first_season(int y_in, int m_in, int &y_out, int &m_out) const;
235 
236  /** Given a year and month returns the year month and day of the end of the
237  * season. the input month need not be on a seasonal boundary.
238  */
239  int get_season_end(int y_in, int m_in,
240  int &y_out, int &m_out, int &d_out) const;
241 
242  /** Given a year and month returns the year and month of the next season.
243  * the input momnth doesn't need to be on a seasonal boundary.
244  */
245  int get_next_season(int y_in, int m_in, int &y_out, int &m_out) const;
246 
247 protected:
248  int year;
249  int month;
250 };
251 
252 /// Enumerate ranges of time steps bracketing months
253 /** An iterator over all months between 2 time_point's. A pair
254  * of time steps bracketing the current month are returned at
255  * each iteration.
256  */
258 {
259 public:
260  year_iterator() : year(-1) {}
261 
262  /// return true if there are more time steps in the sequence
263  bool is_valid() const override;
264 
265  /** Initialize the iterator.
266  *
267  * @param[in] t An array of time values
268  * @param[in] units A string units of the time values
269  * @param[in] calendar A string name of the calendar system
270  * @param[in] first_step the first step to include in the series or 0 to use all
271  * @param[in] last_step the last step to include in the series or -1 to use all
272  * @returns 0 if successfully initialized
273  */
275  const std::string &units, const std::string &calendar,
276  long first_step, long last_step) override;
277 
279 
280  /** Return a pair of time steps bracketing the current year.
281  * Both returned time steps belong to the current year.
282  */
283  int get_next_interval(time_point &first_step,
284  time_point &last_step) override;
285 
286 protected:
287  int year;
288 };
289 
290 /// Enumerate ranges of time steps bracketing months
291 /** An iterator over all months between 2 time_point's. A pair
292  * of time steps bracketing the current month are returned at
293  * each iteration.
294  */
296 {
297 public:
298  month_iterator() : year(-1), month(-1) {}
299 
300  /// return true if there are more time steps in the sequence
301  bool is_valid() const override;
302 
303  /** Initialize the iterator.
304  *
305  * @param[in] t An array of time values
306  * @param[in] units A string units of the time values
307  * @param[in] calendar A string name of the calendar system
308  * @param[in] first_step the first step to include in the series or 0 to use all
309  * @param[in] last_step the last step to include in the series or -1 to use all
310  * @returns 0 if successfully initialized
311  */
313  const std::string &units, const std::string &calendar,
314  long first_step, long last_step) override;
315 
317 
318  /** Return a pair of time steps bracketing the current month.
319  * Both returned time steps belong to the current season.
320  */
321  int get_next_interval(time_point &first_step,
322  time_point &last_step) override;
323 
324 protected:
325  int year;
326  int month;
327 };
328 
329 /// Enumerate ranges of time steps bracketing days
330 /** An iterator over all days between 2 time_point's. A pair
331  * of time steps bracketing the current day are returned at
332  * each iteration.
333  */
335 {
336 public:
337  day_iterator() : year(-1), month(-1), day(-1) {}
338 
339  /// return true if there are more time steps in the sequence
340  bool is_valid() const override;
341 
342  /** Initialize the iterator.
343  *
344  * @param[in] t An array of time values
345  * @param[in] units A string units of the time values
346  * @param[in] calendar A string name of the calendar system
347  * @param[in] first_step the first step to include in the series or 0 to use all
348  * @param[in] last_step the last step to include in the series or -1 to use all
349  * @returns 0 if successfully initialized
350  */
352  const std::string &units, const std::string &calendar,
353  long first_step, long last_step) override;
354 
356 
357  /** Return a pair of time steps bracketing the current day
358  * Both returned time steps belong to the current day.
359  */
360  int get_next_interval(time_point &first_step,
361  time_point &last_step) override;
362 
363 protected:
364  int year;
365  int month;
366  int day;
367 };
368 
370 {
371 public:
372  n_steps_iterator() : index(-1), number_of_steps(0) {}
373 
374  /// return true if there are more time steps in the sequence
375  bool is_valid() const override;
376 
377  /** Initialize the iterator.
378  *
379  * @param[in] t An array of time values
380  * @param[in] units A string units of the time values
381  * @param[in] calendar A string name of the calendar system
382  * @param[in] first_step the first step to include in the series or 0 to use all
383  * @param[in] last_step the last step to include in the series or -1 to use all
384  * @returns 0 if successfully initialized
385  */
387  const std::string &units, const std::string &calendar,
388  long first_step, long last_step) override;
389 
391 
392  /** Return a pair of time steps bracketing the current block of n steps.
393  * Both returned time steps belong to the current block of steps.
394  */
395  int get_next_interval(time_point &first_step,
396  time_point &last_step) override;
397 
398  void set_number_of_steps(long n);
399 
400 protected:
401  long index;
402  long number_of_steps;
403 };
404 
406 {
407 public:
408  all_iterator() : index(-1) {}
409 
410  /// return true if there are more time steps in the sequence
411  bool is_valid() const override;
412 
413  /** Initialize the iterator.
414  *
415  * @param[in] t An array of time values
416  * @param[in] units A string units of the time values
417  * @param[in] calendar A string name of the calendar system
418  * @param[in] first_step the first step to include in the series or 0 to use all
419  * @param[in] last_step the last step to include in the series or -1 to use all
420  * @returns 0 if successfully initialized
421  */
423  const std::string &units, const std::string &calendar,
424  long first_step, long last_step) override;
425 
427 
428  /** Return a pair of time steps bracketing the current and only block of
429  * steps. Both returned time steps belong to the current block of steps.
430  */
431  int get_next_interval(time_point &first_step,
432  time_point &last_step) override;
433 
434 protected:
435  long index;
436 };
437 
438 using p_interval_iterator = std::shared_ptr<interval_iterator>;
439 
440 /// A factory for interval_iterator
442 {
443 public:
444  /** Allocate and return an instance of the named iterator
445  * @param[in] interval Name of the desired interval iterator. One of daily,
446  * monthly, seasonal, yearly, n_steps, or all
447  * @returns an instance of interval_iterator
448  */
449  static p_interval_iterator New(const std::string &interval);
450 
451  /// The available intervals
452  enum {invalid = 0, daily = 2, monthly = 3, seasonal = 4, yearly = 5, n_steps = 6, all = 7};
453 
454  /** Allocate and return an instance of the named iterator
455  * @param[in] interval Id of the desired interval iterator. One of daily,
456  * monthly, seasonal, or yearly
457  * @returns an instance of interval_iterator
458  */
459  static p_interval_iterator New(int interval);
460 };
461 
462 }
463 
464 /// send the time_point to a stream in humnan readable form
466 std::ostream &operator<<(std::ostream &os,
467  const teca_calendar_util::time_point &tpt);
468 
469 #endif
Definition: teca_calendar_util.h:406
bool is_valid() const override
return true if there are more time steps in the sequence
int initialize(const const_p_teca_variant_array &t, const std::string &units, const std::string &calendar, long first_step, long last_step) override
int get_next_interval(time_point &first_step, time_point &last_step) override
Enumerate ranges of time steps bracketing days.
Definition: teca_calendar_util.h:335
int get_next_interval(time_point &first_step, time_point &last_step) override
bool is_valid() const override
return true if there are more time steps in the sequence
int initialize(const const_p_teca_variant_array &t, const std::string &units, const std::string &calendar, long first_step, long last_step) override
A factory for interval_iterator.
Definition: teca_calendar_util.h:442
static p_interval_iterator New(const std::string &interval)
static p_interval_iterator New(int interval)
An iterator over a series of time intervals.
Definition: teca_calendar_util.h:122
const time_point & get_begin() const
return the first time point in the series
Definition: teca_calendar_util.h:177
virtual bool is_valid() const =0
return true if there are more time steps in the sequence
const time_point & get_end() const
return the last time point in the series
Definition: teca_calendar_util.h:180
virtual int initialize(const teca_metadata &md)
virtual int get_next_interval(time_point &first_step, time_point &last_step)=0
virtual int initialize(const const_p_teca_variant_array &t, const std::string &units, const std::string &calendar, long first_step, long last_step)=0
virtual int initialize(const teca_metadata &md, long first_step, long last_step)
Enumerate ranges of time steps bracketing months.
Definition: teca_calendar_util.h:296
bool is_valid() const override
return true if there are more time steps in the sequence
int get_next_interval(time_point &first_step, time_point &last_step) override
int initialize(const const_p_teca_variant_array &t, const std::string &units, const std::string &calendar, long first_step, long last_step) override
Definition: teca_calendar_util.h:370
int get_next_interval(time_point &first_step, time_point &last_step) override
int initialize(const const_p_teca_variant_array &t, const std::string &units, const std::string &calendar, long first_step, long last_step) override
bool is_valid() const override
return true if there are more time steps in the sequence
Enumerate ranges of time steps bracketing seasons.
Definition: teca_calendar_util.h:201
bool is_valid() const override
return true if there are more time steps in the sequence
int get_next_interval(time_point &first_step, time_point &last_step) override
int initialize(const const_p_teca_variant_array &t, const std::string &units, const std::string &calendar, long first_step, long last_step) override
Enumerate ranges of time steps bracketing months.
Definition: teca_calendar_util.h:258
int initialize(const const_p_teca_variant_array &t, const std::string &units, const std::string &calendar, long first_step, long last_step) override
bool is_valid() const override
return true if there are more time steps in the sequence
int get_next_interval(time_point &first_step, time_point &last_step) override
A generic container for meta data in the form of name=value pairs.
Definition: teca_metadata.h:22
Codes dealing with calendaring.
Definition: teca_calendar_util.h:17
TECA_EXPORT const char * get_season_name(int month)
returns one of DJF,MAM,JJA,SON based on the month passed in
TECA_EXPORT bool valid_gregorian_date(long y, long m, long d)
TECA_EXPORT void date_from_gregorian_number(long g, long &y, long &m, long &d)
TECA_EXPORT long gregorian_number(long y, long m, long d)
p_teca_error_handler error_handler TECA_EXPORT
The global error handler instance.
Definition: teca_calendar_util.h:78
time_point(long i, double t, const std::string &units, const std::string &calendar)
time_point(long i, double t, int YYYY=0, int MM=1, int DD=1, int hh=0, int mm=0, double ss=0.0)
Definition: teca_calendar_util.h:93
TECA_EXPORT std::ostream & operator<<(std::ostream &os, const teca_calendar_util::time_point &tpt)
send the time_point to a stream in humnan readable form
std::shared_ptr< const teca_variant_array > const_p_teca_variant_array
Definition: teca_variant_array.h:27