@ -67,6 +67,48 @@ char* strptime(const char* s, const char* fmt, std::tm* tm) {
}
}
# endif
# endif
// Convert a cctz::weekday to a tm_wday value (0-6, Sunday = 0).
int ToTmWday ( weekday wd ) {
switch ( wd ) {
case weekday : : sunday :
return 0 ;
case weekday : : monday :
return 1 ;
case weekday : : tuesday :
return 2 ;
case weekday : : wednesday :
return 3 ;
case weekday : : thursday :
return 4 ;
case weekday : : friday :
return 5 ;
case weekday : : saturday :
return 6 ;
}
return 0 ; /*NOTREACHED*/
}
// Convert a tm_wday value (0-6, Sunday = 0) to a cctz::weekday.
weekday FromTmWday ( int tm_wday ) {
switch ( tm_wday ) {
case 0 :
return weekday : : sunday ;
case 1 :
return weekday : : monday ;
case 2 :
return weekday : : tuesday ;
case 3 :
return weekday : : wednesday ;
case 4 :
return weekday : : thursday ;
case 5 :
return weekday : : friday ;
case 6 :
return weekday : : saturday ;
}
return weekday : : sunday ; /*NOTREACHED*/
}
std : : tm ToTM ( const time_zone : : absolute_lookup & al ) {
std : : tm ToTM ( const time_zone : : absolute_lookup & al ) {
std : : tm tm { } ;
std : : tm tm { } ;
tm . tm_sec = al . cs . second ( ) ;
tm . tm_sec = al . cs . second ( ) ;
@ -84,34 +126,19 @@ std::tm ToTM(const time_zone::absolute_lookup& al) {
tm . tm_year = static_cast < int > ( al . cs . year ( ) - 1900 ) ;
tm . tm_year = static_cast < int > ( al . cs . year ( ) - 1900 ) ;
}
}
switch ( get_weekday ( al . cs ) ) {
tm . tm_wday = ToTmWday ( get_weekday ( al . cs ) ) ;
case weekday : : sunday :
tm . tm_wday = 0 ;
break ;
case weekday : : monday :
tm . tm_wday = 1 ;
break ;
case weekday : : tuesday :
tm . tm_wday = 2 ;
break ;
case weekday : : wednesday :
tm . tm_wday = 3 ;
break ;
case weekday : : thursday :
tm . tm_wday = 4 ;
break ;
case weekday : : friday :
tm . tm_wday = 5 ;
break ;
case weekday : : saturday :
tm . tm_wday = 6 ;
break ;
}
tm . tm_yday = get_yearday ( al . cs ) - 1 ;
tm . tm_yday = get_yearday ( al . cs ) - 1 ;
tm . tm_isdst = al . is_dst ? 1 : 0 ;
tm . tm_isdst = al . is_dst ? 1 : 0 ;
return tm ;
return tm ;
}
}
// Returns the week of the year [0:53] given a civil day and the day on
// which weeks are defined to start.
int ToWeek ( const civil_day & cd , weekday week_start ) {
const civil_day d ( cd . year ( ) % 400 , cd . month ( ) , cd . day ( ) ) ;
return static_cast < int > ( ( d - prev_weekday ( civil_year ( d ) , week_start ) ) / 7 ) ;
}
const char kDigits [ ] = " 0123456789 " ;
const char kDigits [ ] = " 0123456789 " ;
// Formats a 64-bit integer in the given field width. Note that it is up
// Formats a 64-bit integer in the given field width. Note that it is up
@ -355,7 +382,7 @@ std::string format(const std::string& format, const time_point<seconds>& tp,
if ( cur = = end | | ( cur - percent ) % 2 = = 0 ) continue ;
if ( cur = = end | | ( cur - percent ) % 2 = = 0 ) continue ;
// Simple specifiers that we handle ourselves.
// Simple specifiers that we handle ourselves.
if ( strchr ( " YmdeHMSzZs% " , * cur ) ) {
if ( strchr ( " YmdeUuWw HMSzZs% " , * cur ) ) {
if ( cur - 1 ! = pending ) {
if ( cur - 1 ! = pending ) {
FormatTM ( & result , std : : string ( pending , cur - 1 ) , tm ) ;
FormatTM ( & result , std : : string ( pending , cur - 1 ) , tm ) ;
}
}
@ -376,6 +403,22 @@ std::string format(const std::string& format, const time_point<seconds>& tp,
if ( * cur = = ' e ' & & * bp = = ' 0 ' ) * bp = ' ' ; // for Windows
if ( * cur = = ' e ' & & * bp = = ' 0 ' ) * bp = ' ' ; // for Windows
result . append ( bp , static_cast < std : : size_t > ( ep - bp ) ) ;
result . append ( bp , static_cast < std : : size_t > ( ep - bp ) ) ;
break ;
break ;
case ' U ' :
bp = Format02d ( ep , ToWeek ( civil_day ( al . cs ) , weekday : : sunday ) ) ;
result . append ( bp , static_cast < std : : size_t > ( ep - bp ) ) ;
break ;
case ' u ' :
bp = Format64 ( ep , 0 , tm . tm_wday ? tm . tm_wday : 7 ) ;
result . append ( bp , static_cast < std : : size_t > ( ep - bp ) ) ;
break ;
case ' W ' :
bp = Format02d ( ep , ToWeek ( civil_day ( al . cs ) , weekday : : monday ) ) ;
result . append ( bp , static_cast < std : : size_t > ( ep - bp ) ) ;
break ;
case ' w ' :
bp = Format64 ( ep , 0 , tm . tm_wday ) ;
result . append ( bp , static_cast < std : : size_t > ( ep - bp ) ) ;
break ;
case ' H ' :
case ' H ' :
bp = Format02d ( ep , al . cs . hour ( ) ) ;
bp = Format02d ( ep , al . cs . hour ( ) ) ;
result . append ( bp , static_cast < std : : size_t > ( ep - bp ) ) ;
result . append ( bp , static_cast < std : : size_t > ( ep - bp ) ) ;
@ -610,6 +653,17 @@ const char* ParseTM(const char* dp, const char* fmt, std::tm* tm) {
return dp ;
return dp ;
}
}
// Sets year, tm_mon and tm_mday given the year, week_num, and tm_wday,
// and the day on which weeks are defined to start.
void FromWeek ( int week_num , weekday week_start , year_t * year , std : : tm * tm ) {
const civil_year y ( * year % 400 ) ;
civil_day cd = prev_weekday ( y , week_start ) ; // week 0
cd = next_weekday ( cd - 1 , FromTmWday ( tm - > tm_wday ) ) + ( week_num * 7 ) ;
* year + = cd . year ( ) - y . year ( ) ;
tm - > tm_mon = cd . month ( ) - 1 ;
tm - > tm_mday = cd . day ( ) ;
}
} // namespace
} // namespace
// Uses strptime(3) to parse the given input. Supports the same extended
// Uses strptime(3) to parse the given input. Supports the same extended
@ -659,6 +713,8 @@ bool parse(const std::string& format, const std::string& input,
const char * fmt = format . c_str ( ) ; // NUL terminated
const char * fmt = format . c_str ( ) ; // NUL terminated
bool twelve_hour = false ;
bool twelve_hour = false ;
bool afternoon = false ;
bool afternoon = false ;
int week_num = - 1 ;
weekday week_start = weekday : : sunday ;
bool saw_percent_s = false ;
bool saw_percent_s = false ;
std : : int_fast64_t percent_s = 0 ;
std : : int_fast64_t percent_s = 0 ;
@ -697,10 +753,27 @@ bool parse(const std::string& format, const std::string& input,
case ' m ' :
case ' m ' :
data = ParseInt ( data , 2 , 1 , 12 , & tm . tm_mon ) ;
data = ParseInt ( data , 2 , 1 , 12 , & tm . tm_mon ) ;
if ( data ! = nullptr ) tm . tm_mon - = 1 ;
if ( data ! = nullptr ) tm . tm_mon - = 1 ;
week_num = - 1 ;
continue ;
continue ;
case ' d ' :
case ' d ' :
case ' e ' :
case ' e ' :
data = ParseInt ( data , 2 , 1 , 31 , & tm . tm_mday ) ;
data = ParseInt ( data , 2 , 1 , 31 , & tm . tm_mday ) ;
week_num = - 1 ;
continue ;
case ' U ' :
data = ParseInt ( data , 0 , 0 , 53 , & week_num ) ;
week_start = weekday : : sunday ;
continue ;
case ' W ' :
data = ParseInt ( data , 0 , 0 , 53 , & week_num ) ;
week_start = weekday : : monday ;
continue ;
case ' u ' :
data = ParseInt ( data , 0 , 1 , 7 , & tm . tm_wday ) ;
if ( data ! = nullptr ) tm . tm_wday % = 7 ;
continue ;
case ' w ' :
data = ParseInt ( data , 0 , 0 , 6 , & tm . tm_wday ) ;
continue ;
continue ;
case ' H ' :
case ' H ' :
data = ParseInt ( data , 2 , 0 , 23 , & tm . tm_hour ) ;
data = ParseInt ( data , 2 , 0 , 23 , & tm . tm_hour ) ;
@ -891,6 +964,9 @@ bool parse(const std::string& format, const std::string& input,
year + = 1900 ;
year + = 1900 ;
}
}
// Compute year, tm.tm_mon and tm.tm_mday if we parsed a week number.
if ( week_num ! = - 1 ) FromWeek ( week_num , week_start , & year , & tm ) ;
const int month = tm . tm_mon + 1 ;
const int month = tm . tm_mon + 1 ;
civil_second cs ( year , month , tm . tm_mday , tm . tm_hour , tm . tm_min , tm . tm_sec ) ;
civil_second cs ( year , month , tm . tm_mday , tm . tm_hour , tm . tm_min , tm . tm_sec ) ;