ALib C++ Library
Library Version: 2511 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
calendar.cpp
1//##################################################################################################
2// ALib C++ Library
3//
4// Copyright 2013-2025 A-Worx GmbH, Germany
5// Published under 'Boost Software License' (a free software license, see LICENSE.txt)
6//##################################################################################################
7#include "alib_precompile.hpp"
8#if !defined(ALIB_C20_MODULES) || ((ALIB_C20_MODULES != 0) && (ALIB_C20_MODULES != 1))
9# error "Symbol ALIB_C20_MODULES has to be given to the compiler as either 0 or 1"
10#endif
11#if ALIB_C20_MODULES
12 module;
13#endif
14//========================================= Global Fragment ========================================
16//============================================== Module ============================================
17#if ALIB_C20_MODULES
18 module ALib.Strings.Calendar;
19 import ALib.Lang;
20#else
21# include "ALib.Lang.H"
22# include "ALib.Strings.H"
24#endif
25//========================================== Implementation ========================================
26
27namespace alib::strings::util {
28
29#if !DOXYGEN
31#if ALIB_CAMP
32 ;
33#else
34DOX_MARKER( [CDT_MONTH_NAMES])
35={ A_CHAR("January" ), A_CHAR("February" ),
36 A_CHAR("March" ), A_CHAR("April" ),
37 A_CHAR("May" ), A_CHAR("June" ),
38 A_CHAR("July" ), A_CHAR("August" ),
39 A_CHAR("September"), A_CHAR("October" ),
40 A_CHAR("November" ), A_CHAR("December" ) };
41DOX_MARKER( [CDT_MONTH_NAMES])
42
43#endif
44
46#if ALIB_CAMP
47 ;
48#else
49DOX_MARKER( [CDT_DAY_NAMES])
50={ A_CHAR("Sunday" ), A_CHAR("Monday" ),
51 A_CHAR("Tuesday" ), A_CHAR("Wednesday"),
52 A_CHAR("Thursday" ), A_CHAR("Friday" ),
53 A_CHAR("Saturday" ) };
54DOX_MARKER( [CDT_DAY_NAMES])
55#endif
56
57#endif // !DOXYGEN
58
59
60//##################################################################################################
61// CalendarDateTime
62//##################################################################################################
64 Year=
65 Month=
66 Day=
67 Hour=
68 Minute=
69 Second=
70 Millisecond= 0;
71 DayOfWeek= -1;
72}
73
74void CalendarDateTime::Set( const DateTime& timeStamp, lang::Timezone timezone ) {
75 Clear();
76
77 #if defined( _WIN32 )
78 SYSTEMTIME st= timeStamp.ToSystemTime( timezone );
79
80 Year= st.wYear;
81 Day= st.wDay;
82 DayOfWeek= st.wDayOfWeek;
83 Month= st.wMonth;
84 Hour= st.wHour;
85 Minute= st.wMinute;
86 Second= st.wSecond;
87
88 #elif defined (__GLIBCXX__) || defined(_LIBCPP_VERSION) || defined(__APPLE__) || defined(__ANDROID_NDK__)
89 struct tm tm;
90 time_t tt= timeStamp.InEpochSeconds();
91 if ( timezone == lang::Timezone::UTC ) {
92 tm.tm_isdst= 0; // daylight saving off
93 gmtime_r( &tt, &tm );
94 } else {
95 tm.tm_isdst= -1; // daylight saving auto
96 localtime_r( &tt, &tm );
97 }
98
99 Year= tm.tm_year + 1900;
100 Day= tm.tm_mday;
101 DayOfWeek= tm.tm_wday;
102 Month= tm.tm_mon + 1;
103 Second= tm.tm_sec;
104 Hour= tm.tm_hour;
105 Minute= tm.tm_min;
106
107 #else
108 #pragma message ("Unknown Platform in file: " __FILE__ )
109 #endif
110}
111
114
115 #if defined( _WIN32 )
116
117 SYSTEMTIME st;
118 st.wYear= (WORD) Year;
119 st.wDay= (WORD) Day;
120 st.wDayOfWeek= (WORD) DayOfWeek;
121 st.wMonth= (WORD) Month;
122 st.wHour= (WORD) Hour;
123 st.wMinute= (WORD) Minute;
124 st.wSecond= (WORD) Second;
125 st.wMilliseconds= 0;
126
127 result= DateTime::FromSystemTime( st, timezone );
128
129 #elif defined (__GLIBCXX__) || defined(_LIBCPP_VERSION) || defined(__APPLE__) || defined(__ANDROID_NDK__)
130 struct tm tm;
131 tm.tm_year= Year - 1900;
132 tm.tm_mday= Day;
133 tm.tm_mon= Month -1;
134 tm.tm_hour= Hour;
135 tm.tm_min= Minute;
136 tm.tm_sec= Second;
137
138 time_t tt;
139 if ( timezone == lang::Timezone::UTC ) {
140 tm.tm_isdst= 0; // daylight saving off
141 tt= timegm( &tm );
142 } else {
143 tm.tm_isdst= -1; // daylight saving auto
144 tt= mktime( &tm );
145 }
146
147 result= DateTime::FromEpochSeconds( tt );
148
149
150 #else
151 #pragma message ("Unknown Platform in file: " __FILE__ )
152 #endif
153
154 return result;
155}
156
157
158
159//##################################################################################################
160// CalendarDuration
161//##################################################################################################
163 Days=
164 Hours=
165 Minutes=
166 Seconds=
169 Nanoseconds= 0;
170}
171#define NanosPerDay INT64_C( 86400000000000 ) ///< Constant denoting number of nanoseconds of a day.
172#define NanosPerHour INT64_C( 3600000000000 ) ///< Constant denoting number of nanoseconds of an hour.
173#define NanosPerMinute INT64_C( 60000000000 ) ///< Constant denoting number of nanoseconds of a minute.
174#define NanosPerSecond INT64_C( 1000000000 ) ///< Constant denoting number of nanoseconds of a second.
175#define NanosPerMillisecond INT64_C( 1000000 ) ///< Constant denoting number of nanoseconds of a millisecond.
176#define NanosPerMicrosecond INT64_C( 1000 ) ///< Constant denoting number of nanoseconds of a microsecond.
177
178
180 Clear();
181 decltype(nanos) fract;
182 if ( nanos > NanosPerDay ) { Days= int( fract= nanos / NanosPerDay ); nanos-= fract * NanosPerDay; }
183 if ( nanos > NanosPerHour ) { Hours= int( fract= nanos / NanosPerHour ); nanos-= fract * NanosPerHour; }
184 if ( nanos > NanosPerMinute ) { Minutes= int( fract= nanos / NanosPerMinute ); nanos-= fract * NanosPerMinute; }
185 if ( nanos > NanosPerSecond ) { Seconds= int( fract= nanos / NanosPerSecond ); nanos-= fract * NanosPerSecond; }
186 if ( nanos > NanosPerMillisecond ) { Milliseconds= int( fract= nanos / NanosPerMillisecond ); nanos-= fract * NanosPerMillisecond; }
187 if ( nanos > NanosPerMicrosecond ) { Microseconds= int( fract= nanos / NanosPerMicrosecond ); }
188}
189
191 return Days * NanosPerDay
192 + Hours * NanosPerHour
193 + Minutes * NanosPerMinute
194 + Seconds * NanosPerSecond
195 + Milliseconds * NanosPerMillisecond
196 + Microseconds * NanosPerMicrosecond
197 + Nanoseconds;
198}
199
200//##################################################################################################
201// CalendarDate
202//##################################################################################################
203void CalendarDate::Set( const DateTime& dateTime, lang::Timezone timezone ) {
204 CalendarDateTime cdt(dateTime, timezone);
205 stamp= uint32_t( cdt.Year ) << 12
206 | uint32_t( cdt.Month ) << 8
207 | uint32_t( cdt.Day ) << 3
208 | uint32_t( cdt.DayOfWeek ) ;
209}
210void CalendarDate::Set( int year, int month, int day, int dayOfWeek ) {
211 ALIB_ASSERT_ERROR( year >= 0 && year <= 1048575, "CAMP", "CalendarDate: Years must be between 0 and 1,048,575. Given: ", year )
212 ALIB_ASSERT_ERROR( month >= 1 && month <= 12 , "CAMP", "CalendarDate: Months must be between 1 and 12. Given: ", month )
213 ALIB_ASSERT_ERROR( day >= 1 && day <= 31 , "CAMP", "CalendarDate: Days must be between 1 and 31. Given: ", day )
214 ALIB_ASSERT_ERROR( dayOfWeek <= 6 , "CAMP", "CalendarDate: Day of week must be either negative or between 0 and 6. Given: ", dayOfWeek)
215
216 // get day of week, if not given
217 if( dayOfWeek< 0 ) {
218 dayOfWeek= CalendarDateTime( CalendarDateTime( year, month, day, 12, 0, 0 ).Get(),
220 }
221 #if ALIB_DEBUG
222 else {
223 CalendarDateTime cdt( year, month, day, 12, 0, 0 );
224 cdt= CalendarDateTime( cdt.Get( )); // get day of week
225 ALIB_ASSERT_ERROR( dayOfWeek == cdt.DayOfWeek, "CAMP",
226 "Given day of week {} does not correspond to given date. Should be: ",
227 dayOfWeek, cdt.DayOfWeek )
228 }
229 #endif
230 stamp= uint32_t( year ) << 12
231 | uint32_t( month ) << 8
232 | uint32_t( day ) << 3
233 | uint32_t( dayOfWeek ) ;
234}
235
236DateTime CalendarDate::Get( lang::Timezone timezone, int hour, int minute, int second ) const
237{ return CalendarDateTime( Year(), Month(), Day(), hour, minute, second).Get( timezone ); }
238
239CalendarDate CalendarDate::operator+( int daysToAdd ) const {
240 // use the system for it
241 return CalendarDate( CalendarDateTime( Year(), Month(), Day(), 12 ).Get()
242 + DateTime::Duration::FromAbsoluteDays( daysToAdd ),
244}
245
247 auto day = Day ();
248 auto month= Month();
249 auto year = Year ();
250
251 // can we do it manually?
252 if( ( month != 2 && day != 30 )
253 || ( month == 2 && day != 28 ) )
254 {
255 if( ( day != 31 )
256 && ( day != 29 || month != 2 ) )
257 {
258 day++;
259 } else {
260 day= 1;
261 if( ++month == 13 ) {
262 month= 1;
263 ++year;
264 } }
265 Set( year, month, day, (DayOfWeek() + 1) % 7 );
266 return *this;
267 }
268
269 // use the system for it
270 CalendarDateTime cdt( year, month, day, 12 );
271 return *this= CalendarDate( cdt.Get() + DateTime::Duration::FromAbsoluteDays(1), lang::Timezone::UTC );
272}
273
275 auto day = Day();
276
277 // can we do it manually?
278 if( day > 1 ) {
279 stamp= ( stamp & ~lang::LowerMask<8, uint32_t>() )
280 | ( uint32_t( day-1 ) << 3 )
281 | ( ( (stamp & 7) + 6 ) % 7 ) ; // +6 corresponds to -1 in modulo op
282 return *this;
283 }
284
285 // use the system for it
286 return *this= CalendarDate( Get() - DateTime::Duration::FromAbsoluteDays(1), lang::Timezone::UTC );
287}
288
289
290//##################################################################################################
291// CalendarDateTime::Format
292//##################################################################################################
294 if ( targetData == lang::CurrentData::Clear )
295 target.Reset();
296
297 // this ensures that target is not nulled, as all other appends are NC-versions
298 target._("");
300
301 while ( format.IsNotEmpty() ) {
302 // read n equal characters
303 int n= 1;
304 character c= format.ConsumeChar();
305 while ( format.ConsumeChar(c) )
306 ++n;
307
308 switch (c) {
309 case '\'': // single quotes
310 {
311 // one or more pairs of single quotes?
312 if ( n > 1 ) {
313 int pairs= n / 2;
314 target.InsertChars<NC>( '\'', pairs );
315 n-= (pairs * 2);
316 }
317
318 // one single quote?
319 if ( n == 1 ) {
320 // search end
321 integer end= format.IndexOf( '\'' );
322 if ( end < 1 ) {
323 ALIB_WARNING( "ALIB", "Format Error: Missing single Quote" )
324 target << "Format Error: Missing closing single quote character <'>" ;
325 return target;
326 }
327
328 target._<NC>( format, 0, end );
329 format.ConsumeChars<NC>( end + 1 );
330 }
331
332 } break;
333
334 case 's': // second
335 target.template _<NC>( alib::Dec( Second, n, nf ) );
336 break;
337
338 case 'm': //minute
339 target._<NC>( alib::Dec( Minute, n, nf ) );
340 break;
341
342 case 'K': // hour 0..11
343 target._<NC>( alib::Dec( Hour % 12, n, nf ) );
344 target._<NC>( Hour < 12 ? " am" : " pm" );
345 break;
346
347 case 'H': // hour 0..23
348 target._<NC>( alib::Dec( Hour, n, nf ) );
349 break;
350
351 case 'd': // day
352 if ( n <= 2 ) target._<NC>( alib::Dec( Day, n, nf) );
353 else if ( n == 3 ) target._<NC>( DAY_NAMES[DayOfWeek], 0, 3 );
354 else target._<NC>( DAY_NAMES[DayOfWeek] );
355 break;
356
357 case 'M': // month
358 if ( n <= 2 ) target._<NC>( alib::Dec( Month, n, nf ) );
359 else if ( n == 3 ) target._<NC>( MONTH_NAMES[Month-1], 0, 3 );
360 else target._<NC>( MONTH_NAMES[Month-1] );
361 break;
362
363 case 'y': // year
364 if ( n == 1 ) target._<NC>( alib::Dec(Year, 1, nf) );
365 else if ( n == 2 ) target._<NC>( alib::Dec(Year % 100, 2, nf) );
366 else target._<NC>( alib::Dec(Year, n, nf) );
367 break;
368
369 default: // otherwise: copy what was in
370 target.InsertChars<NC>( c, n );
371 break;
372 }
373
374 }
375
376 return target;
377}
378
379
380
381} // namespace [ alib::system]
TAString & InsertChars(TChar c, integer qty)
TAString & _(const TAppendable &src)
int Minute
The calendar minute (0..59).
Definition calendar.inl:62
ALIB_DLL void Set(const DateTime &timeStamp, lang::Timezone timezone=lang::Timezone::Local)
Definition calendar.cpp:74
int Second
The calendar second (0..59).
Definition calendar.inl:65
int Day
The calendar day (1..31).
Definition calendar.inl:56
ALIB_DLL AString & Format(Substring format, AString &target, lang::CurrentData targetData=lang::CurrentData::Keep) const
Definition calendar.cpp:293
int Hour
The calendar hour (0..23).
Definition calendar.inl:59
static ALIB_DLL String MONTH_NAMES[12]
Definition calendar.inl:39
int Year
The calendar year (e.g., 2022).
Definition calendar.inl:50
ALIB_DLL DateTime Get(lang::Timezone timezone=lang::Timezone::Local) const
Definition calendar.cpp:112
ALIB_DLL void Clear()
Sets all public values to 0.
Definition calendar.cpp:63
static ALIB_DLL String DAY_NAMES[7]
Definition calendar.inl:47
int Month
The calendar month (1..12).
Definition calendar.inl:53
int Millisecond
The calendar millisecond (0..999).
Definition calendar.inl:68
CalendarDate()=default
Default constructor leaving this object uninitialized (random value).
ALIB_DLL void Set(int year, int month, int day, int dayOfWeek=-1)
Definition calendar.cpp:210
ALIB_DLL CalendarDate operator++()
Definition calendar.cpp:246
uint32_t stamp
Encoded date value.
Definition calendar.inl:301
ALIB_DLL DateTime Get(lang::Timezone timezone=lang::Timezone::Local, int hour=12, int minute=0, int second=0) const
Definition calendar.cpp:236
ALIB_DLL CalendarDate operator+(int daysToAdd) const
Definition calendar.cpp:239
ALIB_DLL CalendarDate operator--()
Definition calendar.cpp:274
int Seconds
The number of seconds (not the total, hence 0-59) within the duration.
Definition calendar.inl:194
ALIB_DLL void FromNanoSeconds(int64_t nanos)
Definition calendar.cpp:179
int Hours
The number of hours (not the total, hence 0-23) within the duration.
Definition calendar.inl:188
int Nanoseconds
The number of nanoseconds (not the total, hence 0-999) within the duration.
Definition calendar.inl:203
int Minutes
The number of minutes (not the total, hence 0-59) within the duration.
Definition calendar.inl:191
int Milliseconds
The number of milliseconds (not the total, hence 0-999) within the duration.
Definition calendar.inl:197
ALIB_DLL void Clear()
Sets all public values to 0.
Definition calendar.cpp:162
int Microseconds
The number of microseconds (not the total, hence 0-999) within the duration.
Definition calendar.inl:200
int Days
The number of days within the duration.
Definition calendar.inl:185
time_t InEpochSeconds() const
Definition datetime.inl:54
static ALIB_DLL DateTime FromSystemTime(const SYSTEMTIME &systemTime, lang::Timezone timezone=lang::Timezone::Local)
ALIB_DLL SYSTEMTIME ToSystemTime(lang::Timezone timezone=lang::Timezone::Local) const
static DateTime FromEpochSeconds(time_t epochSeconds)
Definition datetime.inl:63
#define A_CHAR(STR)
#define ALIB_WARNING(domain,...)
Definition alib.inl:1063
#define ALIB_ASSERT_ERROR(cond, domain,...)
Definition alib.inl:1066
@ Clear
Chooses to clear existing data.
Timezone
Denotes whether a time value represents local time or UTC.
@ UTC
Denotes UTC (coordinated universal time).
strings::TDec< character > Dec
Type alias in namespace alib.
Definition format.inl:541
strings::TAString< character, lang::HeapAllocator > AString
Type alias in namespace alib.
time::DateTime DateTime
Type alias in namespace alib.
Definition datetime.inl:185
lang::integer integer
Type alias in namespace alib.
Definition integers.inl:149
strings::TNumberFormat< character > NumberFormat
Type alias in namespace alib.
strings::util::CalendarDateTime CalendarDateTime
Type alias in namespace alib.
Definition calendar.inl:512
strings::TString< character > String
Type alias in namespace alib.
Definition string.inl:2189
characters::character character
Type alias in namespace alib.
strings::TSubstring< character > Substring
Type alias in namespace alib.