//
// File: hzDate.cpp
//
// 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.
//
//
// Implimentation of Dates
//
#include <iostream>
#include <sys/time.h>
#include <stdarg.h>
#include "hzChars.h"
#include "hzTextproc.h"
#include "hzErrcode.h"
#include "hzProcess.h"
#include "hzDate.h"
using namespace std ;
/*
** Global Variables
*/
global const char* hz_daynames_abrv [] =
{
// Abreviated day names (Default language English)
"Mon","Tue","Wed","Thu","Fri","Sat","Sun",""
} ;
global const char* hz_daynames_full [] =
{
// Full day names (Default language English)
"Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday",""
} ;
global const char* hz_monthnames_abrv [] =
{
// Abreviated month names (Default language English)
"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec",""
} ;
global const char* hz_monthnames_full [] =
{
// Full month names (Default language English)
"January","February","March","April","May","June","July","August","September","October","November","December",""
} ;
global const hzXDate _hz_null_hzXDate ; // Null full date
global const hzSDate _hz_null_hzSDate ; // Null short date
global const hzTime _hz_null_hzTime ; // Null time
struct hzTimezone
{
// Category: Time
//
// International Timezone. Maps timezone code to GMT offset
const char* code ; // Timezone code
int32_t hour ; // Hours ahead of GMT
int32_t min ; // Minutes ahead of GMT
void clear (void) { code = 0 ; hour = min = 0 ; }
} ;
global hzTimezone _hzGlobal_Timezones [] =
{
{ "ADT", -3, 0, }, // Atlantic Daylight Time North America UTC - 3 hours
{ "AFT", 4, 0, }, // Afghanistan Time Asia UTC + 4:30 hours
{ "AKDT", -8, 0, }, // Alaska Daylight Time North America UTC - 8 hours
{ "AKST", -9, 0, }, // Alaska Std Time North America UTC - 9 hours
{ "ALMT", 6, 0, }, // Alma-Ata Time Asia UTC + 6 hours
{ "AMST", 5, 0, }, // Armenia Summer Time Asia UTC + 5 hours
{ "AMST", -3, 0, }, // Amazon Summer Time South America UTC - 3 hours
{ "AMT", 4, 0, }, // Armenia Time Asia UTC + 4 hours
{ "AMT", -4, 0, }, // Amazon Time South America UTC - 4 hours
{ "ANAST", 12, 0, }, // Anadyr Summer Time Asia UTC + 12 hours
{ "ANAT", 12, 0, }, // Anadyr Time Asia UTC + 12 hours
{ "AQTT", 5, 0, }, // Aqtobe Time Asia UTC + 5 hours
{ "ART", -3, 0, }, // Argentina Time South America UTC - 3 hours
{ "AST", 3, 0, }, // Arabia Std Time Asia UTC + 3 hours
{ "AST", -4, 0, }, // Atlantic Std Time Atlantic UTC - 4 hours
{ "AST", -4, 0, }, // Atlantic Std Time Caribbean UTC - 4 hours
{ "AST", -4, 0, }, // Atlantic Std Time North America UTC - 4 hours
{ "AZOST", 4, 0, }, // Azores Summer Time Atlantic UTC
{ "AZOT", -1, 0, }, // Azores Time Atlantic UTC - 1 hour
{ "AZST", 5, 0, }, // Azerbaijan Summer Time Asia UTC + 5 hours
{ "AZT", 4, 0, }, // Azerbaijan Time Asia UTC + 4 hours
{ "BNT", 8, 0, }, // Brunei Darussalam Time Asia UTC + 8 hours
{ "BOT", -4, 0, }, // Bolivia Time South America UTC - 4 hours
{ "BRST", -2, 0, }, // Brasilia Summer Time South America UTC - 2 hours
{ "BRT", -3, 0, }, // Brasa time South America UTC - 3 hours
{ "BST", 6, 0, }, // Bangladesh Std Time Asia UTC + 6 hours
{ "BST", 1, 0, }, // British Summer Time Europe UTC + 1 hour
{ "BTT", 6, 0, }, // Bhutan Time Asia UTC + 6 hours
{ "CAST", 8, 0, }, // Casey Time Antarctica UTC + 8 hours
{ "CAT", 2, 0, }, // Central Africa Time Africa UTC + 2 hours
{ "CCT", 6, 0, }, // Cocos Islands Time Indian Ocean UTC + 6:30 hours
{ "CDT", 10, 0, }, // Central Daylight Time Australia UTC + 10:30 hours
{ "CDT", -4, 0, }, // Cuba Daylight Time Caribbean UTC - 4 hours
{ "CDT", -5, 0, }, // Central Daylight Time North America UTC - 5 hours
{ "CEST", 2, 0, }, // Central European Summer Time Europe UTC + 2 hours
{ "CET", 1, 0, }, // Central European Time Africa UTC + 1 hour
{ "CET", 1, 0, }, // Central European Time Europe UTC + 1 hour
{ "CHADT", 13, 45, }, // Chatham Island Daylight Time Pacific UTC + 13:45 hours
{ "CHAST", 12, 45, }, // Chatham Island Std Time Pacific UTC + 12:45 hours
{ "CKT", -10, 0, }, // Cook Island Time Pacific UTC - 10 hours
{ "CLST", -3, 0, }, // Chile Summer Time South America UTC - 3 hours
{ "CLT", -4, 0, }, // Chile Std Time South America UTC - 4 hours
{ "COT", -5, 0, }, // Colombia Time South America UTC - 5 hours
{ "CST", 8, 0, }, // China Std Time Asia UTC + 8 hours
{ "CST", 9, 30, }, // Central Std Time Australia UTC + 9:30 hours
{ "CST", -6, 0, }, // Central Std Time Central America UTC - 6 hours
{ "CST", -5, 0, }, // Cuba Std Time Caribbean UTC - 5 hours
{ "CST", -6, 0, }, // Central Std Time North America UTC - 6 hours
{ "CVT", -1, 0, }, // Cape Verde Time Africa UTC - 1 hour
{ "CXT", 7, 0, }, // Christmas Island Time Australia UTC + 7 hours
{ "ChST", 10, 0, }, // Chamorro Std Time Pacific UTC + 10 hours
{ "DAVT", 7, 0, }, // Davis Time Antarctica UTC + 7 hours
{ "EASST", -5, 0, }, // Easter Island Summer Time Pacific UTC - 5 hours
{ "EAST", -6, 0, }, // Easter Island Std Time Pacific UTC - 6 hours
{ "EAT", 3, 0, }, // Eastern Africa Time Africa UTC + 3 hours
{ "EAT", 3, 0, }, // East Africa Time Indian Ocean UTC + 3 hours
{ "ECT", -5, 0, }, // Ecuador Time South America UTC - 5 hours
{ "EDT", 11, 0, }, // Eastern Daylight Time Australia UTC + 11 hours
{ "EDT", -4, 0, }, // Eastern Daylight Time Caribbean UTC - 4 hours
{ "EDT", -4, 0, }, // Eastern Daylight Time North America UTC - 4 hours
{ "EDT", 11, 0, }, // Eastern Daylight Time Pacific UTC + 11 hours
{ "EEST", 3, 0, }, // Eastern European Summer Time Africa UTC + 3 hours
{ "EEST", 3, 0, }, // Eastern European Summer Time Asia UTC + 3 hours
{ "EEST", 3, 0, }, // Eastern European Summer Time Europe UTC + 3 hours
{ "EET", 2, 0, }, // Eastern European Time Africa UTC + 2 hours
{ "EET", 2, 0, }, // Eastern European Time Asia UTC + 2 hours
{ "EET", 2, 0, }, // Eastern European Time Europe UTC + 2 hours
{ "EGST", 0, 0, }, // East Greenland Summer Time North America UTC
{ "EGT", -1, 0, }, // East Greenland Time North America UTC - 1 hour
{ "EST", 10, 0, }, // Eastern Std Time Australia UTC + 10 hours
{ "EST", -5, 0, }, // Eastern Std Time Central America UTC - 5 hours
{ "EST", -5, 0, }, // Eastern Std Time Caribbean UTC - 5 hours
{ "EST", -5, 0, }, // Eastern Standard Time North America UTC - 5 hours
{ "ET", -5, 0, }, // Tiempo del Este Central America UTC - 5 hours
{ "ET", -5, 0, }, // Tiempo del Este Caribbean UTC - 5 hours
{ "ET", -5, 0, }, // Tiempo Del Este North America UTC - 5 hours
{ "FJST", 13, 0, }, // Fiji Summer Time Pacific UTC + 13 hours
{ "FJT", 12, 0, }, // Fiji Time Pacific UTC + 12 hours
{ "FKST", -3, 0, }, // Falkland Islands Summer Time South America UTC - 3 hours
{ "FKT", -4, 0, }, // Falkland Island Time South America UTC - 4 hours
{ "FNT", -2, 0, }, // Fernando de Noronha Time South America UTC - 2 hours
{ "GALT", -6, 0, }, // Galapagos Time Pacific UTC - 6 hours
{ "GAMT", -9, 0, }, // Gambier Time Pacific UTC - 9 hours
{ "GET", 4, 0, }, // Georgia Std Time Asia UTC + 4 hours
{ "GFT", 0, 0, }, // French Guiana Time South America UTC - 3 hours
{ "GILT", 0, 0, }, // Gilbert Island Time Pacific UTC + 12 hours
{ "GMT", 0, 0, }, // Greenwich Mean Time Africa UTC
{ "GMT", 0, 0, }, // Greenwich Mean Time Europe UTC
{ "GST", 0, 0, }, // Gulf Std Time Asia UTC + 4 hours
{ "GYT", 0, 0, }, // Guyana Time South America UTC - 4 hours
{ "HAA", 0, 0, }, // Heure Avanc l'Atlantique Atlantic UTC - 3 hours
{ "HAA", 0, 0, }, // Heure Avanc l'Atlantique North America UTC - 3 hours
{ "HAC", 0, 0, }, // Heure Avanc Centre North America UTC - 5 hours
{ "HADT", 0, 0, }, // Hawaii-Aleutian Daylight Time North America UTC - 9 hours
{ "HAE", 0, 0, }, // Heure Avanc l'Est Caribbean UTC - 4 hours
{ "HAE", 0, 0, }, // Heure Avanc l'Est North America UTC - 4 hours
{ "HAP", 0, 0, }, // Heure Avanc Pacifique North America UTC - 7 hours
{ "HAR", 0, 0, }, // Heure Avanc Rocheuses North America UTC - 6 hours
{ "HAST", 0, 0, }, // Hawaii-Aleutian Std Time North America UTC - 10 hours
{ "HAT", 0, 0, }, // Heure Avanc Terre-Neuve North America UTC - 2:30 hours
{ "HAY", 0, 0, }, // Heure Avanc Yukon North America UTC - 8 hours
{ "HKT", 0, 0, }, // Hong Kong Time Asia UTC + 8 hours
{ "HLV", 0, 0, }, // Hora Legal de Venezuela South America UTC - 4:30 hours
{ "HNA", 0, 0, }, // Heure Normale de l'Atlantique Atlantic UTC - 4 hours
{ "HNA", 0, 0, }, // Heure Normale de l'Atlantique Caribbean UTC - 4 hours
{ "HNA", 0, 0, }, // Heure Normale de l'Atlantique North America UTC - 4 hours
{ "HNC", 0, 0, }, // Heure Normale du Centre Central America UTC - 6 hours
{ "HNC", 0, 0, }, // Heure Normale du Centre North America UTC - 6 hours
{ "HNE", 0, 0, }, // Heure Normale de l'Est Central America UTC - 5 hours
{ "HNE", 0, 0, }, // Heure Normale de l'Est Caribbean UTC - 5 hours
{ "HNE", 0, 0, }, // Heure Normale de l'Est North America UTC - 5 hours
{ "HNP", 0, 0, }, // Heure Normale du Pacifique North America UTC - 8 hours
{ "HNR", 0, 0, }, // Heure Normale des Rocheuses North America UTC - 7 hours
{ "HNT", 0, 0, }, // Heure Normale de Terre-Neuve North America UTC - 3:30 hours
{ "HNY", 0, 0, }, // Heure Normale du Yukon North America UTC - 9 hours
{ "HOVT", 0, 0, }, // Hovd Time Asia UTC + 7 hours
{ "ICT", 0, 0, }, // Indochina Time Asia UTC + 7 hours
{ "IDT", 0, 0, }, // Israel Daylight Time Asia UTC + 3 hours
{ "IOT", 0, 0, }, // Indian Chagos Time Indian Ocean UTC + 6 hours
{ "IRDT", 0, 0, }, // Iran Daylight Time Asia UTC + 4:30 hours
{ "IRKST", 0, 0, }, // Irkutsk Summer Time Asia UTC + 9 hours
{ "IRKT", 0, 0, }, // Irkutsk Time Asia UTC + 8 hours
{ "IRST", 0, 0, }, // Iran Std Time Asia UTC + 3:30 hours
{ "IST", 0, 0, }, // Israel Std Time Asia UTC + 2 hours
{ "IST", 0, 0, }, // India Std Time Asia UTC + 5:30 hours
{ "IST", 0, 0, }, // Irish Std Time Europe UTC + 1 hour
{ "JST", 0, 0, }, // Japan Std Time Asia UTC + 9 hours
{ "KGT", 0, 0, }, // Kyrgyzstan Time Asia UTC + 6 hours
{ "KRAST", 0, 0, }, // Krasnoyarsk Summer Time Asia UTC + 8 hours
{ "KRAT", 0, 0, }, // Krasnoyarsk Time Asia UTC + 7 hours
{ "KST", 0, 0, }, // Korea Std Time Asia UTC + 9 hours
{ "KUYT", 0, 0, }, // Kuybyshev Time Europe UTC + 4 hours
{ "LHDT", 0, 0, }, // Lord Howe Daylight Time Australia UTC + 11 hours
{ "LHST", 0, 0, }, // Lord Howe Std Time Australia UTC + 10:30 hours
{ "LINT", 0, 0, }, // Line Islands Time Pacific UTC + 14 hours
{ "MAGST", 0, 0, }, // Magadan Summer Time Asia UTC + 12 hours
{ "MAGT", 0, 0, }, // Magadan Time Asia UTC + 11 hours
{ "MART", 0, 0, }, // Marquesas Time Pacific UTC - 9:30 hours
{ "MAWT", 0, 0, }, // Mawson Time Antarctica UTC + 5 hours
{ "MDT", 0, 0, }, // Mountain Daylight Time North America UTC - 6 hours
{ "MHT", 0, 0, }, // Marshall Islands Time Pacific UTC + 12 hours
{ "MMT", 0, 0, }, // Myanmar Time Asia UTC + 6:30 hours
{ "MSD", 0, 0, }, // Moscow Daylight Time Europe UTC + 4 hours
{ "MSK", 0, 0, }, // Moscow Std Time Europe UTC + 3 hours
{ "MST", 0, 0, }, // Mountain Std Time North America UTC - 7 hours
{ "MUT", 0, 0, }, // Mauritius Time Africa UTC + 4 hours
{ "MVT", 0, 0, }, // Maldives Time Asia UTC + 5 hours
{ "MYT", 0, 0, }, // Malaysia Time Asia UTC + 8 hours
{ "NCT", 0, 0, }, // New Caledonia Time Pacific UTC + 11 hours
{ "NDT", 0, 0, }, // Newfoundland Daylight Time North America UTC - 2:30 hours
{ "NFT", 0, 0, }, // Norfolk Time Australia UTC + 11:30 hours
{ "NOVST", 0, 0, }, // Novosibirsk Summer Time Asia UTC + 7 hours
{ "NOVT", 0, 0, }, // Novosibirsk Time Asia UTC + 6 hours
{ "NPT", 0, 0, }, // Nepal Time Asia UTC + 5:45 hours
{ "NST", 0, 0, }, // Newfoundland Std Time North America UTC - 3:30 hours
{ "NUT", 0, 0, }, // Niue Time Pacific UTC - 11 hours
{ "NZDT", 0, 0, }, // New Zealand Daylight Time Antarctica UTC + 13 hours
{ "NZDT", 0, 0, }, // New Zealand Daylight Time Pacific UTC + 13 hours
{ "NZST", 0, 0, }, // New Zealand Std Time Antarctica UTC + 12 hours
{ "NZST", 0, 0, }, // New Zealand Std Time Pacific UTC + 12 hours
{ "OMSST", 0, 0, }, // Omsk Summer Time Asia UTC + 7 hours
{ "OMST", 0, 0, }, // Omsk Std Time Asia UTC + 6 hours
{ "PDT", 0, 0, }, // Pacific Daylight Time North America UTC - 7 hours
{ "PET", 0, 0, }, // Peru Time South America UTC - 5 hours
{ "PETST", 0, 0, }, // Kamchatka Summer Time Asia UTC + 12 hours
{ "PETT", 0, 0, }, // Kamchatka Time Asia UTC + 12 hours
{ "PGT", 0, 0, }, // Papua New Guinea Time Pacific UTC + 10 hours
{ "PHOT", 0, 0, }, // Phoenix Island Time Pacific UTC + 13 hours
{ "PHT", 0, 0, }, // Philippine Time Asia UTC + 8 hours
{ "PKT", 0, 0, }, // Pakistan Std Time Asia UTC + 5 hours
{ "PMDT", 0, 0, }, // Pierre & Miquelon Daylight Time North America UTC - 2 hours
{ "PMST", 0, 0, }, // Pierre & Miquelon Std Time North America UTC - 3 hours
{ "PONT", 0, 0, }, // Pohnpei Std Time Pacific UTC + 11 hours
{ "PST", 0, 0, }, // Pacific Std Time North America UTC - 8 hours
{ "PST", 0, 0, }, // Pitcairn Std Time Pacific UTC - 8 hours
{ "PT", 0, 0, }, // Tiempo del Pac North America UTC - 8 hours
{ "PWT", 0, 0, }, // Palau Time Pacific UTC + 9 hours
{ "PYST", 0, 0, }, // Paraguay Summer Time South America UTC - 3 hours
{ "PYT", 0, 0, }, // Paraguay Time South America UTC - 4 hours
{ "RET", 0, 0, }, // Reunion Time Africa UTC + 4 hours
{ "SAMT", 0, 0, }, // Samara Time Europe UTC + 4 hours
{ "SAST", 0, 0, }, // South Africa Std Time Africa UTC + 2 hours
{ "SBT", 0, 0, }, // Solomon IslandsTime Pacific UTC + 11 hours
{ "SCT", 0, 0, }, // Seychelles Time Africa UTC + 4 hours
{ "SGT", 0, 0, }, // Singapore Time Asia UTC + 8 hours
{ "SRT", 0, 0, }, // Suriname Time South America UTC - 3 hours
{ "SST", 0, 0, }, // Samoa Std Time Pacific UTC - 11 hours
{ "TAHT", 0, 0, }, // Tahiti Time Pacific UTC - 10 hours
{ "TFT", 0, 0, }, // French Southern & Antarctic Indian Ocean UTC + 5 hours
{ "TJT", 0, 0, }, // Tajikistan Time Asia UTC + 5 hours
{ "TKT", 0, 0, }, // Tokelau Time Pacific UTC - 10 hours
{ "TLT", 0, 0, }, // East Timor Time Asia UTC + 9 hours
{ "TMT", 0, 0, }, // Turkmenistan Time Asia UTC + 5 hours
{ "TVT", 0, 0, }, // Tuvalu Time Pacific UTC + 12 hours
{ "ULAT", 0, 0, }, // Ulaanbaatar Time Asia UTC + 8 hours
{ "UYST", 0, 0, }, // Uruguay Summer Time South America UTC - 2 hours
{ "UYT", 0, 0, }, // Uruguay Time South America UTC - 3 hours
{ "UZT", 0, 0, }, // Uzbekistan Time Asia UTC + 5 hours
{ "VET", 0, 0, }, // Venezuelan Std Time South America UTC - 4:30 hours
{ "VLAST", 0, 0, }, // Vladivostok Summer Time Asia UTC + 11 hours
{ "VLAT", 0, 0, }, // Vladivostok Time Asia UTC + 10 hours
{ "VUT", 0, 0, }, // Vanuatu Time Pacific UTC + 11 hours
{ "WAST", 0, 0, }, // West Africa Summer Time Africa UTC + 2 hours
{ "WAT", 0, 0, }, // West Africa Time Africa UTC + 1 hour
{ "WDT", 0, 0, }, // Western Daylight Time Australia UTC + 9 hours
{ "WEST", 0, 0, }, // Western European Summer Time Africa UTC + 1 hour
{ "WEST", 0, 0, }, // Western European Summer Time Europe UTC + 1 hour
{ "WET", 0, 0, }, // Western European Time Africa UTC
{ "WET", 0, 0, }, // Western European Time Europe UTC
{ "WFT", 0, 0, }, // Wallis and Futuna Time Pacific UTC + 12 hours
{ "WGST", 0, 0, }, // Western Greenland Summer Time North America UTC - 2 hours
{ "WGT", 0, 0, }, // West Greenland Time North America UTC - 3 hours
{ "WIB", 0, 0, }, // Western Indonesian Time Asia UTC + 7 hours
{ "WIT", 0, 0, }, // Eastern Indonesian Time Asia UTC + 9 hours
{ "WITA", 0, 0, }, // Central Indonesian Time Asia UTC + 8 hours
{ "WST", 0, 0, }, // Western Sahara Summer Time Africa UTC + 1 hour
{ "WST", 0, 0, }, // Western Std Time Australia UTC + 8 hours
{ "WST", 0, 0, }, // West Samoa Time Pacific UTC - 11 hours
{ "WT", 0, 0, }, // Western Sahara Std Time Africa UTC
{ "YAKST", 0, 0, }, // Yakutsk Summer Time Asia UTC + 10 hours
{ "YAKT", 0, 0, }, // Yakutsk Time Asia UTC + 9 hours
{ "YAPT", 0, 0, }, // Yap Time Pacific UTC + 10 hours
{ "YEKST", 0, 0, }, // Yekaterinburg Summer Time Asia UTC + 6 hours
{ "YEKT", 0, 0, }, // Yekaterinburg Time Asia UTC + 5 hours
{ "", 0, 0, } // Null timezone
} ;
/*
** Functions applicable to all date classes
*/
static uint32_t _isdow (const char* cpStr)
{
// Determine if current string amounts to a day-name
//
// Arguments: 1) cpStr The string to be tested for a valid day-name
//
// Returns: 0+ If the supplied cstr is a dayname. 0xff if not.
int32_t nIndex ; // Day names iterator
for (nIndex = 0 ; nIndex < 7 ; nIndex++)
{
if (!CstrCompareI(cpStr, hz_daynames_abrv[nIndex]))
return nIndex ;
if (!CstrCompareI(cpStr, hz_daynames_full[nIndex]))
return nIndex ;
}
return NULL_DOW ;
}
static uint32_t _ismonth (const char* cpStr)
{
// Determine if current string amounts to a month-name
//
// Arguments: 1) cpStr The string to be tested for a valid month-name
//
// Returns: >0 If the supplied cstr is a month name
// 0 Otherwise
int32_t nIndex ; // Month names iterator
for (nIndex = 0 ; nIndex < 12 ; nIndex++)
{
if (!CstrCompareI(cpStr, hz_monthnames_abrv[nIndex]))
return nIndex + 1 ;
if (!CstrCompareI(cpStr, hz_monthnames_full[nIndex]))
return nIndex + 1 ;
}
return 0 ;
}
// FnGrp: IsTime
// Category: Text Processing
//
// Determines if the supplied string value constitues a time and if so, set the supplied hour, minute and seconds references
//
// Arguments: 1) h Hour reference
// 2) m Minute reference
// 3) s Seconds reference
// 4) str String value
//
// Returns: >0 The number of chars used in forming the time if the supplied string amounts to one.
// 0 otherwise.
uint32_t IsTime (uint32_t& h, uint32_t& m, uint32_t& s, const char* cpStr)
{
// Argument: 4) cpStr String value
const char* i = cpStr ; // Input string iterator
if (!i || i[0] == 0)
return 0 ;
if (IsDigit(i[0]) && IsDigit(i[1]) && IsDigit(i[2]) && IsDigit(i[3]) && IsDigit(i[4]) && IsDigit(i[5]) && i[6] <= CHAR_SPACE)
{
h = (10 * (i[0] - '0')) + (i[1] - '0') ;
m = (10 * (i[2] - '0')) + (i[3] - '0') ;
s = (10 * (i[4] - '0')) + (i[5] - '0') ;
return (h < 24 && m < 60 && s < 60) ? 6 : 0 ;
}
if (IsDigit(i[0]) && IsDigit(i[1]) && i[2] == CHAR_COLON && IsDigit(i[3]) && IsDigit(i[4]) && i[5] == CHAR_COLON && IsDigit(i[6]) && IsDigit(i[7]) && i[8] <= CHAR_SPACE)
{
h = (10 * (i[0] - '0')) + (i[1] - '0') ;
m = (10 * (i[3] - '0')) + (i[4] - '0') ;
s = (10 * (i[6] - '0')) + (i[7] - '0') ;
return (h < 24 && m < 60 && s < 60) ? 8 : 0 ;
}
return 0 ;
}
uint32_t IsTime (uint32_t& Y, uint32_t& M, uint32_t& D, hzString& S)
{
// Argument: 4) S String value
return IsTime(Y, M, D, *S) ;
}
uint32_t IsTime (uint32_t& h, uint32_t& m, uint32_t& s, hzChain::Iter& ci)
{
// Argument: 4) ci String value
hzChain::Iter xi ; // Iterator for input chain
uint32_t nCount ; // Length of time entity
char buf [12] ; // Test buffer
if (ci.eof()) return 0 ;
if (!IsDigit(*ci)) return 0 ;
xi = ci ;
for (nCount = 0 ; !xi.eof() && (IsDigit(*xi) || *xi == CHAR_COLON) && nCount < 8 ; nCount++, xi++)
buf[nCount] = *xi ;
buf[nCount] = 0 ;
return IsTime(h, m, s, buf) ? 8 : 0 ;
}
// FnGrp: IsDate
// Category: Text Processing
//
// Determine if the supplied string amounts to a date.
//
// Arguments: 1) Y Year reference
// 2) M Month reference
// 3) D Day reference
// 4) cpStr The test charachter string
//
// Returns: >0 The number of chars used in forming the date if the supplied string does amount to one.
// 0 If the supplied string does not amount to to a valid date.
uint32_t IsDate (uint32_t& Y, uint32_t& M, uint32_t& D, const char* cpStr)
{
const char* i = cpStr ; // String iterator
uint32_t nDigit = 0 ; // Number of digits encountered
uint32_t nSlash = 0 ; // Number of slashes encountered
uint32_t nAlpha = 0 ; // Number of alphas encountered
uint32_t nSpace = 0 ; // Number of spaces encountered
uint32_t nComma = 0 ; // Number of commas encountered
uint32_t dow = NULL_DOW ; // Day of week
uint32_t len = 0 ; // Test string lenght
Y = M = D = 0 ;
if (!i || i[0] == 0)
return 0 ;
// Check standard formats first
if (IsDigit(i[0]) && IsDigit(i[1]))
{
if (IsDigit(i[2]) && IsDigit(i[3]))
{
if (i[4] == CHAR_FWSLASH && IsDigit(i[5]) && IsDigit(i[6]) && i[7] == CHAR_FWSLASH && IsDigit(i[8]) && IsDigit(i[9]))
{
Y = ((i[0]-'0')*1000) + ((i[1]-'0')*100) + ((i[2]-'0')*10) + (i[3]-'0') ;
M = ((i[5]-'0')*10) + (i[6]-'0') ;
D = ((i[8]-'0')*10) + (i[9]-'0') ;
return (Y > 9999 || !M || M > 12 || !D || D > monlen(Y, M)) ? 0 : 10 ;
}
if (IsDigit(i[4]) && IsDigit(i[5]) && IsDigit(i[6]) && IsDigit(i[7]))
{
Y = ((i[0]-'0')*1000) + ((i[1]-'0')*100) + ((i[2]-'0')*10) + (i[3]-'0') ;
M = ((i[4]-'0')*10) + (i[5]-'0') ;
D = ((i[6]-'0')*10) + (i[7]-'0') ;
return (Y > 9999 || !M || M > 12 || !D || D > monlen(Y, M)) ? 0 : 8 ;
}
}
}
// Check more elaborate formats
for (i = cpStr ; *i ; len++, i++)
{
if (IsDigit(*i)) nDigit++ ;
else if (*i == CHAR_FWSLASH) nSlash++ ;
else if (IsAlpha(*i)) nAlpha++ ;
else if (*i <= ' ') nSpace++ ;
else if (*i <= ',') nComma++ ;
else
return 0 ;
}
if (nDigit > 4 && nAlpha > 2 && nSpace > 1)
{
// Could have a date
for (i = cpStr ; *i ; len++, i++)
{
if (IsAlpha(*i))
{
if (dow == NULL_DOW)
dow = _isdow(i) ;
if (M <= 0)
M = _ismonth(i) ;
for (; IsAlpha(*i) ; i++) ;
}
if (IsDigit(*i))
{
if (!D)
for (; IsDigit(*i) ; i++) { D *= 10 ; D += (*i - '0') ; }
if (!Y)
for (; IsDigit(*i) ; i++) { Y *= 10 ; Y += (*i - '0') ; }
}
if (Y && M > 0 && D > 0)
break ;
}
}
else
{
/*
** Check numeric format
*/
nDigit = 0 ;
nSlash = 0 ;
for (i = cpStr ; *i ; len++, i++)
{
if (*i == CHAR_FWSLASH)
nSlash++ ;
else if (IsDigit(*i))
nDigit++ ;
else
break ;
}
if (*i > CHAR_SPACE && *i != CHAR_MINUS)
return 0 ;
i = cpStr ;
if (nSlash == 0)
{
if (nDigit == 8)
{
Y = ((i[0]-'0')*1000) + ((i[1]-'0')*100) + ((i[2]-'0')*10) + (i[3]-'0') ;
M = ((i[4]-'0')*10) + (i[5]-'0') ;
D = ((i[6]-'0')*10) + (i[7]-'0') ;
}
}
if (nSlash == 2)
{
for (i = cpStr ; IsDigit(*i) ; len++, i++) { D *= 10 ; D += (*i - '0') ; }
for (i++ ; IsDigit(*i) ; len++, i++) { M *= 10 ; M += (*i - '0') ; }
for (i++ ; IsDigit(*i) ; len++, i++) { Y *= 10 ; Y += (*i - '0') ; }
}
}
return (Y > 9999 || !M || M > 12 || !D || D > monlen(Y, M)) ? 0 : len ;
}
uint32_t IsDate (uint32_t& Y, uint32_t& M, uint32_t& D, hzString& S) { return IsDate(Y, M, D, *S) ; }
// FnGrp: IsDateTime
// Category: Text Processing
//
// Determine if the supplied string amounts to a date and time (does not have to be null terminated)
//
// Arguments: 1) Y Year reference
// 2) M Month reference
// 3) D Day reference
// 4) h Hour reference
// 5) m Minute reference
// 6) s Seconds reference
// 7) str The test charachter string
//
// Returns: Number of chars used in forming the time if the supplied string is at the start of a time or 0 otherwise.
uint32_t IsDateTime (uint32_t& Y, uint32_t& M, uint32_t& D, uint32_t& h, uint32_t& m, uint32_t& s, const char* str)
{
const char* i = str ; // String iterator
uint32_t lenD = 0 ; // Length of date part
uint32_t lenT = 0 ; // Length of time part
if (i)
{
lenD = IsDate(Y, M, D, i) ;
if (lenD)
{
i += lenD ;
if (*i == CHAR_SPACE || *i == CHAR_MINUS)
i++ ;
lenT = IsTime(h, m, s, i) ;
if (lenT)
return lenD + lenT + 1 ;
}
}
return 0 ;
}
uint32_t IsDateTime (uint32_t& Y, uint32_t& M, uint32_t& D, uint32_t& h, uint32_t& m, uint32_t& s, hzString& S)
{
return IsDateTime(Y, M, D, h, m, s, *S) ;
}
hzEcode _daysfromdate (uint32_t& nDays, uint32_t Y, uint32_t M, uint32_t D)
{
// Convert calenda date into the number of days since of days since 00000101.
//
// Arguments: 1) nDays Number of days (set by this operation)
// 2) Y The given year
// 3) M The given month
// 4) D The given day
//
// Returns: E_RANGE If the supplied arguments Y, M and D do not amount to a valid date
// E_OK If the supplied arguments Y, M and D do form a valid date
uint32_t y = Y ; // Set to stated year and then decremented to 0
uint32_t m = M ; // Start at 1 and count up to month before M (to increment days see below)
uint32_t days = 0 ; // Days since start of calenda (0000/01/01 = 0)
bool leap = true ; // Leap year indicator
nDays = NULL_DATE ;
if (Y < 0 || Y > 9999) return E_RANGE ;
if (M < 1 || M > 12) return E_RANGE ;
if (D < 1 || D > monlen(Y, M)) return E_RANGE ;
// Consider 400 year blocks
for (; y >= 400 ; days += DAYS_IN_4C, y -= 400) ;
// Consider centuries (1st of which will have extra leap year)
if (y >= 100)
{ days += DAYS_IN_LC ; y -= 100 ; leap = false ; }
if (y >= 100)
{
for (; y >= 100 ; days += DAYS_IN_1C, y -= 100) ;
leap = false ;
}
// Consider 4 year blocks
if (!leap)
{
if (y >= 4)
{ days += 1460 ; y -= 4 ; leap = true ; }
}
if (y >= 4)
{
for (; y >= 4 ; days += DAYS_IN_4Y, y -= 4) ;
leap = true ;
}
// Consider trailing years
if (y && leap)
{ y-- ; days += 366 ; }
for (; y ; days += 365, y--) ;
// Consider month and day
for (m = 1 ; m < M ; m++)
days += monlen(Y, m) ;
days += (D - 1) ;
nDays = days ;
return E_OK ;
}
void _datefromdays (uint32_t& Y, uint32_t& M, uint32_t& D, uint32_t nDays)
{
// Convert the number of days since the start of the calenda, into Year, Month and Day. This is achieved by the following process
// 1) First divide the day number by the no of days in four centuries
//
// Arguments: 1) Y The derived year
// 2) M The derived month
// 3) D The derived day
// 4) nDays The number of days since the start of the calenda
//
// Returns: None
uint32_t d = nDays ; // Used to calculate date by incremental reduction of the day number
uint32_t len = 0 ; // Month length
bool leap ; // Is year derived so far a leap year?
Y = M = D = 0 ;
if (nDays <= 0)
return ;
leap = true ;
// Count 400 year periods
for (d = nDays ; d >= DAYS_IN_4C ; Y += 400, d -= DAYS_IN_4C) ;
// Count 100 year periods (1st will have 36525 days including 25 leap years but the rest will have only 36524)
if (d >= DAYS_IN_LC)
{ Y += 100 ; d -= DAYS_IN_LC ; leap = false ; }
if (d >= DAYS_IN_1C)
{
for (; d >= DAYS_IN_1C ; Y += 100, d -= DAYS_IN_1C) ;
leap = false ;
}
// Count 4 year periods. Note that if single centries were added the year so far will not be a leap year.
if (!leap)
{
if (d >= 1460)
{ Y += 4 ; d -= 1460 ; leap = true ; }
}
if (d >= DAYS_IN_4Y)
{
for (; d >= DAYS_IN_4Y ; Y += 4, d -= DAYS_IN_4Y) ;
leap = true ;
}
// Count 1 year periods. If year so far is a leap the first period is 366 days.
if (!leap)
for (; d >= 365 ; Y++, d -= 365) ;
else
{
if (d >= 366)
{
Y++ ;
d -= 366 ;
//leap = false ;
for (; d >= 365 ; Y++, d -= 365) ;
}
}
// Now sort month & days
M = D = 1 ;
for (;;)
{
len = monlen(Y, M) ;
if (d < len)
break ;
d -= len ;
M += 1 ;
}
D += d ;
}
uint64_t RealtimeMicro (void)
{
// Category: Timer/Scheduling
//
// Arguments: None
// Returns: Value of real time in microseconds
struct timeval tv ; // Recepticle for system time
uint64_t usecs ; // Real time in microseconds
gettimeofday(&tv, 0) ;
usecs = tv.tv_sec ;
usecs *= 1000000 ;
usecs += tv.tv_usec ;
return usecs ;
}
uint64_t RealtimeNano (void)
{
// Category: Timer/Scheduling
//
// Arguments: None
// Returns: Value of real time in nanoseconds
struct timespec tx ; // Recepticle for system time
uint64_t nano ; // Real time in nanoseconds
clock_gettime(CLOCK_MONOTONIC, &tx) ;
nano = tx.tv_sec ;
nano *= 1000000000 ; //L ;
nano += tx.tv_nsec ;
return nano ;
}
/*
** Section 2: Time Functions
*/
void hzTime::SysTime (void)
{
// Set this hzTime instance to the system clock
//
// Arguments: None
// Returns: None
time_t pt ; // Recepticle for system time
struct tm* t ; // Converted system time
pt = time(&pt) ;
t = localtime(&pt) ;
m_secs = (t->tm_hour * 3600) + (t->tm_min * 60) + t->tm_sec ;
}
void hzTime::SetTime (const hzTime& op)
{
// Set this hzTime instance to the supplied hzTime value
//
// Arguments: 1) op The hzTime operand
// Returns: None
m_secs = op.m_secs ;
}
hzEcode hzTime::SetTime (uint32_t h, uint32_t m, uint32_t s)
{
// Set this hzTime instance to time supplied as hours, minutes and seconds
//
// Arguments: 1) h The hour component
// 2) m The minute component
// 3) s The seconds component
//
// Returns: E_RANGE If the supplied hour, minute and seconds are not a valid time
// E_OK If the time has been set
if (h < 0 || h > 23) return E_RANGE ;
if (m < 0 || m > 59) return E_RANGE ;
if (s < 0 || s > 59) return E_RANGE ;
m_secs = (h * 3600) + (m * 60) + s ;
return E_OK ;
}
hzEcode hzTime::SetTime (uint32_t nSecs)
{
// Set this hzTime instance using the number of seconds since midnight.
//
// Arguments: 1) nSecs Number of seconds since midnight
//
// Returns: E_RANGE If the supplied number of seconds exceeds the number in a day
// E_OK If the time has been set
if (nSecs < 0 || nSecs > 86399)
return E_RANGE ;
m_secs = nSecs ;
return E_OK ;
}
hzEcode hzTime::SetTime (const char* cpTimeStr)
{
// Set this hzTime using a string representation of the time. Allowed formats are hh:mm:ss, hh:mm and hhmmss
//
// Arguments: 1) cpTimeStr Time char string
//
// Returns: E_ARGUMENT If the time cstr is not supplied or blank
// E_BADVALUE If the supplied cstr is not a valid time
// E_OK If the time is set
const char* i = cpTimeStr ; // Time string iterator
uint32_t h ; // Hours
uint32_t m ; // Minutes
uint32_t s ; // Seconds
if (!i || !i[0])
return E_ARGUMENT ;
if (!strcmp(cpTimeStr, "Not set"))
{
m_secs = NULL_TIME ;
return E_OK ;
}
if (i[2] == ':' && i[5] == ':')
{
h = ((i[0] - CHAR_0) * 10) ;
h += (i[1] - CHAR_0) ;
m = ((i[3] - CHAR_0) * 10) ;
m += (i[4] - CHAR_0) ;
s = ((i[6] - CHAR_0) * 10) ;
s += (i[7] - CHAR_0) ;
}
else if (i[2] == ':' && i[5] == 0)
{
h = ((i[0] - CHAR_0) * 10) ;
h += (i[1] - CHAR_0) ;
m = ((i[3] - CHAR_0) * 10) ;
m += (i[4] - CHAR_0) ;
s = 0 ;
}
else
{
h = ((i[0] - CHAR_0) * 10) ;
h += (i[1] - CHAR_0) ;
m = ((i[2] - CHAR_0) * 10) ;
m += (i[3] - CHAR_0) ;
s = ((i[4] - CHAR_0) * 10) ;
s += (i[5] - CHAR_0) ;
}
if (h < 0 || h > 23) return E_BADVALUE ;
if (m < 0 || m > 59) return E_BADVALUE ;
if (s < 0 || s > 59) return E_BADVALUE ;
m_secs = (h * 3600) + (m * 60) + s ;
return E_OK ;
}
#if 0
hzString hzTime::Str (hzDateFmt eFmt) const
{
// Create a hzString and populate it as a string of the supplied format. Return the hzString by value.
//
// Arguments: 1) eFmt Requested format of output string
//
// Returns: Instance of hzString by value being the time in text form.
hzString v ; // Output string (Time)
char buf [32] ; // Working buffer
if (m_secs == NULL_TIME)
strcpy(buf, "Not set") ;
else
{
if (eFmt & FMT_TIME_DFLT)
sprintf(buf, "%02d%02d%02d", Hour(), Min(), Sec()) ;
else if (eFmt & FMT_TIME_STD)
sprintf(buf, "%02d:%02d:%02d", Hour(), Min(), Sec()) ;
else
strcpy(buf, "Invalid Time Format") ;
}
v = buf ;
return v ;
}
#endif
const char* hzTime::Txt (hzDateFmt eFmt) const
{
// Write the time as per the supplied format.
//
// Arguments: 1) eFmt Requested format of output string
//
// Returns: Pointer to buffer populated with the time in text form.
//
// Note: The space required is allocated from the thread scratch pad and must not be deleted by the calling function.
_hzfunc("hzTime::Txt") ;
char* pBuf ; // Text recepticle
pBuf = _thisfn.ScratchPad(16) ;
if (m_secs == NULL_TIME)
strcpy(pBuf, "Not set") ;
else
{
if (eFmt & FMT_TIME_DFLT)
sprintf(pBuf, "%02d%02d%02d", Hour(), Min(), Sec()) ;
else if (eFmt & FMT_TIME_STD)
sprintf(pBuf, "%02d:%02d:%02d", Hour(), Min(), Sec()) ;
else
strcpy(pBuf, "Invalid Time") ;
}
return pBuf ;
}
std::ostream& operator<< (std::ostream& os, const hzTime& t)
{
// Category: Data Output
//
// Append an outgoing stream with the time formatted as hh:mm:ss
//
// Arguments: 1) os The output stream
// 2) t The hzTime (const)
char buf [12] ; // Working buffer
sprintf(buf, "%02d:%02d:%02d", (char) t.Hour(), (char) t.Min(), (char) t.Sec()) ;
os << buf ;
return os ;
}
/*
** Section 3: Short Date Functions
*/
void hzSDate::SysDate (void)
{
// Set a short date by the system clock
//
// Arguments: None
// Returns: None
time_t pt ; // Recepticle for system time
struct tm* t ; // Converted system time
pt = time(&pt) ;
t = localtime(&pt) ;
_daysfromdate(m_days, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday) ;
}
hzEcode hzSDate::SetDate (const hzSDate& op)
{
// Set the short date to the supplied short date operand
//
// Arguments: 1) op The operant short form date
//
// Returns: E_OK
m_days = op.m_days ;
return E_OK ;
}
hzEcode hzSDate::SetDate (uint32_t Y, uint32_t M, uint32_t D)
{
// Set the short date by three supplied integers of year, month and day
//
// Arguments: 1) Y Year
// 2) M Month
// 3) D Day
//
// Returns: E_RANGE If the supplied arguments Y, M and D do not amount to a valid date
// E_OK If the supplied arguments Y, M and D do form a valid date
return _daysfromdate(m_days, Y, M, D) ;
}
hzEcode hzSDate::SetDate (uint32_t nDays)
{
// Set the short date by the number of days since the start of the calenda (Jan 1st 0000)
//
// Arguments: 1) nDays Number of days
//
// Returns: E_RANGE If the supplied arguments Y, M and D do not amount to a valid date
// E_OK If the supplied arguments Y, M and D do form a valid date
if (nDays < 0 || nDays > DAYS_IN_10K)
return E_RANGE ;
m_days = nDays ;
return E_OK ;
}
hzEcode hzSDate::SetDate (const char* cpDateStr)
{
// Set the short date by a text string of an acceptable format
//
// Arguments: 1) cpDateStr Date as string
//
// Returns: E_RANGE If the supplied arguments Y, M and D do not amount to a valid date
// E_OK If the supplied arguments Y, M and D do form a valid date
uint32_t Y ; // Year part
uint32_t M ; // Month part
uint32_t D ; // Day part
hzEcode rc ; // Return code
if (!cpDateStr || !cpDateStr[0])
{ m_days = NULL_DATE ; return E_OK ; }
if (!IsDate(Y, M, D, cpDateStr))
{
m_days = NULL_DATE ;
return E_FORMAT ;
}
return _daysfromdate(m_days, Y, M, D) ;
}
void hzSDate::SetByEpoch (uint32_t nEpochTime)
{
// Set the short date using a epoch time
//
// Arguments: 1) nEpochTime Epoch time
// Returns: None
time_t pt ; // Recepticle for system time
struct tm* t ; // Converted system time
pt = nEpochTime ;
t = localtime(&pt) ;
_daysfromdate(m_days, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday) ;
}
uint32_t hzSDate::Year (void) const
{
// Provide the year value of this date
//
// Arguments: None
// Returns: Number being the year value of this date
uint32_t Y ; // Year part
uint32_t M ; // Month part
uint32_t D ; // Day part
_datefromdays(Y, M, D, m_days) ;
return Y ;
}
uint32_t hzSDate::Month (void) const
{
// Provide the month value of this date
//
// Arguments: None
// Returns: Number being the month value of this date
uint32_t Y ; // Year part
uint32_t M ; // Month part
uint32_t D ; // Day part
_datefromdays(Y, M, D, m_days) ;
return M ;
}
uint32_t hzSDate::Day (void) const
{
// Provide the day value of this date
//
// Arguments: None
// Returns: Number being the day value of this date
uint32_t Y ; // Year part
uint32_t M ; // Month part
uint32_t D ; // Day part
_datefromdays(Y, M, D, m_days) ;
return D ;
}
#if 0
hzString hzSDate::Str (hzDateFmt eFmt) const
{
// Produce text form of short form date in one of the following formats:-
//
// 1) As YYYYMMDD
// 2) As dayname, monthname day year (American)
// 3) As dayname, day monthname year (International)
//
// Arguments: 1) eFmt Output format
//
// Returns: Instance of hzString by value being text form of date.
hzString v ; // Result string
uint32_t Y ; // Year part
uint32_t M ; // Month part
uint32_t D ; // Day part
char buf[32] ; // Working buffer
if (m_days == NULL_DATE)
strcpy(buf, "Not set") ;
else
{
_datefromdays(Y, M, D, m_days) ;
switch (eFmt)
{
case FMT_DATE_DFLT: // yyyy/mm/dd
sprintf(buf, "%04d%02d%02d", Y, M, D) ;
break ;
case FMT_DATE_STD: // Dow, day month year
if (eFmt & FMT_DATE_USA)
sprintf(buf, "%s %s %d %04d", hz_daynames_abrv[Dow()], hz_monthnames_abrv[M - 1], D, Y) ;
else
sprintf(buf, "%s %d %s %04d", hz_daynames_abrv[Dow()], D, hz_monthnames_abrv[M - 1], Y) ;
break ;
default:
sprintf(buf, "Format unavailable") ;
break ;
}
}
v = buf ;
return v ;
}
#endif
const char* hzSDate::Txt (hzDateFmt eFmt) const
{
// Write the date as per the supplied format. The options are:-
//
// 1) As YYYYMMDD
// 2) As dayname, monthname day year (American)
// 3) As dayname, day monthname year (International)
//
// Arguments: 1) eFmt Requested format of output string
//
// Returns: Pointer to buffer populated with the date in text form.
//
// Note: The space required is allocated from the thread scratch pad and must not be deleted by the calling function.
_hzfunc("hzSDate::Txt") ;
char* pBuf ; // Text recepticle
uint32_t Y ; // Year part
uint32_t M ; // Month part
uint32_t D ; // Day part
pBuf = _thisfn.ScratchPad(32) ;
if (m_days == NULL_DATE)
strcpy(pBuf, "Not set") ;
else
{
_datefromdays(Y, M, D, m_days) ;
switch (eFmt)
{
case FMT_DATE_DFLT: // yyyy/mm/dd
sprintf(pBuf, "%04d%02d%02d", Y, M, D) ;
break ;
case FMT_DATE_STD: // Dow, day month year
if (eFmt & FMT_DATE_USA)
sprintf(pBuf, "%s %s %d %04d", hz_daynames_abrv[Dow()], hz_monthnames_abrv[M - 1], D, Y) ;
else
sprintf(pBuf, "%s %d %s %04d", hz_daynames_abrv[Dow()], D, hz_monthnames_abrv[M - 1], Y) ;
break ;
default:
sprintf(pBuf, "Format unavailable") ;
break ;
}
}
return pBuf ;
}
hzEcode hzSDate::AltDay (int32_t interval)
{
// Alter this short date by a number of days into future/past. The changed value will not be assumed if it amounts to an out of range date.
//
// Arguments: 1) interval Number of days into future/past
//
// Returns: E_RANGE If the supplied interval rendered this date invalid
// E_OK If the supplied interval was applied
if (interval < 0 && (m_days + interval) < 0)
return E_RANGE ;
if ((m_days + interval) > DAYS_IN_10K)
return E_RANGE ;
m_days += interval ;
return E_OK ;
}
hzEcode hzSDate::AltMonth (int32_t interval)
{
// Alter this short date by a number of months into future/past. The changed value will not be assumed if it amounts to an out of range
// date.
//
// Arguments: 1) interval Number of months into future/past
//
// Returns: E_RANGE If the supplied interval rendered this date invalid
// E_OK If the supplied interval was applied
uint32_t Y ; // Year part
uint32_t M ; // Month part
uint32_t D ; // Day part
int32_t months ; // Total months
if (!interval)
return E_OK ;
_datefromdays(Y, M, D, m_days) ;
months = (Y * 12) + M ;
months += interval ;
if (months < 0 || months >= 120000)
return E_RANGE ;
Y = months / 12 ;
M = months % 12 ;
return _daysfromdate(m_days, Y, M, D) ;
}
hzEcode hzSDate::AltYear (int32_t interval)
{
// Alter this short date by a number of years into future/past. The changed value will not be assumed if it amounts to an out of range
// date.
//
// Arguments: 1) x Number of years into future/past
//
// Returns: E_RANGE If the supplied interval rendered this date invalid
// E_OK If the supplied interval was applied
uint32_t Y ; // Year part
uint32_t M ; // Month part
uint32_t D ; // Day part
if (interval < 0 && (m_days + interval) < 0)
return E_RANGE ;
if ((m_days + interval) > DAYS_IN_10K)
return E_RANGE ;
_datefromdays(Y, M, D, m_days) ;
Y += interval ;
return _daysfromdate(m_days, Y, M, D) ;
}
const hzSDate& hzSDate::operator= (const hzXDate& op)
{
// Set a short date to the date component of a full date/time.
//
// Arguments: 1) op Operand date
//
// Returns: Reference to this hzSDate instance
m_days = op.NoDays() ;
return *this ;
}
bool hzSDate::operator== (const hzXDate& op) const
{
// Test if a short date is 'equal' to a long date (ignoring the time in the long date)
//
// Arguments: 1) op Operand date
//
// Returns: True If this short form date is equal to the date part of the supplied full date
// False Otherwise
return m_days == op.NoDays() ? true : false ;
}
std::ostream & operator<< (std::ostream &os, const hzSDate &d)
{
// Category: Data Output
//
// Stream out the textual manefestation of a short date to s stream
//
// Arguments: 1) os Output stream
// 2) d Short form date to output
//
// Returns: Reference to the supplied output stream
char buf[12] ; // Date formation buffer
sprintf(buf, "%04d/%02d/%02d", d.Year(), d.Month(), d.Day()) ;
os << buf ;
return os ;
}
/*
** Section 4: Full Date Functions
*/
void hzXDate::altsec (int32_t units)
{
// Advance or retard a hzXDate by a number of seconds. This will alter the day date if the alteration is sufficient to cross one or more
// midnight boundaries.
//
// Arguments: 1) nounits Number of units (seconds) into future/past
//
// Returns: None
int64_t S ; // No of full seconds
int64_t X ; // No of micro-seconds
m_hour += (units/3600) ;
units %= 3600 ;
S = m_usec ;
X = units ;
X *= 1000000 ;
S += X ;
if (S > 3600000000)
{ S -= 3600000000 ; m_hour++ ; }
m_usec = (uint32_t) S ;
}
void hzXDate::altmin (int32_t nounits)
{
// Advance or retard a hzXDate by a number of minutes. This will alter the day date if the alteration is sufficient to cross one or more
// midnight boundaries.
//
// Arguments: 1) nounits Number of units (minutes) into future/past
// Returns: None
altsec(60 * nounits) ;
}
void hzXDate::althour (int32_t nounits)
{
// Advance or retard a hzXDate by a number of hours. This will alter the day date if the alteration is sufficient to cross one or more
// midnight boundaries.
//
// Arguments: 1) nounits Number of units (hours) into future/past
// Returns: None
altsec(3600 * nounits) ;
}
void hzXDate::altday (int32_t nounits)
{
// Advance or retard a hzXDate by a number of days.
//
// Arguments: 1) nounits Number of units (days) into future/past
// Returns: None
m_hour += (nounits * 24) ;
}
void hzXDate::altyear (int32_t nounits)
{
// Advance or retard a hzXDate by a number of years.
//
// Arguments: 1) nounits Number of units (years) into future/past
// Returns: None
uint32_t days ; // Used by date - no of days conversion
uint32_t Y ; // Year part
uint32_t M ; // Month part
uint32_t D ; // Day part
days = m_hour/24 ;
_datefromdays(Y, M, D, days) ;
Y += nounits ;
_daysfromdate(days, Y, M, D) ;
days *= 24 ;
days += (m_hour%24) ;
m_hour = days ;
}
void hzXDate::altmon (int32_t nounits)
{
// Advance or retard a hzXDate by a number of months.
//
// Arguments: 1) nounits Number of units (months) into future/past
// Returns: None
uint32_t days ; // Used by date - no of days conversion
uint32_t Y ; // Year part
uint32_t M ; // Month part
uint32_t D ; // Day part
days = m_hour/24 ;
_datefromdays(Y, M, D, days) ;
if (nounits > 0)
{
for (; nounits > 0 ; nounits--)
{
if (nounits > 12)
{ Y++ ; nounits -= 11 ; continue ; }
M = M == 12 ? 1 : M + 1 ;
}
if (D > monlen(Y, M))
D = monlen(Y, M) ;
}
if (nounits < 0)
{
for (; nounits < 0 ; nounits++)
{
if (nounits < -12)
{ Y-- ; nounits += 11 ; continue ; }
M = M == 1 ? 12 : M - 1 ;
}
if (D > monlen(Y, M))
D = monlen(Y, M) ;
}
_daysfromdate(days, Y, M, D) ;
days *= 24 ;
days += (m_hour%24) ;
m_hour = days ;
}
// public functions
void hzXDate::SysDateTime (void)
{
// Set this hzXDate instance by the system clock
//
// Arguments: None
// Returns: None
struct timeval tv ; // Recepticle for system time
struct tm* t ; // Converted system time
time_t pt ; // Time recepticle
uint32_t days ; // Used by date - no of days conversion
gettimeofday(&tv, 0) ;
pt = tv.tv_sec ;
t = localtime(&pt) ;
_daysfromdate(days, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday) ;
m_hour = (days * 24) + t->tm_hour ;
m_usec = (t->tm_min * 60) + t->tm_sec ;
m_usec *= 1000000 ;
m_usec += tv.tv_usec ;
}
hzEcode hzXDate::SetDate (const char* cpDateStr)
{
// Set the date component of this hzXDate instance by a text string of an acceptable format
//
// Arguments: 1) cpDateStr Date as string
//
// Returns: E_FORMAT If the supplied cstr does not amount to a full date and time
// E_OK If this full date and time was set
uint32_t days ; // Used by date - no of days conversion
uint32_t Y ; // Year part
uint32_t M ; // Month part
uint32_t D ; // Day part
hzEcode rc ; // Return code
if (!cpDateStr || !cpDateStr[0])
{ m_hour = 0 ; m_usec = 0 ; return E_OK ; }
if (!strcmp(cpDateStr, "Not set"))
{ m_hour = 0 ; m_usec = 0 ; return E_OK ; }
if (!IsDate(Y, M, D, cpDateStr))
return E_FORMAT ;
rc = _daysfromdate(days, Y, M, D) ;
if (rc != E_OK)
return rc ;
//Y = m_hour % 24 ;
m_hour = (days * 24) ;
//m_hour += Y ;
return E_OK ;
}
hzEcode hzXDate::SetDateTime (const char* i)
{
// Set both the date and time components of this hzXDate instance by a text string of an acceptable format
//
// Arguments: 1) cpDateStr Time and date as string
//
// Returns: E_FORMAT If the supplied cstr does not amount to a full date and time
// E_OK If this full date and time was set
hzTimezone tz ; // Timezone
uint32_t dow = NULL_DOW ; // Doy of week
uint32_t len = 0 ; // Length of examined text
uint32_t Y = 0 ; // Year
uint32_t M = 0 ; // Month
uint32_t D = 0 ; // Day
uint32_t h = 0 ; // Hour
uint32_t m = 0 ; // Minute
uint32_t s = 0 ; // Second
uint32_t n ; // Counter
uint32_t hOset = 0 ; // Hours in timezone offset to GMT
uint32_t mOset = 0 ; // Minutes in timezone offset to GMT
char buf [4] ; // For reading numbers
if (!i || !i[0])
{ m_hour = 0 ; m_usec = 0 ; return E_OK ; }
tz.clear() ;
n = IsDateTime(Y, M, D, h, m, s, i) ;
if (!n)
{
Y = M = D = 0 ;
for (; *i ;)
{
if (*i < CHAR_SPACE)
break ;
if (*i == CHAR_SPACE || *i == CHAR_COMMA || *i == CHAR_PAROPEN || *i == CHAR_PARCLOSE)
{ len++ ; i++ ; continue ; }
if (IsDigit(*i))
{
// We are looking for a day of the month, a year or the start of a time sequence
n = IsTime(h, m, s, i) ;
if (n)
i += n ;
else
{
if (IsPosint(n, i))
{
if (n < 32 && D == 0) D = n ;
else if (n < 10000 && Y == 0) Y = n ;
else
return E_FORMAT ;
for (; IsDigit(*i) ; i++) ;
}
}
}
if (IsAlpha(*i))
{
// We are looking for a day name, a month name or a timezone code
if (dow == NULL_DOW)
{
for (n = 0 ; n < 7 ; n++)
if (!CstrCompareI(i, hz_daynames_full[n]))
{ dow = n ; break ; }
if (dow == NULL_DOW)
{
for (n = 0 ; n < 7 ; n++)
if (!CstrCompareI(i, hz_daynames_abrv[n]))
{ dow = n ; break ; }
}
if (dow != 8)
{ for (; IsAlpha(*i) ; i++) ; continue ; }
}
if (M == 0)
{
for (n = 0 ; n < 12 ; n++)
if (!CstrCompareI(i, hz_monthnames_full[n]))
{ M = n + 1 ; break ; }
if (M == 0)
{
for (n = 0 ; n < 12 ; n++)
if (!CstrCompareI(i, hz_monthnames_abrv[n]))
{ M = n + 1 ; break ; }
}
if (M >= 0)
{ for (; IsAlpha(*i) ; i++) ; continue ; }
}
if (!tz.code)
{
for (n = 0 ; _hzGlobal_Timezones[n].code ; n++)
{
if (!CstrCompareI(i, _hzGlobal_Timezones[n].code))
{ tz = _hzGlobal_Timezones[n] ; break ; }
}
if (tz.code)
{ for (; IsAlpha(*i) ; i++) ; continue ; }
}
return E_FORMAT ;
}
if (*i == CHAR_PLUS || *i == CHAR_MINUS)
{
// We are looking for a timezone offset to GMT (of the form +/-dddd)
i++ ; buf[0] = *i ;
i++ ; buf[1] = *i ;
i++ ; buf[2] = *i ;
i++ ; buf[3] = *i ;
if (IsDigit(buf[0]) && IsDigit(buf[1]) && IsDigit(buf[2]) && IsDigit(buf[3]))
{
hOset = ((buf[0] - '0') * 10) + (buf[1] - '0') ;
mOset = ((buf[2] - '0') * 10) + (buf[3] - '0') ;
if (hOset > 23 || mOset > 59)
return E_FORMAT ;
i++ ;
continue ;
}
return E_FORMAT ;
}
}
}
if (SetDate(Y, M, D) != E_OK) return E_FORMAT ;
if (SetTime(h, m, s) != E_OK) return E_FORMAT ;
return E_OK ;
}
hzEcode hzXDate::SetDate (uint32_t Y, uint32_t M, uint32_t D)
{
// Set the date component of this hzXDate instance by three numeric arguments of Y, M and D
//
// Arguments: 1) Y Year
// 2) M Month
// 3) D Day
//
// Returns: E_RANGE If the supplied year, month and day does not amount to a valid date
// E_OK If this date was set
uint32_t hour ; // Current hour
uint32_t days ; // No of days since 0000/01/01
hzEcode rc ; // Return code
if (m_hour == 0)
hour = 0 ;
else
hour = m_hour % 24 ;
rc = _daysfromdate(days, Y, M, D) ;
if (rc != E_OK)
{ m_hour = 0 ; m_usec = 0 ; return rc ; }
m_hour = (days * 24) + hour ;
return E_OK ;
}
hzEcode hzXDate::SetDate (uint32_t nDays, uint32_t nSecs)
{
// Set the date and time components of this hzXDate as two numeric arguments, the number of days since Jan 1 0000 and the number of seconds
// since midnight.
//
// Arguments: 1) nDays Total days since Jan 1 0000
// 2) nSecs Seconds since midnight
//
// Returns: E_RANGE If the supplied day count equals or exceeds the number of days in 10,000 years or the seconds exceed number in a day
// E_OK If the time is set
if (nDays < 0 || nDays > DAYS_IN_10K) return E_RANGE ;
if (nSecs < 0 || nSecs > SECS_IN_DAY) return E_RANGE ;
m_hour = (nDays * 24) + (nSecs/3600) ;
m_usec = (nSecs%3600) * 1000000 ;
return E_OK ;
}
hzEcode hzXDate::SetDate (uint64_t xdVal)
{
// Set the date and time components of this hzXDate by a single 64-bit value. This function is provided in order to retrieve dates from repositories in the
// HadronZoo Database Suite which stores full dates as 64 bit unsigned numbers.
//
// Argument: The date as a 64 bit value
//
// Returns: E_RANGE If the supplied day count equals or exceeds the number of days in 10,000 years or the seconds exceed number in a day
// E_OK If the time is set
m_usec = xdVal & 0xffffffff ;
xdVal >>= 32 ;
m_hour = xdVal & 0xffffffff ;
//m_hour = ((xdVal & 0xffffffff00000000) >> 32) ;
return E_OK ;
}
hzEcode hzXDate::SetDate (uint32_t nDays)
{
// Set the date component of this hzXDate instance by number of days since Jan 1 0000
//
// Arguments: 1) nDays Total days since Jan 1 0000
//
// Returns: E_RANGE If the supplied day count equals or exceeds the number of days in 10,000 years.
// E_OK If the time is set
if (nDays >= DAYS_IN_10K)
return E_RANGE ;
uint32_t hour ; // Current hour
hour = m_hour % 24 ;
m_hour = nDays * 24 ;
m_hour += hour ;
return E_OK ;
}
hzEcode hzXDate::SetTime (const char* i)
{
// Set the time component of this hzXDate using a string representation of the time. Allowed formats are hh:mm:ss, hh:mm and hhmmss
//
// Arguments: 1) nSecs Seconds since midnight
//
// Returns: E_RANGE If the supplied cstr does not amount to a legal time
// E_OK If the time is set
uint32_t h ; // Hours
uint32_t m ; // Minutes
uint32_t s ; // Seconds
if (!i)
return E_OK ;
if (i[2] == ':' && i[5] == ':')
{
h = ((i[0] - CHAR_0) * 10) ;
h += (i[1] - CHAR_0) ;
m = ((i[3] - CHAR_0) * 10) ;
m += (i[4] - CHAR_0) ;
s = ((i[6] - CHAR_0) * 10) ;
s += (i[7] - CHAR_0) ;
}
else
{
h = ((i[0] - CHAR_0) * 10) ;
h += (i[1] - CHAR_0) ;
m = ((i[2] - CHAR_0) * 10) ;
m += (i[3] - CHAR_0) ;
s = ((i[4] - CHAR_0) * 10) ;
s += (i[5] - CHAR_0) ;
}
if (h < 0 || h > 23) return E_RANGE ;
if (m < 0 || m > 59) return E_RANGE ;
if (s < 0 || s > 59) return E_RANGE ;
m_hour -= (m_hour % 24) ;
m_hour += h ;
m_usec = ((m * 60) + s) * 1000000 ;
return E_OK ;
}
hzEcode hzXDate::SetTime (uint32_t h, uint32_t m, uint32_t s)
{
// Set the time component of this hzXDate to time supplied as hours, minutes and seconds
//
// Arguments: 1) h Hour
// 2) m Minutes
// 3) s Seconds
//
// Returns: E_RANGE If the supplied hour, minute and seconds do not amount to a legal time
// E_OK If the time is set
if (h < 0 || h > 23) return E_RANGE ;
if (m < 0 || m > 59) return E_RANGE ;
if (s < 0 || s > 59) return E_RANGE ;
m_hour -= (m_hour % 24) ;
m_hour += h ;
m_usec = ((m * 60) + s) * 1000000 ;
return E_OK ;
}
hzEcode hzXDate::SetTime (uint32_t nSecs)
{
// Set the time component of this hzXDate to time supplied as number of seconds since midnight
//
// Arguments: 1) nEpochTime The date supplied as an epoch value
//
// Returns: E_RANGE If the supplied number of seconds exceed the number in a day
// E_OK If the time is set
if (nSecs > SECS_IN_DAY)
return E_RANGE ;
m_hour -= (m_hour % 24) ;
m_hour += (nSecs / 3600) ;
m_usec = (nSecs % 3600) * 1000000 ;
return E_OK ;
}
void hzXDate::SetByEpoch (uint32_t nEpochTime)
{
// Set the date and time components of this hzXDate using the epoch time (number of seconds since midnight , Jan 1 1970)
//
// Arguments: 1) nEpochTime The date supplied as an epoch value
// Returns: None
struct tm* t ; // Converted system time
time_t pt ; // Time recepticle
uint32_t days ; // Used by date - no of days conversion
pt = nEpochTime ;
t = localtime(&pt) ;
_daysfromdate(days, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday) ;
m_hour = (days * 24) + t->tm_hour ;
m_usec = ((t->tm_min * 60) + t->tm_sec) * 1000000 ;
}
void hzXDate::SetByEpoch (uint32_t nEpochTime, uint32_t usec)
{
// Set the date and time components of this hzXDate using the epoch time (number of seconds since midnight , Jan 1 1970). Also set the
// number of microseconds
//
// Arguments: 1) nEpochTime The date supplied as an epoch value
// 2) usec Number of microseconds
// Returns: None
struct tm* t ; // Converted system time
time_t pt ; // Time recepticle
uint32_t days ; // Used by date - no of days conversion
pt = nEpochTime ;
t = localtime(&pt) ;
_daysfromdate(days, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday) ;
m_hour = (days * 24) + t->tm_hour ;
m_usec = ((t->tm_min * 60) + t->tm_sec) * 1000000 ;
m_usec += usec ;
}
void hzXDate::altdate (hzInterval unit, int32_t nounits)
{
// Alter this hzXDate by a number of units which may be either days, months, years, hours, minutes or seconds
//
// Arguments: 1) unit Interval duration
// 2) nounits Number of interval durations
//
// Returns: None
switch (unit)
{
case DAY: altday(nounits) ; break ;
case MONTH: altmon(nounits) ; break ;
case YEAR: altyear(nounits) ; break ;
case HOUR: althour(nounits) ; break ;
case MINUTE: altmin(nounits) ; break ;
case SECOND: altsec(nounits) ; break ;
}
}
uint32_t hzXDate::Year (void) const
{
// Return the year part from this hzXDate
//
// Arguments: None
// Returns: Number being year part of this date
uint32_t Y ; // Year
uint32_t M ; // Month
uint32_t D ; // Day of month
_datefromdays(Y, M, D, m_hour/24) ;
return Y ;
}
uint32_t hzXDate::Month (void) const
{
// Return the month part from this hzXDate
//
// Arguments: None
// Returns: Number being month of year
uint32_t Y ; // Year
uint32_t M ; // Month
uint32_t D ; // Day of month
_datefromdays(Y, M, D, m_hour/24) ;
return M ;
}
uint32_t hzXDate::Day (void) const
{
// Return the day of month part from this hzXDate
//
// Arguments: None
// Returns: Number being day of month
uint32_t Y ; // Year
uint32_t M ; // Month
uint32_t D ; // Day of month
_datefromdays(Y, M, D, m_hour/24) ;
return D ;
}
uint64_t hzXDate::AsVal (void) const
{
// Return the day of month part from this hzXDate
//
// Arguments: None
// Returns: Number being day of month
uint64_t v ;
//v = (m_hour << 32) + m_usec ;
v = m_hour ;
v <<= 32 ;
v |= m_usec ;
return v ;
}
uint32_t hzXDate::DaysInYear (void) const
{
// Arguments: None
// Returns: Number of days since Jan 1
uint32_t d ; // Days since 0000/01/01
d = m_hour / 24 ;
for (; d >= DAYS_IN_4C ; d -= DAYS_IN_4C) ;
for (; d >= DAYS_IN_1C ; d -= DAYS_IN_1C) ;
for (; d >= DAYS_IN_4Y ; d -= DAYS_IN_4Y) ;
if (d >= DAYS_IN_LY)
{
d -= DAYS_IN_LY ;
for (; d >= DAYS_IN_1Y ; d -= DAYS_IN_1Y) ;
}
return d ;
}
hzSDate hzXDate::Date (void) const
{
// Extract the date part of the full dte and time as hzSDate (short form date) instance
//
// Arguments: None
// Returns: Instance of hzSDate as the date part of the full date
hzSDate d ; // hzTime instance
d.SetDate(NoDays()) ;
return d ;
}
hzTime hzXDate::Time (void) const
{
// Extract the time part of the full data and time as a hzTime instance
//
// Arguments: None
// Returns: Instance of hzTime as the time part of the full date
hzTime t ; // hzTime instance
t.SetTime(NoSecs()) ;
return t ;
}
uint32_t hzXDate::AsEpoch (void) const
{
// Return the time & date as an epoch
//
// Arguments: None
// Returns: Number of seconds passed since epoch start
uint32_t epoch ; // Target epoch
if (m_hour < HOURS_B4_EPOCH || m_hour > HOURS_EPOCH_END)
return 0 ;
epoch = m_hour - HOURS_B4_EPOCH ;
epoch *= SECS_IN_HOUR ;
epoch += (m_usec/1000000) ;
return epoch ;
}
const char* hzXDate::Txt (hzDateFmt eFmt) const
{
// Write the date and time as per the supplied format. The options are:-
//
// 1) As YYYYMMDD
// 2) As dayname, monthname day year (American)
// 3) As dayname, day monthname year (International)
//
// Arguments: 1) eFmt Requested format of output string
//
// Returns: Pointer to buffer populated with the date in text form.
//
// Note: The space required is allocated from the thread scratch pad and must not be deleted by the calling function.
_hzfunc("hzXDate::Txt") ;
char* pBuf ; // Text recepticle
bool bUS ; // True if American format required
bool bFN ; // True if full names are required
int32_t nSofar = 0 ; // Length so far.
if (!m_hour && !m_usec)
return 0 ;
pBuf = _thisfn.ScratchPad(32) ;
// if (m_hour & 0x80000000)
// { strcpy(pBuf, "Not set") ; return pBuf ; }
// Do we have the full blown internet format?
if (eFmt == FMT_DT_INET)
{
if (bUS)
sprintf(pBuf, "%s %s %d %04d %02d:%02d:%02d +0000 (GMT)", hz_daynames_abrv[Dow()], hz_monthnames_abrv[Month() - 1], Day(), Year(), Hour(), Min(), Sec()) ;
else
sprintf(pBuf, "%s %d %s %04d %02d:%02d:%02d +0000 (GMT)", hz_daynames_abrv[Dow()], Day(), hz_monthnames_abrv[Month() - 1], Year(), Hour(), Min(), Sec()) ;
return pBuf ;
}
// US or International
bUS = eFmt & FMT_DATE_USA ? true : false ;
bFN = eFmt & FMT_DATE_FULL ? true : false ;
// Do we have a dow? if so print this first
if (eFmt & FMT_DATE_DOW)
{
if (bFN)
strcpy(pBuf, hz_daynames_full[Dow()]) ;
else
strcpy(pBuf, hz_daynames_abrv[Dow()]) ;
nSofar = strlen(pBuf) ;
}
// Now print date
if (eFmt & FMT_DT_MASK_DATES)
{
if (nSofar)
{
pBuf[nSofar] = CHAR_SPACE ;
nSofar++ ;
}
switch (eFmt & FMT_DT_MASK_DATES)
{
case FMT_DATE_DFLT: // YYYYMMDD
nSofar += sprintf(pBuf + nSofar, "%04d%02d%02d", Year(), Month(), Day());
break ;
case FMT_DATE_STD: // YYYY/MM/DD
nSofar += sprintf(pBuf + nSofar, "%04d/%02d/%02d", Year(), Month(), Day());
break ;
case FMT_DATE_NORM: // DD/MM/YYYY (UK) or MM/DD/YYYY (US)
if (bUS)
nSofar += sprintf(pBuf + nSofar, "%02d/%02d/%04d", Month(), Day(), Year()) ;
else
nSofar += sprintf(pBuf + nSofar, "%02d/%02d/%04d", Day(), Month(), Year()) ;
break ;
case FMT_DATE_FULL: // Day_of_month+monthname+YYYY (UK) or monthname+day_of_month+YYYY (US)
if (bUS)
nSofar += sprintf(pBuf + nSofar, "%s %d %04d", hz_monthnames_abrv[Month() - 1], Day(), Year()) ;
else
nSofar += sprintf(pBuf + nSofar, "%d %s %04d", Day(), hz_monthnames_abrv[Month() - 1], Year()) ;
break ;
}
}
// Now print time
if (eFmt & FMT_DT_MASK_TIMES)
{
if (nSofar)
{
pBuf[nSofar] = CHAR_MINUS ;
nSofar++ ;
}
switch (eFmt & FMT_DT_MASK_TIMES)
{
case FMT_TIME_DFLT: // Time HHMMSS
nSofar += sprintf(pBuf + nSofar, "%02d%02d%02d", Hour(), Min(), Sec()) ;
break ;
case FMT_TIME_STD: // Time HH:MM:SS
nSofar += sprintf(pBuf + nSofar, "%02d:%02d:%02d", Hour(), Min(), Sec()) ;
break ;
case FMT_TIME_USEC: // Time HH:MM:SS.uSec
nSofar += sprintf(pBuf + nSofar, "%02d:%02d:%02d.%06d", Hour(), Min(), Sec(), uSec()) ;
break ;
}
}
// Now print timezone if applicable
if (eFmt & FMT_DT_MASK_TZONE)
{
if (nSofar)
{
pBuf[nSofar] = CHAR_SPACE ;
nSofar++ ;
}
switch (eFmt & FMT_DT_MASK_TIMES)
{
case FMT_TZ_CODE: strcpy(pBuf + nSofar, "GMT") ; break ;
case FMT_TZ_NUM: strcpy(pBuf + nSofar, "+0000") ; break ;
case FMT_TZ_BOTH: strcpy(pBuf + nSofar, "+0000 (GMT)") ; break ;
}
}
return pBuf ;
}
bool hzXDate::operator== (const hzXDate& op) const
{
// Return true if the operand hzXDate is the same as this
//
// Arguments: 1) op Operand date
return (m_hour == op.m_hour && m_usec == op.m_usec) ;
}
bool hzXDate::operator!= (const hzXDate& op) const
{
// Return true if the operand hzXDate is not the same as this
//
// Arguments: 1) op Operand date
return (m_hour != op.m_hour || m_usec != op.m_usec) ;
}
bool hzXDate::operator< (const hzXDate& op) const
{
// Return true if this hzXDate is earlier than the operand
//
// Arguments: 1) op Operand date
return (m_hour < op.m_hour || (m_hour == op.m_hour && m_usec < op.m_usec)) ;
}
bool hzXDate::operator<= (const hzXDate& op) const
{
// Return true if this hzXDate is earlier than or the same as the operand
//
// Arguments: 1) op Operand date
return ((m_hour == op.m_hour && m_usec == op.m_usec)
|| (m_hour < op.m_hour || (m_hour == op.m_hour && m_usec < op.m_usec))) ;
}
bool hzXDate::operator> (const hzXDate& op) const
{
// Return true if this hzXDate is later than the operand
//
// Arguments: 1) op Operand date
return (m_hour > op.m_hour || (m_hour == op.m_hour && m_usec > op.m_usec)) ;
}
bool hzXDate::operator>= (const hzXDate& op) const
{
// Return true if this hzXDate is later than or the same as the operand
//
// Arguments: 1) op Operand date
return ((m_hour == op.m_hour && m_usec == op.m_usec) || (m_hour > op.m_hour || (m_hour == op.m_hour && m_usec > op.m_usec))) ;
}
// static functions (may get rid of these)
int32_t hzXDate::datecmp (hzXDate& a, hzXDate& b)
{
// Compare two hzXDate instances, A and B. Return 1 if A>B, -1 if A<B and 0 if A and B are equal
//
// Arguments: 1) a First date
// 2) b Second date
//
// Returns: +1 If a > b
// -1 If a < b
// 0 If a and b are equal
if ( a.m_hour > b.m_hour)
return 1 ;
if (a.m_hour < b.m_hour)
return -1 ;
if (a.m_usec > b.m_usec)
return 1 ;
if (a.m_usec < b.m_usec)
return -1 ;
return 0 ;
//return a.m_hour > b.m_hour ? 1 : a.m_hour < b.m_hour ? -1 : a.m_usec > b.m_usec ? 1 : a.m_usec < b.m_usec ? -1 : 0 ;
}
std::ostream & operator<< (std::ostream &os, const hzXDate &d)
{
// Category: Data Output
//
// Stream out the textual manefestation of a hzXDate to s stream
//
// Arguments: 1) os Output stream
// 2) d Date/time to output
//
// Returns: Reference to the supplied output stream.
char buf[40] ; // Sprintf buffer
sprintf(buf, "%04d/%02d/%02d %02d:%02d:%02d.%06d",
(int16_t) d.Year(),
(char) d.Month(),
(char) d.Day(),
(char) d.Hour(),
(char) d.Min(),
(char) d.Sec(),
(int32_t) d.uSec()) ;
os << buf ;
return os ;
}
uint32_t IsFormalDate (hzXDate& date, hzChain::Iter& ci)
{
// Category: Text Processing
//
// Determine if the supplied chain iterator is at the begining of a legal date and/or time. If it is then the supplied hzXDate reference is populated. The
// lenth of the date/time sequence is returned so that the calling process can choose to advance the iterator by this length. The iterator is not advanced
// by this function
//
// Expects dates of the form "day_name, dd month_name yyyy hh:mm:ss Time-Zone"
//
// Arguments: 1) date The full date
// 2) ci Chain iterator to be tested
//
// Returns: Number being length of the date string if found
chIter zi ; // Internal chain iterator
hzTimezone tz ; // Timezone
uint32_t n ; // Counter
uint32_t dow = NULL_DOW ; // Day of week
uint32_t len = 0 ; // Length of examined text
uint32_t Y = 0 ; // Year
uint32_t M = 0 ; // Month
uint32_t D = 0 ; // Day
uint32_t h = 0 ; // Hour
uint32_t m = 0 ; // Minute
uint32_t s = 0 ; // Second
uint32_t hOset = 0 ; // Hours in timezone offset to GMT
uint32_t mOset = 0 ; // Minutes in timezone offset to GMT
char numBuf[4] ; // For reading numbers
zi = ci ;
tz.clear() ;
for (; !zi.eof() ;)
{
if (*zi < CHAR_SPACE)
break ;
if (*zi == CHAR_SPACE || *zi == CHAR_COMMA || *zi == CHAR_PAROPEN || *zi == CHAR_PARCLOSE)
{ len++ ; zi++ ; continue ; }
if (IsDigit(*zi))
{
// We are looking for a day of the month, a year or the start of a time sequence
n = IsTime(h, m, s, zi) ;
if (n)
zi += n ;
else
{
for (n = 0 ; IsDigit(*zi) ; zi++)
{ n *= 10 ; n += (*zi - '0') ; }
if (n < 32 && D == 0) D = n ;
else if (n < 10000 && Y == 0) Y = n ;
else
return 0 ;
}
}
if (IsAlpha(*zi))
{
// We are looking for a day name, a month name or a timezone code
if (dow == NULL_DOW)
{
for (n = 0 ; n < 7 ; n++)
if (zi == hz_daynames_full[n])
{ dow = n ; break ; }
if (dow == NULL_DOW)
{
for (n = 0 ; n < 7 ; n++)
if (zi == hz_daynames_abrv[n])
{ dow = n ; break ; }
}
if (dow != 8)
{ for (; IsAlpha(*zi) ; zi++) ; continue ; }
}
if (M == 0)
{
for (n = 0 ; n < 12 ; n++)
if (zi == hz_monthnames_full[n])
{ M = n + 1 ; break ; }
if (M == 0)
{
for (n = 0 ; n < 12 ; n++)
if (zi == hz_monthnames_abrv[n])
{ M = n + 1 ; break ; }
}
if (M >= 0)
{ for (; IsAlpha(*zi) ; zi++) ; continue ; }
}
if (!tz.code)
{
for (n = 0 ;; n++)
{
if (zi == _hzGlobal_Timezones[n].code)
{ tz = _hzGlobal_Timezones[n] ; break ; }
}
if (tz.code)
{ for (; IsAlpha(*zi) ; zi++) ; continue ; }
}
return 0 ;
}
if (*zi == CHAR_PLUS || *zi == CHAR_MINUS)
{
// We are looking for a timezone offset to GMT (of the form +/-dddd)
zi++ ; numBuf[0] = *zi ;
zi++ ; numBuf[1] = *zi ;
zi++ ; numBuf[2] = *zi ;
zi++ ; numBuf[3] = *zi ;
if (IsDigit(numBuf[0]) && IsDigit(numBuf[1]) && IsDigit(numBuf[2]) && IsDigit(numBuf[3]))
{
hOset = ((numBuf[0] - '0') * 10) + (numBuf[1] - '0') ;
mOset = ((numBuf[2] - '0') * 10) + (numBuf[3] - '0') ;
if (hOset > 23 || mOset > 59)
return 0 ;
zi++ ;
continue ;
}
return 0 ;
}
}
if (date.SetDate(Y, M, D) != E_OK) return 0 ;
if (date.SetTime(h, m, s) != E_OK) return 0 ;
ci = zi ;
return len ;
}
/*
** Date Formats
*/
const char* s_dt_types[] =
{
"FMT_DT_UNKNOWN", // Invalid or uninitialized type
// Dates contrl flags
"FMT_DATE_DOW", // Print the dow (this will appear first)
"FMT_DATE_USA", // Where applicable, put day before month
"FMT_DATE_ABBR", // Write words (eg dow and monthname) out in short form
"FMT_DATE_FULL", // Write words (eg dow and monthname) out in full
// Date only formats
"FMT_DATE_DFLT", // YYYYMMDD
"FMT_DATE_STD", // YYYY/MM/DD
"FMT_DATE_NORM", // DD/MM/YYYY (UK) or MM/DD/YYYY (US)
"FMT_DATE_FULL", // Day_of_month+monthname+YYYY (UK) or monthname+day_of_month+YYYY (US)
// Time only formats
"FMT_TIME_DFLT", // Time HHMMSS
"FMT_TIME_STD", // Time HH:MM:SS
"FMT_TIME_USEC", // Time HH:MM:SS.uSec
// Timezones (always last)
"FMT_TZ_CODE", // Timezone as code
"FMT_TZ_DIGITS", // Timezone as digits
"FMT_TZ_BOTH", // Timezone as digits plus (code in braces)
} ;
const hzString DateFmt2Str (hzDateFmt fmt)
{
// Category: Diagnostics
//
// Convert a HadroZoo Format to its text name for diagnostic purposes
//
// Arguments: 1) fmt Enumerated HadronZoo text format
//
// Returns: Instance of hzString by value being format/layout description
hzChain Z ; // Output chain
hzString S ; // Target hzString instance
// Dates contrl flags
if (fmt & FMT_DATE_DOW) { Z.AddByte(CHAR_PLUS) ; Z << s_dt_types[1] ; }
if (fmt & FMT_DATE_USA) { Z.AddByte(CHAR_PLUS) ; Z << s_dt_types[2] ; }
if (fmt & FMT_DATE_ABBR) { Z.AddByte(CHAR_PLUS) ; Z << s_dt_types[3] ; }
if (fmt & FMT_DATE_FULL) { Z.AddByte(CHAR_PLUS) ; Z << s_dt_types[4] ; }
// Date only formats
if (fmt & FMT_DATE_DFLT) { Z.AddByte(CHAR_PLUS) ; Z << s_dt_types[5] ; }
if (fmt & FMT_DATE_STD) { Z.AddByte(CHAR_PLUS) ; Z << s_dt_types[6] ; }
if (fmt & FMT_DATE_NORM) { Z.AddByte(CHAR_PLUS) ; Z << s_dt_types[7] ; }
if (fmt & FMT_DATE_FULL) { Z.AddByte(CHAR_PLUS) ; Z << s_dt_types[8] ; }
// Time only formats
if (fmt & FMT_TIME_DFLT) { Z.AddByte(CHAR_PLUS) ; Z << s_dt_types[9] ; }
if (fmt & FMT_TIME_STD) { Z.AddByte(CHAR_PLUS) ; Z << s_dt_types[10] ; }
if (fmt & FMT_TIME_USEC) { Z.AddByte(CHAR_PLUS) ; Z << s_dt_types[11] ; }
// Timezones (always last)
if (fmt & FMT_TZ_CODE) { Z.AddByte(CHAR_PLUS) ; Z << s_dt_types[12] ; }
if (fmt & FMT_TZ_NUM) { Z.AddByte(CHAR_PLUS) ; Z << s_dt_types[13] ; }
if (fmt & FMT_TZ_BOTH) { Z.AddByte(CHAR_PLUS) ; Z << s_dt_types[14] ; }
if (Z.Size())
S = Z ;
else
S = s_dt_types[FMT_DT_UNKNOWN] ;
return S ;
}
hzDateFmt Str2DateFmt (const hzString& S)
{
// Category: Config
//
// Convert the name of a HadronZoo Format to the enum
//
// Arguments: 1) S String presumed to indicate an enumerated HadronZoo text format
//
// Returns: Enum value being the format/layout matching supplied description
int32_t x = 0 ; // Format flagset
// Dates contrl flags
if (S.Contains("FMT_DATE_DOW")) x |= FMT_DATE_DOW ;
if (S.Contains("FMT_DATE_USA")) x |= FMT_DATE_USA ;
if (S.Contains("FMT_DATE_ABBR")) x |= FMT_DATE_ABBR ;
if (S.Contains("FMT_DATE_FULL")) x |= FMT_DATE_FULL ;
// Date only formats
if (S.Contains("FMT_DATE_DFLT")) x |= FMT_DATE_DFLT ;
if (S.Contains("FMT_DATE_STD")) x |= FMT_DATE_STD ;
if (S.Contains("FMT_DATE_NORM")) x |= FMT_DATE_NORM ;
if (S.Contains("FMT_DATE_FORM")) x |= FMT_DATE_FORM ;
// Time only formats
if (S.Contains("FMT_TIME_DFLT")) x |= FMT_TIME_DFLT ;
if (S.Contains("FMT_TIME_STD")) x |= FMT_TIME_STD ;
if (S.Contains("FMT_TIME_USEC")) x |= FMT_TIME_USEC ;
// Timezones (always last)
if (S.Contains("FMT_TZ_CODE")) x |= FMT_TZ_CODE ;
if (S.Contains("FMT_TZ_DIGITS")) x |= FMT_TZ_NUM ;
if (S.Contains("FMT_TZ_BOTH")) x |= FMT_TZ_BOTH ;
return (hzDateFmt) x ;
}