#ifndef pdate_Date_h_included
#define pdate_Date_h_included
#include "inc.h"
#include "parse.h"
namespace panda { namespace date {
using panda::time::tz;
using panda::time::dt;
using panda::time::days_in_month;
using panda::time::tzget;
using panda::time::tzlocal;
class DateRel;
class Date {
private:
static const int MAX_FMT = 255;
static char _strfmt[MAX_FMT+1];
static bool _rangeCheck;
tz* _zone;
ptime_t _epoch;
dt _date;
bool _hasEpoch;
bool _hasDate;
bool _normalized;
uint8_t _error;
void eSync ();
void dSync ();
void eCheck ();
void dCheck ();
err_t validateRange();
void dChg();
void dChgAuto();
void eChg();
void _zone_set (tz* zone);
public:
static Date* now ();
static Date* today ();
static void stringFormat (const char*);
static const char* stringFormat ();
static void rangeCheck (bool);
static bool rangeCheck ();
Date (const Date& source);
Date (ptime_t epoch = (ptime_t) ::time(NULL), tz* zone = NULL);
Date (const char* str, size_t len = 0, tz* zone = NULL);
Date (int32_t, ptime_t, ptime_t, ptime_t, ptime_t, ptime_t, int isdst = -1, tz* zone = NULL);
Date (const Date* source, tz* zone = NULL);
~Date ();
Date& operator= (const Date&);
void set (ptime_t, tz* = NULL);
err_t set (const char* str, size_t len = 0, tz* zone = NULL);
err_t set (int32_t, ptime_t, ptime_t, ptime_t, ptime_t, ptime_t, int isdst = -1, tz* zone = NULL);
void set (const Date*, tz* zone = NULL);
err_t change (int32_t year, ptime_t mon=-1, ptime_t day=-1, ptime_t hour=-1, ptime_t min=-1, ptime_t sec=-1, int isdst=-1, tz* zone=NULL);
ptime_t epoch ();
void epoch (ptime_t);
const dt* date ();
bool hasEpoch () const;
bool hasDate () const;
bool normalized () const;
err_t error () const;
void error (err_t);
tz* timezone () const;
void timezone (tz*);
void toTimezone (tz*);
int32_t year ();
void year (int32_t);
int32_t _year ();
void _year (int32_t);
int8_t yr ();
void yr (int);
uint8_t month ();
void month (ptime_t);
uint8_t _month ();
void _month (ptime_t);
uint8_t mday ();
void mday (ptime_t);
uint8_t day ();
void day (ptime_t);
uint8_t hour ();
void hour (ptime_t);
uint8_t min ();
void min (ptime_t);
uint8_t sec ();
void sec (ptime_t);
uint8_t wday ();
void wday (ptime_t);
uint8_t _wday ();
void _wday (ptime_t);
uint8_t ewday ();
void ewday (ptime_t);
uint16_t yday ();
void yday (ptime_t);
uint16_t _yday ();
void _yday (ptime_t);
bool isdst ();
int32_t gmtoff ();
const char* tzabbr ();
int daysInMonth ();
Date* clone (tz* zone = NULL) const;
Date* clone (int32_t year, ptime_t mon=-1, ptime_t day=-1, ptime_t hour=-1, ptime_t min=-1, ptime_t sec=-1, int isdst=-1, tz* zone=NULL) const;
Date* monthBegin ();
Date* monthEnd ();
int compare (Date*);
bool lt (Date*);
bool lte (Date*);
bool gt (Date*);
bool gte (Date*);
bool equals (Date*);
Date* add (const DateRel*);
Date* subtract (const DateRel*);
Date* truncate ();
Date* truncateNew () const;
Date* monthBeginNew () const;
Date* monthEndNew () const;
Date* addNew (const DateRel*) const;
Date* subtractNew (const DateRel*) const;
char* strftime (const char*, char*, size_t);
const char* toString ();
const char* errstr () const;
const char* iso ();
const char* mysql ();
const char* hms ();
const char* ymd ();
const char* mdy ();
const char* dmy ();
const char* meridiam ();
const char* ampm ();
};
inline void Date::dChg() {
_hasEpoch = false;
_normalized = false;
}
inline void Date::dChgAuto() {
dChg();
_date.isdst = -1;
}
inline void Date::eChg() {
_hasDate = false;
_normalized = false;
}
inline Date::Date (const Date& source) : _zone(NULL) {
set(&source);
}
inline Date::Date (ptime_t val, tz* zone) : _zone(NULL), _error(E_OK) {
set(val, zone);
}
inline Date::Date (const char* str, size_t len, tz* zone) : _zone(NULL) {
set(str, len, zone);
}
inline Date::Date (int32_t year, ptime_t mon, ptime_t day, ptime_t hour, ptime_t min, ptime_t sec, int isdst, tz* zone) : _zone(NULL) {
set(year, mon, day, hour, min, sec, isdst, zone);
}
inline Date::Date (const Date* source, tz* zone) : _zone(NULL) {
set(source, zone);
}
inline void Date::set (ptime_t val, tz* zone) {
_zone_set(zone);
epoch(val);
}
inline err_t Date::set (const char* str, size_t len, tz* zone) {
_zone_set(zone);
_error = parse_iso(str, len, &_date);
_hasDate = true;
dChgAuto();
if (_rangeCheck && _error == E_OK) validateRange();
return (err_t) _error;
}
inline err_t Date::set (int32_t year, ptime_t month, ptime_t day, ptime_t hour, ptime_t min, ptime_t sec, int isdst, tz* zone) {
_zone_set(zone);
_error = E_OK;
_date.year = year;
_date.mon = month - 1;
_date.mday = day;
_date.hour = hour;
_date.min = min;
_date.sec = sec;
_date.isdst = isdst;
_hasDate = true;
dChg();
if (_rangeCheck) validateRange();
return (err_t) _error;
}
inline void Date::set (const Date* source, tz* zone) {
_error = source->_error;
if (_zone != NULL) tzfree(_zone);
if (zone == NULL || _error) {
_hasEpoch = source->_hasEpoch;
_hasDate = source->_hasDate;
_normalized = source->_normalized;
_zone = source->_zone;
_epoch = source->_epoch;
if (_hasDate) _date = source->_date;
} else {
_hasEpoch = false;
_hasDate = true;
_normalized = source->_normalized;
_date = source->_date;
_zone = zone;
}
tzcapture(_zone);
}
inline err_t Date::change (int32_t year, ptime_t mon, ptime_t day, ptime_t hour, ptime_t min, ptime_t sec, int isdst, tz* zone) {
dCheck();
_error = E_OK;
if (year >= 0) _date.year = year;
if (mon > 0) _date.mon = mon - 1;
if (day > 0) _date.mday = day;
if (hour >= 0) _date.hour = hour;
if (min >= 0) _date.min = min;
if (sec >= 0) _date.sec = sec;
_date.isdst = isdst;
dChg();
_zone_set(zone);
if (_rangeCheck) validateRange();
return (err_t) _error;
}
inline void Date::_zone_set (tz* zone) {
if (_zone == NULL) {
if (zone == NULL) _zone = tzlocal();
else _zone = zone;
tzcapture(_zone);
} else if (zone != NULL) {
tzfree(_zone);
tzcapture(zone);
_zone = zone;
}
}
inline void Date::eCheck () { if (!_hasEpoch) eSync(); }
inline void Date::dCheck () { if (!_hasDate || !_normalized) dSync(); }
inline ptime_t Date::epoch () { eCheck(); return _epoch; }
inline void Date::epoch (ptime_t val) { _epoch = val; _hasEpoch = true; eChg(); }
inline const dt* Date::date () { dCheck(); return &_date; }
inline bool Date::hasEpoch () const { return _hasEpoch; }
inline bool Date::hasDate () const { return _hasDate; }
inline bool Date::normalized () const { return _normalized; }
inline err_t Date::error () const { return (err_t) _error; }
inline void Date::error (err_t val) { _error = val; epoch(0); }
inline tz* Date::timezone () const { return _zone; }
inline void Date::timezone (tz* zone) {
dCheck();
if (zone == NULL) zone = tzlocal();
dChgAuto();
_zone_set(zone);
}
inline void Date::toTimezone (tz* zone) {
eCheck();
if (zone == NULL) zone = tzlocal();
eChg();
_zone_set(zone);
}
inline int32_t Date::year () { dCheck(); return _date.year; }
inline void Date::year (int32_t val) { dCheck(); _date.year = val; dChgAuto(); }
inline int32_t Date::_year () { return year() - 1900; }
inline void Date::_year (int32_t val) { year(val + 1900); }
inline int8_t Date::yr () { return year() % 100; }
inline void Date::yr (int val) { year( year() - yr() + val ); }
inline uint8_t Date::month () { dCheck(); return _date.mon + 1; }
inline void Date::month (ptime_t val) { dCheck(); _date.mon = val - 1; dChgAuto(); }
inline uint8_t Date::_month () { return month() - 1; }
inline void Date::_month (ptime_t val) { month(val + 1); }
inline uint8_t Date::mday () { dCheck(); return _date.mday; }
inline void Date::mday (ptime_t val) { dCheck(); _date.mday = val; dChgAuto(); }
inline uint8_t Date::day () { return mday(); }
inline void Date::day (ptime_t val) { mday(val); }
inline uint8_t Date::hour () { dCheck(); return _date.hour; }
inline void Date::hour (ptime_t val) { dCheck(); _date.hour = val; dChgAuto(); }
inline uint8_t Date::min () { dCheck(); return _date.min; }
inline void Date::min (ptime_t val) { dCheck(); _date.min = val; dChgAuto(); }
inline uint8_t Date::sec () { dCheck(); return _date.sec; }
inline void Date::sec (ptime_t val) { dCheck(); _date.sec = val; dChgAuto(); }
inline uint8_t Date::wday () { dCheck(); return _date.wday + 1; }
inline void Date::wday (ptime_t val) { dCheck(); _date.mday += val - (_date.wday + 1); dChgAuto(); }
inline uint8_t Date::_wday () { return wday() - 1; }
inline void Date::_wday (ptime_t val) { wday(val + 1); }
inline uint8_t Date::ewday () { dCheck(); return _date.wday == 0 ? 7 : _date.wday; }
inline void Date::ewday (ptime_t val) { _date.mday += val - ewday(); dChgAuto(); }
inline uint16_t Date::yday () { dCheck(); return _date.yday + 1; }
inline void Date::yday (ptime_t val) { dCheck(); _date.mday += val - 1 - _date.yday; dChgAuto(); }
inline uint16_t Date::_yday () { return yday() - 1; }
inline void Date::_yday (ptime_t val) { yday(val + 1); }
inline bool Date::isdst () { dCheck(); return _date.isdst > 0 ? true : false; }
inline int32_t Date::gmtoff () { dCheck(); return _date.gmtoff; }
inline const char* Date::tzabbr () { dCheck(); return _date.zone; }
inline int Date::daysInMonth () { dCheck(); return days_in_month(_date.year, _date.mon); }
inline Date* Date::monthBegin () { mday(1); return this; }
inline Date* Date::monthEnd () { mday(daysInMonth()); return this; }
inline Date* Date::truncate () {
dCheck();
_date.sec = 0;
_date.min = 0;
_date.hour = 0;
dChgAuto();
return this;
}
inline Date* Date::clone (tz* zone) const {
return new Date(this, zone);
}
inline Date* Date::clone (int32_t year, ptime_t mon, ptime_t day, ptime_t hour, ptime_t min, ptime_t sec, int isdst, tz* zone) const {
Date* ret = clone();
ret->change(year, mon, day, hour, min, sec, isdst, zone);
return ret;
}
inline Date* Date::truncateNew () const { return clone()->truncate(); }
inline Date* Date::monthBeginNew () const { return clone()->monthBegin(); }
inline Date* Date::monthEndNew () const { return clone()->monthEnd(); }
inline Date* Date::addNew (const DateRel* operand) const { return clone()->add(operand); }
inline Date* Date::subtractNew (const DateRel* operand) const { return clone()->subtract(operand); }
inline const char* Date::toString () {
if (_error) return NULL;
return _strfmt[0] == '\0' ? iso() : this->strftime(_strfmt, NULL, 0);
}
inline bool Date::equals (Date* operand) { return compare(operand) == 0; }
inline bool Date::lt (Date* operand) { return compare(operand) == -1; }
inline bool Date::lte (Date* operand) { return compare(operand) <= 0; }
inline bool Date::gt (Date* operand) { return compare(operand) == 1; }
inline bool Date::gte (Date* operand) { return compare(operand) >= 0; }
inline Date& Date::operator= (const Date& source) {
if (this != &source) set(&source);
return *this;
}
inline Date::~Date () {
tzfree(_zone);
}
inline Date* Date::now () { return new Date(); }
inline Date* Date::today () { return now()->truncate(); }
inline bool Date::rangeCheck () { return _rangeCheck; }
inline void Date::rangeCheck (bool val) { _rangeCheck = val; }
};};
#endif