In boost::locale document it says:
date_time_period boost::locale::period::first_day_of_week(int v) [inline]
Get date_time_period for: First day of week, constant, for example Sunday in US = 1, Monday in France = 2
Those functions which return date_time_period
can be used to create custom boost::locale::date_time
objects.
I tried to create one with std::locale
set to "en_US.UTF-8"
, so the first day of week is default to Sunday, and then modified it to Monday. Here's the code:
#include <iostream>
#include <boost/locale.hpp>
int main() {
using namespace boost::locale;
date_time_period_set s;
generator gen;
std::locale locale = gen("en_US.UTF-8");
std::locale::global(locale);
std::cout.imbue(locale);
s.add(period::year(2000));
s.add(period::month(6));
s.add(period::day(5));
s.add(period::hour(9));
s.add(period::minute(0));
s.add(period::second(0));
s.add(period::first_day_of_week(2));// set the first day of week to Monday
date_time now(s); // should be 2000-07-05 09:00:00, week starts from Monday
std::cout << now << std::endl;
}
However, running the program results to an error:
terminate called after throwing an instance of 'std::invalid_argument'
what(): Invalid date_time period type
The error comes from its ICU backend adapter:
static UCalendarDateFields to_icu(period::marks::period_mark f)
{
using namespace period::marks;
switch(f) {
case era: return UCAL_ERA;
case year: return UCAL_YEAR;
case extended_year: return UCAL_EXTENDED_YEAR;
case month: return UCAL_MONTH;
case day: return UCAL_DATE;
case day_of_year: return UCAL_DAY_OF_YEAR;
case day_of_week: return UCAL_DAY_OF_WEEK;
case day_of_week_in_month: return UCAL_DAY_OF_WEEK_IN_MONTH;
case day_of_week_local: return UCAL_DOW_LOCAL;
case hour: return UCAL_HOUR_OF_DAY;
case hour_12: return UCAL_HOUR;
case am_pm: return UCAL_AM_PM;
case minute: return UCAL_MINUTE;
case second: return UCAL_SECOND;
case week_of_year: return UCAL_WEEK_OF_YEAR;
case week_of_month: return UCAL_WEEK_OF_MONTH;
default:
throw std::invalid_argument("Invalid date_time period type");
}
}
first_day_of_week
is not acceptable.
So the questions are:
- Can a
boost::locale::date_time
object be created with modified "the first day of week"? If true, how to do it?
- How (or where) to use
date_time_period boost::locale::period::first_day_of_week(int v)
?
This seems confusing indeed.
Preliminaries:
std::locale english = gen("en_US.UTF-8");
std::locale french = gen("fr_FR.UTF-8");
std::cout.imbue(english); // this one doesn't matter
std::locale::global(french);
After some (extensive) tests, I figured out that the value for first_day_of_week
on a date_time
instance is:
set from the global locale at the time of the construction
std::locale::global(english);
assert(1 == period::first_day_of_week(date_time()));
std::locale::global(french);
assert(2 == period::first_day_of_week(date_time()));
or: set from the locale that is passed during construction
assert(1 == period::first_day_of_week(date_time(english)));
assert(2 == period::first_day_of_week(date_time(french)));
or: set from the date_time
object that is passed during copy construction (ignoring locale)
date_time edt(english), fdt(french);
assert(1 == period::first_day_of_week(edt));
edt = date_time(french);
assert(2 == period::first_day_of_week(edt));
fdt = date_time(english);
assert(1 == period::first_day_of_week(fdt));
and most importantly: cannot be set from another source than the locale
{
date_time_period_set dtps;
dtps.add(period::friday());
dtps.add(period::week_of_year(4));
// no effect
dtps.add(period::first_day_of_week(1));
assert(2 == period::first_day_of_week(date_time(dtps)));
}
{
date_time dt;
// no effect:
dt.set(period::first_day_of_week(), 1);
assert(2 == period::first_day_of_week(dt));
}
Whether or not this is a bug, I leave up to the devs. You can maybe ask it on the boost mailing list. It sure is surprising, as the presence of a set
interface suggests that this property can be changed.
In fact it appears that the first weekday property is not a property of a date_time
in the first place, but rather a property of the locale
, and it appears that the locale "imbued" on a date_time
instance can not be changed except at construction/assignment.
Full tests: Live On Coliru
#include <boost/locale.hpp>
#include <iostream>
int main()
{
using namespace boost::locale;
generator gen;
std::locale english = gen("en_US.UTF-8");
std::locale french = gen("fr_FR.UTF-8");
std::cout.imbue(english); // this one doesn't matter
std::locale::global(french);
{
std::locale::global(english);
assert(1 == period::first_day_of_week(date_time()));
std::locale::global(french);
assert(2 == period::first_day_of_week(date_time()));
}
{
assert(1 == period::first_day_of_week(date_time(english)));
assert(2 == period::first_day_of_week(date_time(french)));
}
{
date_time_period_set dtps;
dtps.add(period::friday());
dtps.add(period::week_of_year(4));
// no effect
dtps.add(period::first_day_of_week(1));
assert(2 == period::first_day_of_week(date_time(dtps)));
}
{
date_time dt;
// no effect:
dt.set(period::first_day_of_week(), 1);
assert(2 == period::first_day_of_week(dt));
}
{
// associated locale gets copied:
date_time edt(english), fdt(french);
assert(1 == period::first_day_of_week(edt));
edt = date_time(french);
assert(2 == period::first_day_of_week(edt));
fdt = date_time(english);
assert(1 == period::first_day_of_week(fdt));
}
std::cout << "All tests passed\n";
}