//
// File: hzDate.h
//
// Legal Notice: This file is part of the HadronZoo C++ Class Library.
//
// Copyright 2025 HadronZoo Project (http://www.hadronzoo.com)
//
// The HadronZoo C++ Class Library is free software: You can redistribute it, and/or modify it under the terms of the GNU Lesser General Public License, as published by the Free
// Software Foundation, either version 3 of the License, or any later version.
//
// The HadronZoo C++ Class Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License along with the HadronZoo C++ Class Library. If not, see http://www.gnu.org/licenses.
//
//
// Three HadronZoo data and time package provides a set of classes and methods that promote a 'rational and comprehensive' approach to dates and
// times. Much of this package is thus asthetic.
//
// Four classes are provided namely:-
//
// 1) hzTime - Based on the number of seconds since midnight (4 bytes)
// 2) hzSDate - A short form of date based on the number of days since Jan 1st, 0000 (4 bytes)
// 3) hzXDate - A full date and time accurate to microseconds (8 bytes)
//
#ifndef hzDate_h
#define hzDate_h
#include "hzString.h"
#define DAYS_IN_10K 3652425 // days in 10000 years
#define DAYS_IN_2K 730485 // days in 2000 years
#define DAYS_IN_4C 146097 // days in 400 years
#define DAYS_IN_1C 36524 // days in 100 years (in which the 00 year is not a leap)
#define DAYS_IN_LC 36525 // days in 100 years (in which the 00 year is a leap)
#define DAYS_IN_4Y 1461 // days in 4 years
#define DAYS_IN_1Y 365 // days in 1 year
#define DAYS_IN_LY 366 // days in 1 leap year
#define DAYS_B4_EPOCH 719528 // days between 00000101 and 19700101
#define DAYS_EPOCH_END 744383 // days at end of epoch (2030)
#define HOURS_B4_EPOCH 17268672 // hours between 00000101 and 19700101
#define HOURS_EPOCH_END 17865192 // hours at end of epoch (rounded to nearest whole day)
#define SECS_IN_DAY 86400 // seconds in one day
#define SECS_IN_HOUR 3600 // seconds in one day
#define DAYS_EXCEL 693959 // Number of days with Dec 31st 1899 being day 1 (Microsoft Excel dates)
#define NULL_DOW 0xFF
#define NULL_TIME 0x80000000
#define NULL_DATE 0x80000000
enum hzInterval
{
// Category: Scheduling
//
// Represents a standard interval
DAY, // One day
MONTH, // One calender month
YEAR, // One calender year
HOUR, // One hour
MINUTE, // One minute
SECOND // One second
} ;
enum hzDateFmt
{
// Category: Data Processing
//
// Enumerated HadronZoo date presentation formats.
FMT_DT_UNKNOWN = 0x0000, // Invalid or uninitialized format
// Dates contrl flags
FMT_DATE_DOW = 0x0001, // Print the dow (this will appear first)
FMT_DATE_USA = 0x0002, // Where applicable, put day before month
FMT_DATE_ABBR = 0x0004, // Write words (eg dow and monthname) out in short form
FMT_DATE_FULL = 0x0008, // Write words (eg dow and monthname) out in full
// Date only formats
FMT_DATE_DFLT = 0x0010, // Default format YYYYMMDD
FMT_DATE_STD = 0x0020, // Standard format YYYY/MM/DD
FMT_DATE_NORM = 0x0040, // Normal format DD/MM/YYYY (UK) or MM/DD/YYYY (US)
FMT_DATE_FORM = 0x0080, // Day_of_month+monthname+YYYY (UK) or monthname+day_of_month+YYYY (US)
// Time only formats
FMT_TIME_DFLT = 0x0100, // Time HHMMSS
FMT_TIME_STD = 0x0200, // Time HH:MM:SS
FMT_TIME_USEC = 0x0400, // Time HH:MM:SS.uSec
// Timezones (always last)
FMT_TZ_CODE = 0x1000, // Timezone as code
FMT_TZ_NUM = 0x2000, // Timezone as number of hours +/- GMT
FMT_TZ_BOTH = 0x3000, // Timezone as digits plus (code in braces)
// Combined Date & Time formats
FMT_DT_DFLT = FMT_DATE_DFLT + FMT_TIME_DFLT, // YYYYMMDD HHMMSS
FMT_DT_STD = FMT_DATE_STD + FMT_TIME_STD, // YYYY/MM/DD HH:MM:SS
FMT_DT_NORM = FMT_DATE_NORM + FMT_TIME_STD, // DD/MM/YYYY (UK) or MM/DD/YYYY (US) followed by HH:MM:SS
FMT_DT_USEC = FMT_DATE_STD + FMT_TIME_USEC, // YYYYMMDD HH:MM:SS.uSec
FMT_DT_INET = FMT_DATE_DOW + FMT_DATE_FULL + FMT_TIME_STD + FMT_TZ_NUM,
// Day of Week + Day_of_month+monthname+YYYY or monthname+day_of_month+YYYY + HH:MM:SS + timezone
} ;
#define FMT_DT_CONTROL 0x000F // Checks if there are any control settings (dow, long names, american)
#define FMT_DT_MASK_DATES 0x00F0 // Checks if there are any control settings (dow, long names, american)
#define FMT_DT_MASK_TIMES 0x0F00 // Checks if there are any control settings (dow, long names, american)
#define FMT_DT_MASK_TZONE 0xF000 // Checks if there are any timezone settings
/*
** Date calculation macros
*/
#define isleap(y) (!(y%400)?1:!(y%100)?0:!(y%4)?1:0)
#define monlen(y,m) (m==2?isleap(y)?29:28:m==4||m==6||m==9||m==11?30:31)
/*
** Variables for formal date presentation
*/
extern const char* hz_daynames_abrv [] ; // Day names (short)
extern const char* hz_daynames_full [] ; // Day names (full)
extern const char* hz_monthnames_abrv [] ; // Month names (short)
extern const char* hz_monthnames_full [] ; // Month names (full)
/*
** misc non-member functions
*/
hzEcode _daysfromdate (uint32_t& nDays, uint32_t Y, uint32_t M, uint32_t D) ;
void _datefromdays (uint32_t& Y, uint32_t& M, uint32_t& D, uint32_t nDays) ;
/*
** TIME (HHMMSS)
*/
class hzTime
{
// Category: Data
//
// hzTime is a data type to represent the time of day. It has allowed range of 00:00:00 (midnight) thru to 23:59:59. The minimum
// unit is the second.
private:
uint32_t m_secs ; // No of seconds since midnight
public:
hzTime (void) { m_secs = NULL_TIME ; }
~hzTime (void) {}
void SysTime (void) ;
void SetTime (const hzTime& op) ;
hzEcode SetTime (uint32_t h, uint32_t m, uint32_t s) ;
hzEcode SetTime (uint32_t nSecs) ;
hzEcode SetTime (const char* pTimeStr) ;
void Clear (void) { m_secs = NULL_TIME ; }
bool IsNull (void) const { return m_secs == NULL_TIME ? true : false ; }
bool IsSet (void) const { return m_secs == NULL_TIME ? false : true ; }
uint32_t NoSecs (void) const { return m_secs ; }
uint32_t Hour (void) const { return m_secs / 3600 ; }
uint32_t Min (void) const { return (m_secs / 60) % 60 ; }
uint32_t Sec (void) const { return m_secs % 60 ; }
const char* Txt (hzDateFmt eEType = FMT_TIME_DFLT) const ;
// Eval operators
const char* operator* (void) const { return Txt() ; }
// Casting operators
operator const char* (void) const { return Txt() ; }
// Assignment Operators
const hzTime& operator= (const hzTime& op) { m_secs = op.m_secs ; return *this ; }
const hzTime& operator= (uint32_t nSecs) { SetTime(nSecs) ; return *this ; }
const hzTime& operator= (const char* cpTime) { SetTime(cpTime) ; return *this ; }
const hzTime& operator= (const hzString& time) { SetTime(*time) ; return *this ; }
// Arithmetic Operators
bool operator+= (uint32_t nSecs) { m_secs += nSecs ; return true ; }
bool operator-= (uint32_t nSecs) { m_secs -= nSecs ; return true ; }
// Test Operators
bool operator== (const hzTime& op) const { return (m_secs==op.m_secs) ? true : false ; }
bool operator!= (const hzTime& op) const { return (m_secs!=op.m_secs) ? true : false ; }
bool operator< (const hzTime& op) const { return (m_secs< op.m_secs) ? true : false ; }
bool operator<= (const hzTime& op) const { return (m_secs<=op.m_secs) ? true : false ; }
bool operator> (const hzTime& op) const { return (m_secs> op.m_secs) ? true : false ; }
bool operator>= (const hzTime& op) const { return (m_secs>=op.m_secs) ? true : false ; }
bool operator! (void) const { return m_secs == NULL_TIME ? true : false ; }
// Stream operator
friend std::ostream& operator<< (std::ostream& os, const hzTime& Time) ;
} ;
/*
** Short date (YYYYMMDD)
*/
class hzXDate ;
class hzSDate
{
// Category: Data
//
// hzSDate is a data type capable of representing a date. It comprises a single 32 bit variable whose value is the number of days
// since 'the Birth of Christ' or Jan 1st, year 0.
uint32_t m_days ; // No of days since Jan 1, 0000
public:
hzSDate (void) { m_days = NULL_DATE ; }
~hzSDate (void) {}
// Set functions
void SysDate (void) ;
hzEcode SetDate (const hzSDate& op) ;
hzEcode SetDate (uint32_t Y, uint32_t M, uint32_t D) ;
hzEcode SetDate (uint32_t nDays) ;
hzEcode SetDate (const char* pDateStr) ;
void SetByEpoch (uint32_t nEpochTime) ;
// Modify functions
hzEcode AltYear (int32_t x) ;
hzEcode AltMonth (int32_t x) ;
hzEcode AltDay (int32_t x) ;
// Get functions
uint32_t Year (void) const ;
uint32_t Month (void) const ;
uint32_t Day (void) const ;
uint32_t Dow (void) const { return (m_days + 5) % 7 ; }
void Clear (void) { m_days = NULL_DATE ; }
uint32_t NoDays (void) const { return m_days ; }
uint32_t Excel (void) const { return m_days > DAYS_EXCEL ? m_days - DAYS_EXCEL : 0 ; }
bool IsNull (void) const { return m_days == NULL_DATE ? true : false ; }
bool IsSet (void) const { return m_days == NULL_DATE ? false : true ; }
const char* Txt (hzDateFmt eEType = FMT_DATE_DFLT) const ;
// Eval operators
const char* operator* (void) const { return Txt() ; }
// Casting operators
operator const char* (void) const { return Txt() ; }
// Assignment Operators
const hzSDate& operator= (const hzXDate& op) ;
const hzSDate& operator= (const hzSDate& op) { m_days = op.m_days ; return *this ; }
const hzSDate& operator= (uint32_t nDays) { SetDate(nDays) ; return *this ; }
const hzSDate& operator= (const char* cpDate) { SetDate(cpDate) ; return *this ; }
const hzSDate& operator= (const hzString& S) { SetDate(*S) ; return *this ; }
// Arithmetic Operators
const hzSDate& operator+= (uint32_t nDays)
{
// Add to this date, the supplied number of days
m_days += nDays ;
m_days = m_days<0 ? 0 : m_days>DAYS_IN_10K ? DAYS_IN_10K : m_days ;
return *this ;
}
const hzSDate& operator-= (uint32_t nDays)
{
// Subtract from this date, the supplied number of days
m_days -= nDays ;
m_days = m_days<0 ? 0 : m_days>DAYS_IN_10K ? DAYS_IN_10K : m_days ;
return *this ;
}
// Test Operators
bool operator== (const hzXDate& op) const ;
bool operator== (const hzSDate& op) const { return (m_days==op.m_days) ? true : false ; }
bool operator!= (const hzSDate& op) const { return (m_days!=op.m_days) ? true : false ; }
bool operator< (const hzSDate& op) const { return (m_days< op.m_days) ? true : false ; }
bool operator<= (const hzSDate& op) const { return (m_days<=op.m_days) ? true : false ; }
bool operator> (const hzSDate& op) const { return (m_days> op.m_days) ? true : false ; }
bool operator>= (const hzSDate& op) const { return (m_days>=op.m_days) ? true : false ; }
bool operator! (void) const { return m_days == NULL_TIME ? true : false ; }
// Stream operator
friend std::ostream& operator<< (std::ostream& os, const hzSDate& d) ;
} ;
/*
** Full date and time
*/
class hzXDate
{
// Category: Data
//
// A full date and time accurate to microseconds (8 bytes)
private:
uint32_t m_hour ; // no of hours since midnight 0000/01/01
uint32_t m_usec ; // no of microseconds since start of hour
void altsec (int32_t nounits) ;
void altmin (int32_t nounits) ;
void althour (int32_t nounits) ;
void altday (int32_t nounits) ;
void altmon (int32_t nounits) ;
void altyear (int32_t nounits) ;
public:
hzXDate (void) { m_hour = 0 ; m_usec = 0 ; }
~hzXDate (void) {}
bool IsNull (void) const { return !m_hour && !m_usec ? true : false ; }
bool IsSet (void) const { return m_hour || m_usec ? true : false ; }
uint32_t Year (void) const ;
uint32_t Month (void) const ;
uint32_t Day (void) const ;
uint64_t AsVal (void) const ;
uint32_t Hour (void) const { return m_hour%24 ; }
uint32_t Min (void) const { return m_usec/60000000 ; }
uint32_t Sec (void) const { return (m_usec/1000000)%60 ; }
uint32_t uSec (void) const { return m_usec%1000000 ; }
uint32_t Dow (void) const { return ((m_hour/24)+5)%7 ; }
void Clear (void) { m_hour = 0 ; m_usec = 0 ; }
void SysDateTime (void) ;
hzEcode SetDate (const hzXDate& op) { m_hour = op.m_hour ; m_usec = op.m_usec ; return E_OK ; }
hzEcode SetDate (hzSDate& D) { m_hour %= 24 ; m_hour += (D.NoDays() * 24) ; return E_OK ; }
hzEcode SetDate (uint32_t Y, uint32_t M, uint32_t D) ;
hzEcode SetDate (uint32_t nDays) ;
hzEcode SetDate (uint32_t nDays, uint32_t nSecs) ;
hzEcode SetDate (uint64_t xdVal) ;
hzEcode SetDate (const char* pDateStr) ;
hzEcode SetTime (hzTime& T) { m_hour -= m_hour%24 ; m_hour += T.Hour() ; m_usec = (T.NoSecs()/24) * 1000000 ; return E_OK ; }
hzEcode SetTime (const char* cpTimeStr) ;
hzEcode SetTime (uint32_t h, uint32_t m, uint32_t s) ;
hzEcode SetTime (uint32_t nSecs) ;
hzEcode SetDateTime (const char* pDateStr) ;
void SetByEpoch (uint32_t nEpochTime) ;
void SetByEpoch (uint32_t nEpochTime, uint32_t usec) ;
void altdate (hzInterval unit, int32_t nounits) ;
uint32_t DaysInYear (void) const ;
uint32_t NoDays (void) const { return m_hour/24 ; }
uint32_t NoSecs (void) const { return ((m_hour%24) * 3600) + (m_usec/1000000) ; }
uint32_t Excel (void) const { return (m_hour/24) > DAYS_EXCEL ? (m_hour/24) - DAYS_EXCEL : 0 ; }
hzSDate Date (void) const ; // Return the date part only
hzTime Time (void) const ; // Return the time part only
uint32_t AsEpoch (void) const ; // Return the time & date as an epoch
const char* Txt (hzDateFmt eEType = FMT_DT_DFLT) const ;
// Eval operators
const char* operator* (void) const { return Txt() ; }
// Casting operators
operator const char* (void) const { return Txt() ; }
// Assignment Operators
const hzXDate& operator= (const hzXDate& op) { m_hour = op.m_hour ; m_usec = op.m_usec ; return *this ; }
const hzXDate& operator= (const hzSDate& op) { m_hour = op.Day() * 24 ; m_usec = 0 ; return *this ; }
const hzXDate& operator= (uint64_t xdVal) { SetDate(xdVal) ; return *this ; }
const hzXDate& operator= (const hzString& S) { SetDate(*S) ; return *this ; }
const hzXDate& operator= (const char* s) { SetDate(s) ; return *this ; }
// Arithmentic Operators
const hzXDate& operator+= (uint32_t nDays)
{
// Add to this date the supplied number of days
m_hour += (nDays * 24) ;
m_hour = m_hour < 0 ? 0 : m_hour > (DAYS_IN_10K * 24) ? (DAYS_IN_10K * 24) : m_hour ;
return *this ;
}
const hzXDate& operator-= (uint32_t nDays)
{
// Subtract from this date the supplied number of days
m_hour -= (nDays * 24) ;
m_hour = m_hour < 0 ? 0 : m_hour > (DAYS_IN_10K * 24) ? (DAYS_IN_10K * 24) : m_hour ;
return *this ;
}
// Test Operators
bool operator== (const hzXDate& op) const ;
bool operator!= (const hzXDate& op) const ;
bool operator< (const hzXDate& op) const ;
bool operator<= (const hzXDate& op) const ;
bool operator> (const hzXDate& op) const ;
bool operator>= (const hzXDate& op) const ;
bool operator! (void) const { return !m_hour && !m_usec ? true : false ; }
// Static functions
static int32_t datecmp (hzXDate& a, hzXDate& b) ;
// Stream operator
friend std::ostream& operator<< (std::ostream& os, const hzXDate& Date) ;
} ;
// Externals
extern const hzSDate _hz_null_hzSDate ; // Null short date
extern const hzXDate _hz_null_hzXDate ; // Null full date
extern const hzTime _hz_null_hzTime ; // Null time
/*
** Prototypes
*/
hzDateFmt Str2DateFmt (const hzString& dtFmt) ;
const char* DateFmt2Txt (hzDateFmt dtFmt) ;
// Return real time in microseconds/nanoseconds
uint64_t RealtimeMicro (void) ;
uint64_t RealtimeNano (void) ;
#endif // hzDate_h