Introduction ☂
Since DataFrame is a statistical library, it often deals with time-series data. So, it needs to keep track of time.
The most efficient way of indexing DataFrame by time is to use an index type of time_t for second precision or double or long long integer for more precision. DateTime class provides a more elaborate handling of time. Also, it is a general handy DateTime object. DateTime is a cool and handy object to manipulate date/time with nanosecond precision and multi timezone capability. It has a very simple and intuitive interface that allows you to break date/time to their components, reassemble date/time from their components, advance or pullback date/time with different granularities, and more.
DateTime is one of the types that DataFrame library can read/write from/to files and serialization.
Code structure 🗂
Both the header (DateTime.h) and source (DateTime.cc) files are part of the DataFrame project. They are in the usual include/Utils and src/Utils directories.
Build Instructions 🛠
Follow the DataFrame build instructions.
Example 🧩
This library can have up to Nano second precision depending on what systems calls are available. These are some example code:
DateTime now;
DateTime gmt_now (DT_TIME_ZONE::GMT);
DateTime hk_now (DT_TIME_ZONE::AS_HONG_KONG);
cout << "Local Time is: " << now.string_format (DT_FORMAT::DT_TM2) << std::endl;
cout << "GMT Time is: " << gmt_now.string_format (DT_FORMAT::DT_TM2) << std::endl;
double diff = now.diff_seconds (gmt_now);
const DateTime paris("02/11/2010 12:31:56 PAR", DT_DATE_STYLE::AME_STYLE);
const DateTime tehran("02/11/2010 12:31:56 THR", DT_DATE_STYLE::AME_STYLE);
// Tehran must be 2.5 hours ahead of Paris
//
assert(((paris.time() - tehran.time()) == 9000));
now = 19721202;
gmt_now = 19721210;
diff = now.diff_weekdays (gmt_now);
now.add_days(3)
now.add_weekdays(-2);
For more examples see file date_time_tester.cc
Types 🦋
These constants are used for formatting date/time into strings:
enum class DT_FORMAT : unsigned short int {
AMR_DT = 1, // e.g. 09/16/99
AMR_DT_CTY = 2, // e.g. 09/16/1999
EUR_DT = 3, // e.g. 16/09/99
EUR_DT_CTY = 4, // e.g. 16/09/1999
DT_TM = 5, // e.g. 09/16/1999 13:51:04
SCT_DT = 6, // e.g. Sep 16, 1999
DT_MMDDYYYY = 7, // e.g. 09161999
DT_YYYYMMDD = 8, // e.g. 19990916
DT_TM2 = 9, // e.g. 09/16/1999 13:51:04.124
DT_DATETIME = 10, // e.g. 19990916 13:51:04.124
DT_PRECISE = 11, // e.g. 1516179600.874123908 = Epoch.Nanoseconds
ISO_DT_TM = 12, // e.g. 1999-09-16 13:51:04.000234
ISO_DT = 13, // e.g. 1999-09-16
ISO_DT_NANO = 14, // e.g. 1999-09-16 13:51:04.123456789
AMR_DT_TM = 15, // e.g. 09/16/1999 13:51:04.000234
EUR_DT_TM = 16, // e.g. 16/09/1999 13:51:04.000234
};
These are the available time zones, used in a few methods and constructors.
enum class DT_TIME_ZONE : short int {
LOCAL = -2,
GMT = 0,
AM_BUENOS_AIRES = 1,
AM_CHICAGO = 2,
AM_LOS_ANGELES = 3,
AM_MEXICO_CITY = 4,
AM_NEW_YORK = 5,
AS_DUBAI = 6,
AS_HONG_KONG = 7,
AS_SHANGHAI = 8,
AS_SINGAPORE = 9,
AS_TEHRAN = 10,
AS_TEL_AVIV = 11,
AS_TOKYO = 12,
AU_MELBOURNE = 13,
AU_SYDNEY = 14,
BR_RIO_DE_JANEIRO = 15,
EU_BERLIN = 16,
EU_LONDON = 17,
EU_MOSCOW = 18,
EU_PARIS = 19,
EU_ROME = 20,
EU_VIENNA = 21,
EU_ZURICH = 22,
UTC = 23,
AS_SEOUL = 24,
AS_TAIPEI = 25,
EU_STOCKHOLM = 26,
NZ = 27,
EU_OSLO = 28,
EU_WARSAW = 29,
EU_BUDAPEST = 30
};
Week days: 1 - 7 (Sunday - Saturday), used by various methods:
enum class DT_WEEKDAY : unsigned char {
BAD_DAY = 0,
SUN = 1,
MON = 2,
TUE = 3,
WED = 4,
THU = 5,
FRI = 6,
SAT = 7
};
Months: 1 - 12 (January - December), used by various methods:
enum class DT_MONTH : unsigned char {
BAD_MONTH = 0,
JAN = 1,
FEB = 2,
MAR = 3,
APR = 4,
MAY = 5,
JUN = 6,
JUL = 7,
AUG = 8,
SEP = 9,
OCT = 10,
NOV = 11,
DEC = 12
};
These constants are used for parsing data:
enum class DT_DATE_STYLE : unsigned char {
YYYYMMDD = 1,
AME_STYLE = 2, // MM/DD/YYYY
EUR_STYLE = 3, // YYYY/MM/DD
ISO_STYLE = 3. // YYYY-MM-DD
};
Types used in DateTime class:
using DateType = unsigned int; // YYYYMMDD
using DatePartType = unsigned short int; // year, month etc.
using HourType = unsigned short int; // 0 - 23
using MinuteType = unsigned short int; // 0 - 59
using SecondType = unsigned short int; // 0 - 59
using MillisecondType = short int; // 0 - 999
using MicrosecondType = int; // 0 - 999,999
using NanosecondType = int; // 0 - 999,999,999
using EpochType = time_t; // Signed epoch
using LongTimeType = long long int; // Nano seconds since epoch
This table lists the 3-letter abbreviations for allowable time zones that can appear
in strings parsed by DateTime constructor or assignment operator:
inline static const
std::unordered_map<std::string_view, DT_TIME_ZONE> ZONE_STR_TO_TIME_ZONE {
{ "LOC", DT_TIME_ZONE::LOCAL },
{ "GMT", DT_TIME_ZONE::GMT },
{ "BUE", DT_TIME_ZONE::AM_BUENOS_AIRES },
{ "CHI", DT_TIME_ZONE::AM_CHICAGO },
{ "LAX", DT_TIME_ZONE::AM_LOS_ANGELES },
{ "MEX", DT_TIME_ZONE::AM_MEXICO_CITY },
{ "NYC", DT_TIME_ZONE::AM_NEW_YORK },
{ "DXB", DT_TIME_ZONE::AS_DUBAI },
{ "HKG", DT_TIME_ZONE::AS_HONG_KONG },
{ "SHA", DT_TIME_ZONE::AS_SHANGHAI },
{ "SIN", DT_TIME_ZONE::AS_SINGAPORE },
{ "THR", DT_TIME_ZONE::AS_TEHRAN },
{ "TLV", DT_TIME_ZONE::AS_TEL_AVIV },
{ "TYO", DT_TIME_ZONE::AS_TOKYO },
{ "MEL", DT_TIME_ZONE::AU_MELBOURNE },
{ "SYD", DT_TIME_ZONE::AU_SYDNEY },
{ "RIO", DT_TIME_ZONE::BR_RIO_DE_JANEIRO },
{ "BER", DT_TIME_ZONE::EU_BERLIN },
{ "LON", DT_TIME_ZONE::EU_LONDON },
{ "MOW", DT_TIME_ZONE::EU_MOSCOW },
{ "PAR", DT_TIME_ZONE::EU_PARIS },
{ "ROM", DT_TIME_ZONE::EU_ROME },
{ "VIE", DT_TIME_ZONE::EU_VIENNA },
{ "ZRH", DT_TIME_ZONE::EU_ZURICH },
{ "UTC", DT_TIME_ZONE::UTC },
{ "SEL", DT_TIME_ZONE::AS_SEOUL },
{ "TAY", DT_TIME_ZONE::AS_TAIPEI },
{ "STO", DT_TIME_ZONE::EU_STOCKHOLM },
{ "AKL", DT_TIME_ZONE::NZ },
{ "OSL", DT_TIME_ZONE::EU_OSLO },
{ "WAW", DT_TIME_ZONE::EU_WARSAW },
{ "BUD", DT_TIME_ZONE::EU_BUDAPEST },
};
Member Functions 🗝
// A constructor that creates a DateTime initialized to now.
// tz: Desired time zone from DT_TIME_ZONE above.
//
explicit
DateTime(DT_TIME_ZONE tz = DT_TIME_ZONE::LOCAL) noexcept;
// The constructor that creates a DateTime based on parameters passed.
//
explicit
DateTime(DateType d, // Date e.g. 20180112
HourType hr = 0, // Hour e.g. 13
MinuteType mn = 0, // Minute e.g. 45
SecondType sc = 0, // Second e.g. 45
NanosecondType ns = 0, // Nano-second e.g. 123456789
DT_TIME_ZONE tz = DT_TIME_ZONE::LOCAL) noexcept; // Desired time zone from DT_TIME_ZONE above
// The constructor that creates a DateTime by parsing a string and based on parameters passed.
// Currently, the following formats are supported.
// [TZN] denotes an optional 3-letter time zone abbreviation listed above. The default is local time zone.
// (1) YYYYMMDD [TZN]
// AME_STYLE:
// (2) MM/DD/YYYY [TZN]
// (3) MM/DD/YYYY HH [TZN]
// (4) MM/DD/YYYY HH:MM [TZN]
// (5) MM/DD/YYYY HH:MM:SS [TZN]
// (6) MM/DD/YYYY HH:MM:SS.MMM [TZN] // Milliseconds
// (7) MM/DD/YYYY HH:MM:SS.IIIIII [TZN] // Microseconds
// (8) MM/DD/YYYY HH:MM:SS.NNNNNNNNN [TZN] // Nanoseconds
//
// EUR_STYLE:
// (9) YYYY/MM/DD [TZN]
// (10) YYYY/MM/DD HH [TZN]
// (11) YYYY/MM/DD HH:MM [TZN]
// (12) YYYY/MM/DD HH:MM:SS [TZN]
// (13) YYYY/MM/DD HH:MM:SS.MMM [TZN] // Milliseconds
// (14) YYYY/MM/DD HH:MM:SS.IIIIII [TZN] // Microseconds
// (15) YYYY/MM/DD HH:MM:SS.NNNNNNNNN [TZN] // Nanoseconds
//
// ISO_STYLE:
// (16) YYYY-MM-DD [TZN]
// (17) YYYY-MM-DD HH [TZN]
// (18) YYYY-MM-DD HH:MM [TZN]
// (19) YYYY-MM-DD HH:MM:SS [TZN]
// (20) YYYY-MM-DD HH:MM:SS.MMM [TZN] // Milliseconds
// (21) YYYY-MM-DD HH:MM:SS.IIIIII [TZN] // Microseconds
// (22) YYYY-MM-DD HH:MM:SS.NNNNNNNNN [TZN] // Nanoseconds
//
explicit DateTime(const char *s,
DT_DATE_STYLE ds = DT_DATE_STYLE::YYYYMMDD,
DT_TIME_ZONE tz = DT_TIME_ZONE::LOCAL);
DateTime(const DateTime &that);
DateTime(DateTime &&that);
// A convenient method, if you already have a DateTime instance and want to change the date/time quickly.
// the_time: Time as epoch
//
// nanosec: Nano seconds
//
void set_time(EpochType the_time, NanosecondType nanosec = 0) noexcept;
// Changes the time zone to desired time zone.
// NOTE: This method is not multithread-safe. This method modifies the TZ environment
// variable which changes the time zone for the entire program.
//
// tz: Desired time zone
//
void set_timezone(DT_TIME_ZONE tz);
// Returns the current time zone.
//
DT_TIME_ZONE get_timezone() const;
// Sets self to right-hand-side.
//
// rhs: A date e.g. dt = 20181215
//
DateTime &operator = (DateType rhs);
// Sets self to right-hand-side.
// Currently, the following formats are supported.
// [TZN] denotes an optional 3-letter time zone abbreviation listed above. The default is local time zone.
// (1) YYYYMMDD [TZN]
// (2) YYYYMMDD HH [TZN]
// (3) YYYYMMDD HH:MM [TZN]
// (4) YYYYMMDD HH:MM:SS [TZN]
// (5) YYYYMMDD HH:MM:SS.MMM [TZN]
//
// rhs: A date/time string e.g. dt = “20181215 08:34 GMT”;
//
DateTime &operator = (const char *rhs);
// Compares self with right-hand-side and returns an integer result accordingly.
//
// rhs: Another DateTime instance
//
int dt_compare(const DateTime &rhs) const;
// These methods return the corresponding date/time parts.
//
DateType date() const noexcept; // e.g. 20020303
DatePartType year() const noexcept; // e.g. 1990
DT_MONTH month() const noexcept; // JAN - DEC
DatePartType dmonth() const noexcept; // 1 - 31
DatePartType dyear() const noexcept; // 1 - 366
DT_WEEKDAY dweek() const noexcept; // SUN - SAT
HourType hour() const noexcept; // 0 - 23
MinuteType minute() const noexcept; // 0 - 59
SecondType sec() const noexcept; // 0 - 59
MillisecondType msec() const noexcept; // 0 - 999
MicrosecondType microsec() const noexcept; // 0 - 999,999
NanosecondType nanosec() const noexcept; // 0 - 999,999,999
EpochType time() const noexcept; // Like time()
EpochType days() const noexcept; // Days since epoch
LongTimeType long_time() const noexcept; // Nano seconds since epoch
DatePartType days_in_month() const noexcept; // 28, 29, 30, 31
// These return the diff including the fraction of the unit. This is why they return a double.
// The diff could be +/- based on "this - that"
//
double diff_seconds(const DateTime &that) const;
double diff_minutes(const DateTime &that) const noexcept;
double diff_hours(const DateTime &that) const noexcept;
double diff_days(const DateTime &that) const noexcept;
double diff_weekdays(const DateTime &that) const noexcept;
double diff_weeks(const DateTime &that) const noexcept;
// These methods either advance or pullback the time accordingly. The parameter to these methods could be +/-.
//
void add_nanoseconds(long nanosecs) noexcept;
void add_seconds(EpochType secs) noexcept;
void add_days(long days) noexcept;
void add_weekdays(long days) noexcept;
void add_months(long months) noexcept;
void add_years(long years) noexcept;
// These methods return a Boolean indicating holidays or special days.
//
bool is_weekend() const noexcept;
bool is_newyear() const noexcept;
bool is_leap_year() const noexcept;
bool is_xmas() const noexcept;
bool is_us_business_day() const noexcept;
bool is_us_bank_holiday() const noexcept;
bool is_valid() const noexcept;
// These methods format the date/time into a string based on the format parameter
//
// T: Type of string
// result: a string instance to store the formatted date/time
//
template<typename T>
void date_to_str(DT_FORMAT format, T &result) const;
// format: String format parameter based on DT_FORMAT above
//
std::string string_format(DT_FORMAT format) const;
Global DateTime Operators 🌐
// DateTime output operator to a stream
//
template<typename S>
S &operator << (S &o, const DateTime &rhs);
// DateTime comparison operators
//
bool operator == (const DateTime &lhs, const DateTime &rhs) noexcept;
bool operator != (const DateTime &lhs, const DateTime &rhs) noexcept;
bool operator < (const DateTime &lhs, const DateTime &rhs) noexcept;
bool operator <= (const DateTime &lhs, const DateTime &rhs) noexcept;
bool operator > (const DateTime &lhs, const DateTime &rhs) noexcept;
bool operator >= (const DateTime &lhs, const DateTime &rhs) noexcept;
// DateTime/DateTime arithmetic operators
//
double operator + (const DateTime &lhs, const DateTime &rhs) noexcept;
double operator - (const DateTime &lhs, const DateTime &rhs) noexcept;
double operator * (const DateTime &lhs, const DateTime &rhs) noexcept;
double operator / (const DateTime &lhs, const DateTime &rhs) noexcept;
// DateTime/double arithmetic operators
//
double operator + (const DateTime &lhs, double rhs) noexcept;
double operator - (const DateTime &lhs, double rhs) noexcept;
double operator * (const DateTime &lhs, double rhs) noexcept;
double operator / (const DateTime &lhs, double rhs) noexcept;
DateTime &operator += (DateTime &lhs, double rhs) noexcept;
DateTime &operator -= (DateTime &lhs, double rhs) noexcept;
DateTime &operator *= (DateTime &lhs, double rhs) noexcept;
DateTime &operator /= (DateTime &lhs, double rhs) noexcept;
// double/DateTime arithmetic operators
//
double operator + (double lhs, const DateTime &rhs) noexcept;
double operator - (double lhs, const DateTime &rhs) noexcept;
double operator * (double lhs, const DateTime &rhs) noexcept;
double operator / (double lhs, const DateTime &rhs) noexcept;
double &operator += (double &lhs, const DateTime &rhs) noexcept;
double &operator -= (double &lhs, const DateTime &rhs) noexcept;
double &operator *= (double &lhs, const DateTime &rhs) noexcept;
double &operator /= (double &lhs, const DateTime &rhs) noexcept;
// std::hash specialization for DateTime
//
namespace std {
template<>
struct hash<typename hmdf::DateTime>;
};