📄 wydate.cpp
字号:
/* Copyright is licensed under GNU LGPL. by I.J.Wang 2003*/#define WYLIB_SOURCE#include "wydate.h"#include "wystr.h"#include "wymutex.h"#include "wy_atdestroy.h"#include <cstdlib>#include <new> // new and bad_alloc// For mktime, localtime_r// #include <ctime>#include <time.h> // for externalsextern char *tzname[2];extern long timezone;extern int daylight;static const char ENVNAME_TZ[]="TZ";const char WyDate::class_name[]="WyDate";const char WyDate::TIMEZONE_UTC[]="UTC";// for speeding up copy/convert/compare of TIMEZONE_UTC//static const WyStr::size_type wy_TZLEN= sizeof(WyDate::TIMEZONE_UTC)-1;class Wy__static_check__ { public: Wy__static_check__ () { // Impl assertions if(WyTimeSpec()!=WyTimeSpec( Wy_Second(0), Wy_Nano(0))) { WY_TERMINATE(""); // assertion fail } if((std::numeric_limits<Wy_Second>::max()!= std::numeric_limits<std::time_t>::max())|| (std::numeric_limits<Wy_Second>::min()!= std::numeric_limits<std::time_t>::min())|| (std::numeric_limits<Wy_Nano>::max()!= std::numeric_limits<signed long int>::max())|| (std::numeric_limits<Wy_Nano>::min()!= std::numeric_limits<signed long int>::min())) { WY_TERMINATE(""); // assertion fail } if(wy_TZLEN>WyStr::min_capacity()) { WY_TERMINATE(""); // Impl::reset() may fail } };} static const wy_do_not_use_me__;// Class of environment variable// (for temporary use, rrid-like)//class TmpEnvVar { const char* _vname; bool _has_value; // _value available WyStr _value; // value of _vname indicated environment variable // Hidden TmpEnvVar(); TmpEnvVar(const TmpEnvVar&); const TmpEnvVar& operator =(const TmpEnvVar&); bool operator ==(const TmpEnvVar&); public: // Construct object to contain value of name (restore at destruction) // // Note: argument name pointed string should be const through // object life time // // has_value= true, if name defined in the environment variable // false otherwise // value= string value of name defined environment variable // undefined if has_value is false // // [Throw] WyStr::Reply // Wym_ENOMEM // TmpEnvVar(const char* name) WY__TSPC(WyStr::Reply); // Restore environment variable with value in *this and destruct *this // ~TmpEnvVar(); bool has_value(void) const WY__TSPC() { return _has_value; }; const WyStr& value(void) const WY__TSPC() { return _value; };};TmpEnvVar::TmpEnvVar(const char* name) WY__TSPC(WyStr::Reply) : _vname(name),_has_value(false),_value(){ const char* cptr=::getenv(name); if(cptr==NULL) { return; } _has_value=true; _value=WyCSeg(cptr);};TmpEnvVar::~TmpEnvVar(){ if(_has_value) { if(::setenv(_vname,_value.c_str(),1)!=0) { WY_THROW( WyRet() ); // recovering the change failed // (insufficient environment space) // Changed from WY_TERMINATE to WY_THROW } } else { ::unsetenv(_vname); }};// Mutex for accessing environment TZ//static WyMutex& wy_tzmutex(void) WY__TSPC(){ static WyMutex _tzmtx; return(_tzmtx);};// [Internal] Get the value of environment TZ//// [Ret] Ok // defined= true, value is set to the value of environment TZ// defined= false, TZ not in the environment, value intact// Wym_ENOMEM//static WyRet getenv_tz(bool& defined, WyStr& value)try { WyLock aa( wy_tzmutex() ); WyRet r; const char *vp( ::getenv(ENVNAME_TZ) ); if(vp==NULL) { defined=false; } else { if((r=value.reset(WyCSeg(vp)))!=Ok) { // ctor of WyCSeg wont throw WY_RETURN(r); } defined=true; } return(Ok);}catch(const WyLock::Reply& e) { WY_THROW( WyRet(e) );}catch(const WyRet& e) { WY_NDEBUG_MSG(e); WY_THROW( WyRet(e) );};class WyDate::Impl { public: // zone = TIMEZONE_UTC // year = 1970 // month= 1 [1-12] // mday = 1 [1-31] // hour = 0 [0-23] // min = 0 [0-59] // sec = 0 [0-61] // wday = 4 [0-6] // isdst= 0 // // [Throw] WyDate::Reply // Wym_ENOMEM // Impl() WY__TSPC(WyDate::Reply); // [Throw] WyDate::Reply // Wym_ENOMEM // Impl(const Impl&) WY__TSPC(WyDate::Reply); // [Syn] Construct object of time zone tzval, UTC time ucs // // [Throw] WyDate::Reply // Wym_EFAULT // Wym_EINVAL unrecognized tzval // Wym_ERANGE conversion failed // Wym_ENOMEM // Impl(const char* tzval,const WyTimeSpec& ttm); // [Syn] Construct object of time zone tzval, argument given date // // [Throw] WyDate::Reply // Wym_EFAULT // Wym_EINVAL unrecognized tzval // Wym_ERANGE conversion failed // Wym_ENOMEM // Impl(const char* tzval,int year,int month,int mday, int hour,int min, int sec); bool is_default(void) const WY__NOTHROW__; // [Syn] Reconstruct *this to WyDate() // void reset(void) WY__NOTHROW__; // [Syn] Reconstruct *this to WyDate(const Impl&) // // [Ret] Ok // Wym_ENOMEM // WyRet reset(const Impl& src) WY__TSPC(); // [Syn] Reconstruct *this to WyDate(const WyStr&,const WyTimeSpec&) // // [Ret] Ok // Wym_EFAULT // Wym_EINVAL unrecognized tzval // Wym_ERANGE conversion failed // Wym_ENOMEM // WyRet reset(const char* tzval, const WyTimeSpec& ucs); // [Syn] Reconstruct *this to WyDate(const WyStr&,int,int,int,int,int,int) // // [Ret] Ok // Wym_EFAULT // Wym_EINVAL unrecognized tzval // Wym_ERANGE conversion failed // Wym_ENOMEM // WyRet reset(const char* tzv,int year,int month,int mday, int hour,int min, int sec); void swap(Impl& another) WY__TSPC(); // [Ret] Time zone value (as for the environment string) // // Note: _SC_TZNAME_MAX is defined on this Linux machine (=6) // this may be problem with the design of this class (too short) // const WyStr& time_zone(void) const WY__NOTHROW__ { return _tzv; }; int year(void) const WY__NOTHROW__ { return _year; }; // [Syn] Get the month of a year of the object // // [Ret] Month of the object [1-12] // int month(void) const WY__NOTHROW__ { return _month; }; // [Syn] Get the day of the month // // [Ret] Day of the month [1-31] // int mday(void) const WY__NOTHROW__ { return _mday; }; // [Syn] Get the hour in a day // // [Ret] The hour [0-23] // int hour(void) const WY__NOTHROW__ { return _hour; }; // [Syn] Get the minute in an hour // // [Ret] Minute [0-59] // int min(void) const WY__NOTHROW__ { return _min; }; // [Syn] Get the second in a minute. // // [Ret] Second [0-61] // int sec(void) const WY__NOTHROW__ { return _sec; }; // [Syn] Get the day of the week // // [Ret] Day of the week [0-6] // int wday(void) const WY__NOTHROW__ { return _wday; }; // [Syn] Get the day of the year // // [Ret] Day of the year [0-365] // int yday(void) const WY__NOTHROW__ { return _yday; }; int isdst(void) const WY__NOTHROW__ { return _isdst; }; // [Syn] Get the UTC time of *this // // [Ret] UTC time of *this // WyTimeSpec utc_time(void) const WY__NOTHROW__ { return _wyt; }; // [Syn] Synchronize date to UTC second ucs // // [Ret] Ok // Wym_ERANGE conversion failed // Wym_ENOMEM // WyRet set_utc(const WyTimeSpec& ucs); // [Syn] Set date as the arguments indicate // // [Ret] Ok // Wym_EINVAL invalid argument // Wym_ERANGE conversion failed // Wym_ENOMEM // WyRet set_date(int year,int month,int mday, int hour,int min, int sec); // [Syn] Add linear time to *this // // [Ret] Ok // Wym_ERANGE result not representable // Wym_ENOMEM // WyRet add(const WyTimeSpec& tm); // [Syn] Reconstruct date as by Impl(const Impl&) // // [Throw] WyDate::Reply // Wym_ENOMEM // // [Ret] const Reference of this object // const Impl& operator =(const Impl& rhs) WY__TSPC(WyDate::Reply); // [Syn] Convert *this to text representation according to the format, and // reset res with the result // // Note: This member is the conversion for ::strftime. resultant timezone // string may not be what WyDate otherwise uses // (timezone issue is vague to me). // Locale may be involved. // // [Ret] Ok // Wym_EFBIG // Wym_ENOMEM // WyRet _strftime(WyStr& str, const char* format) const; // [Syn] Add time by rhs // // [Throw] WyDate::Reply // Wym_ERANGE result not representable // Wym_ENOMEM // // [Ret] const reference of this object // // [Refer] WyTimeSpec::operator+ , reset // const Impl& operator +=(const WyTimeSpec& rhs); // [Syn] Equivalence test // // [Ret] bool result of the equivalence // bool operator ==(const Impl& rhs) const WY__NOTHROW__ { return( (_wyt==rhs._wyt)&&(_tzv==rhs._tzv) ); }; bool operator !=(const Impl& rhs) const WY__NOTHROW__ { return( (_wyt!=rhs._wyt)||(_tzv!=rhs._tzv) ); }; private: WyStr _tzv; // time zone string int _isdst; // daylight saving time int _year; // [A.D. year] int _month; // [1,12] int _mday; // [1,31] int _hour; // [0,23] int _min; // [0,59] int _sec; // [0,61] // The following members are redundant, but useful. // int _wday; // [0-6] week day int _yday; // [0,365] Days since January 1st // Corresopnding UTC time (of the date) // WyTimeSpec _wyt;};WyDate::Impl::Impl() WY__TSPC(WyDate::Reply)try : _tzv( WyCSeg(TIMEZONE_UTC,wy_TZLEN) ),_isdst(0), _year(Default_Year),_month(Default_Month),_mday(Default_MDay), _hour(Default_Hour),_min(Default_Min),_sec(Default_Sec), _wday(Default_WDay),_yday(Default_YDay), _wyt(){}catch(const WyStr::Reply& e) { WY_THROW( WyDate::Reply(e) );};WyDate::Impl::Impl(const WyDate::Impl& src) WY__TSPC(WyDate::Reply)try : _tzv(src._tzv),_isdst(src._isdst), _year(src._year),_month(src._month),_mday(src._mday), _hour(src._hour),_min(src._min),_sec(src._sec), _wday(src._wday),_yday(src._yday), _wyt(src._wyt){}catch(const WyStr::Reply& e) { WY_THROW( WyDate::Reply(e) );};WyDate::Impl::Impl(const char* tzval,const WyTimeSpec& tm){ WyRet r=this->reset(tzval,tm); if(r!=Ok) { WY_THROW( WyDate::Reply(r) ); }};WyDate::Impl::Impl(const char* tzval,int year,int month,int mday, int hour,int min, int sec){ WyRet r=this->reset(tzval,year,month,mday,hour,min,sec); if(r!=Ok) { WY_THROW( WyDate::Reply(r) ); }};bool WyDate::Impl::is_default(void) const WY__NOTHROW__{ return(_wyt.is_default() &&(_tzv.cseg()==WyCSeg(TIMEZONE_UTC,wy_TZLEN)));};void WyDate::Impl::reset(void) WY__NOTHROW__{ if(_tzv.reset( WyCSeg(TIMEZONE_UTC,wy_TZLEN) )!=Ok) { WY_TERMINATE(""); // asserted not to fail (enough capacity) } _isdst=0; _wyt.reset(); _year=Default_Year; _month=Default_Month; _mday=Default_MDay; _hour=Default_Hour; _min=Default_Min; _sec=Default_Sec; _wday=Default_WDay; _yday=Default_YDay;};WyRet WyDate::Impl::reset(const WyDate::Impl& src) WY__TSPC(){ WyRet r=_tzv.reset(src._tzv); if(r!=Ok) { WY_RETURN(r); } _isdst=src._isdst; _wyt.reset(src._wyt); _year=src._year; _month=src._month; _mday=src._mday; _hour=src._hour; _min=src._min; _sec=src._sec; _wday=src._wday; _yday=src._yday; return(Ok);};WyRet WyDate::Impl::reset(const char* tzval,const WyTimeSpec& ucs)try {struct tm tm;std::time_t tt; if(tzval==0) { WY_RETURN(Wym_EFAULT); } // Warning: Not all unrecognized tzval can be reported if(tzval[0]==0) { WY_RETURN(Wym_EINVAL); // empty string not accepted for now } tt=ucs.second(); { WyLock aa(wy_tzmutex()); TmpEnvVar rr_tz(ENVNAME_TZ); if(::setenv(ENVNAME_TZ,tzval,1)!=0) { WY_RETURN(Wym_ENOMEM); // man. indicates no errno and only this reason } ::tzset(); // man. indicated this can be saved, call it however. if(::localtime_r(&tt,&tm)==NULL) { WY_RETURN(Wym_ERANGE); } _tzv=tzval; // WyCSeg(tzval) wont throw } _wyt.reset(ucs); _isdst=tm.tm_isdst; _year=tm.tm_year+1900; _month=tm.tm_mon+1; _mday=tm.tm_mday; _hour=tm.tm_hour; _min=tm.tm_min; _sec=tm.tm_sec; _wday=tm.tm_wday; _yday=tm.tm_yday; return(Ok);}catch(const WyStr::Reply& e) { return(e);}catch(const WyRet& e) { WY_NDEBUG_MSG(e); WY_THROW( WyRet(e) );};WyRet WyDate::Impl::reset(const char* tzval,int year,int month,int mday, int hour,int min, int sec)try { if((month<1)||(mday<1)||(hour<0)||(min<0)||(sec<0)) { WY_RETURN(Wym_EINVAL); } if(tzval==0) { WY_RETURN(Wym_EFAULT); } // Warning: Not all unrecognized tzval can be reported if(tzval[0]==0) { WY_RETURN(Wym_EINVAL); // empty string not accepted for now } struct std::tm tm; std::time_t tt; tm.tm_year=year-1900; tm.tm_mon=month-1; tm.tm_mday=mday; tm.tm_hour=hour; tm.tm_min=min; tm.tm_sec=sec; tm.tm_isdst=-1; if(tm.tm_year>=year) { WY_RETURN(Wym_ERANGE); // value conversion failed } { WyLock aa(wy_tzmutex()); TmpEnvVar rr_tz(ENVNAME_TZ); if(::setenv(ENVNAME_TZ,tzval,1)!=0) { WY_RETURN(Wym_ENOMEM); // man. indicates no errno and only this reason } ::tzset(); tt=std::mktime(&tm); if(tt==static_cast<std::time_t>(-1)) { WY_RETURN(Wym_ERANGE); } _tzv=tzval; // WyCSeg(tzval) wont throw } _wyt.reset(tt,Wy_Nano(0)); _isdst=tm.tm_isdst; _year=year; _month=month; _mday=mday; _hour=hour; _min=min; _sec=sec; _wday=tm.tm_wday; _yday=tm.tm_yday; return(Ok);}catch(const WyStr::Reply& e) { return(e);}catch(const WyRet& e) { WY_NDEBUG_MSG(e); WY_THROW( WyRet(e) );};void WyDate::Impl::swap(Impl& another) WY__TSPC(){ _tzv.swap(another._tzv); _wyt.swap(another._wyt); Wy__Base::vswap(_isdst,another._isdst); Wy__Base::vswap(_year,another._year); Wy__Base::vswap(_month,another._month); Wy__Base::vswap(_mday,another._mday); Wy__Base::vswap(_hour,another._hour); Wy__Base::vswap(_min,another._min); Wy__Base::vswap(_sec,another._sec); Wy__Base::vswap(_wday,another._wday); Wy__Base::vswap(_yday,another._yday);};WyRet WyDate::Impl::set_utc(const WyTimeSpec& rhs)try {struct tm tm;const std::time_t tt( rhs.second() ); { WyLock aa(wy_tzmutex()); TmpEnvVar rr_tz(ENVNAME_TZ); if(::setenv(ENVNAME_TZ,_tzv.c_str(),1)!=0) { WY_RETURN(Wym_ENOMEM); // man. indicates no errno and only this reason } ::tzset(); // man. indicated this can be saved, call it however. if(::localtime_r(&tt,&tm)==NULL) { WY_RETURN(Wym_ERANGE); } } _wyt.reset(rhs); _isdst=tm.tm_isdst; _year=tm.tm_year+1900; _month=tm.tm_mon+1; _mday=tm.tm_mday; _hour=tm.tm_hour; _min=tm.tm_min; _sec=tm.tm_sec; _wday=tm.tm_wday; _yday=tm.tm_yday; return(Ok);}catch(const WyStr::Reply& e) { return(e);}catch(const WyRet& e) { WY_NDEBUG_MSG(e); WY_THROW( WyRet(e) );};WyRet WyDate::Impl::set_date(int year,int month,int mday, int hour,int min, int sec)try { if((month<1)||(mday<1)||(hour<0)||(min<0)||(sec<0)) { WY_RETURN(Wym_EINVAL); } struct std::tm tm; std::time_t tt; tm.tm_year=year-1900; tm.tm_mon=month-1; tm.tm_mday=mday; tm.tm_hour=hour;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -