Skip to content

Commit

Permalink
Fixed a bug for parsing posix timezone: the + sign must be used for t…
Browse files Browse the repository at this point in the history
…imezones on the west of UTC, and - for timezones on the east of UTC correspondingly.

Fixes:
* https://svn.boost.org/trac/boost/ticket/4545
* https://svn.boost.org/trac/boost/ticket/3336
  • Loading branch information
zerkms committed Oct 6, 2015
1 parent 75d979c commit 3204e59
Show file tree
Hide file tree
Showing 17 changed files with 114 additions and 114 deletions.
4 changes: 2 additions & 2 deletions include/boost/date_time/local_time/custom_time_zone.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,10 @@ namespace local_time {
// offset
if(base_utc_offset().is_negative()) {
// inverting the sign guarantees we get two digits
ss << '-' << std::setw(2) << base_utc_offset().invert_sign().hours();
ss << '+' << std::setw(2) << base_utc_offset().invert_sign().hours();
}
else {
ss << '+' << std::setw(2) << base_utc_offset().hours();
ss << '-' << std::setw(2) << base_utc_offset().hours();
}
if(base_utc_offset().minutes() != 0 || base_utc_offset().seconds() != 0) {
ss << ':' << std::setw(2) << base_utc_offset().minutes();
Expand Down
6 changes: 3 additions & 3 deletions include/boost/date_time/local_time/posix_time_zone.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,10 +190,10 @@ namespace local_time{
// offset
if(base_utc_offset().is_negative()) {
// inverting the sign guarantees we get two digits
ss << '-' << std::setw(2) << base_utc_offset().invert_sign().hours();
ss << '+' << std::setw(2) << base_utc_offset().invert_sign().hours();
}
else {
ss << '+' << std::setw(2) << base_utc_offset().hours();
ss << '-' << std::setw(2) << base_utc_offset().hours();
}
if(base_utc_offset().minutes() != 0 || base_utc_offset().seconds() != 0) {
ss << ':' << std::setw(2) << base_utc_offset().minutes();
Expand Down Expand Up @@ -266,7 +266,7 @@ namespace local_time{
while(sit != obj_end && !std::isalpha(*sit)){
ss << *sit++;
}
base_utc_offset_ = date_time::str_from_delimited_time_duration<time_duration_type,char_type>(ss.str());
base_utc_offset_ = date_time::str_from_delimited_time_duration<time_duration_type,char_type>(ss.str()).invert_sign();
ss.str(empty_string);

// base offset must be within range of -12 hours to +14 hours
Expand Down
4 changes: 2 additions & 2 deletions test/local_time/testclocks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ main()
using namespace boost::local_time;


boost::shared_ptr<time_zone> az_tz(new posix_time_zone("MST-07"));
boost::shared_ptr<time_zone> ny_tz(new posix_time_zone("EST-05EDT,M4.1.0,M10.5.0"));
boost::shared_ptr<time_zone> az_tz(new posix_time_zone("MST+07"));
boost::shared_ptr<time_zone> ny_tz(new posix_time_zone("EST+05EDT,M4.1.0,M10.5.0"));

ptime tl = second_clock::local_time();
std::cout << to_simple_string(tl) << std::endl;
Expand Down
8 changes: 4 additions & 4 deletions test/local_time/testcustom_time_zone.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,13 @@ main()
tz1->dst_local_end_time(2003) == ptime(date(2003,Oct,30),hours(2)));

check("tz1 to posix string",
tz1->to_posix_string() == std::string("PST-08PDT+01,120/02:00,303/02:00"));
tz1->to_posix_string() == std::string("PST+08PDT+01,120/02:00,303/02:00"));
check("tz2 to posix string",
tz2->to_posix_string() == std::string("PST-08PDT+01,M4.1.0/02:00,M10.5.0/02:00"));
tz2->to_posix_string() == std::string("PST+08PDT+01,M4.1.0/02:00,M10.5.0/02:00"));
check("tz3 to posix string",
tz3->to_posix_string() == std::string("PST-08PDT+01,M3.5.0/02:00,M10.5.0/02:00"));
tz3->to_posix_string() == std::string("PST+08PDT+01,M3.5.0/02:00,M10.5.0/02:00"));
check("tz4 to posix string",
tz4->to_posix_string() == std::string("MST-07"));
tz4->to_posix_string() == std::string("MST+07"));

// test start/end for non-dst zone
check("has dst in non-dst zone", !tz4->has_dst());
Expand Down
6 changes: 3 additions & 3 deletions test/local_time/testlocal_time.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ main()
// of these operations is done in the posix_time tests

try {
time_zone_ptr az_tz(new posix_time_zone("MST-07"));
time_zone_ptr ny_tz(new posix_time_zone("EST-05EDT,M4.1.0,M10.5.0"));
time_zone_ptr az_tz(new posix_time_zone("MST+07"));
time_zone_ptr ny_tz(new posix_time_zone("EST+05EDT,M4.1.0,M10.5.0"));
// EST & EST for sydney is correct, according to zoneinfo files
time_zone_ptr sydney(new posix_time_zone("EST+10EST,M10.5.0,M3.5.0/03:00"));
time_zone_ptr sydney(new posix_time_zone("EST-10EST,M10.5.0,M3.5.0/03:00"));
time_zone_ptr null_tz;
date d(2003, 12, 20);
hours h(12);
Expand Down
40 changes: 20 additions & 20 deletions test/local_time/testlocal_time_input_facet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ int main() {
#if !defined(BOOST_NO_STD_WSTRING)
{
std::wstringstream ws;
ws.str(L"2005-Feb-15 12:15:00 EST-05EDT,M4.1.0,M10.5.0");
ws.str(L"2005-Feb-15 12:15:00 EST+05EDT,M4.1.0,M10.5.0");
ws >> ldt1;
check("Wide stream, Eastern US, daylight savings, winter, minimal input",
ldt1.local_time() == ptime(date(2005,2,15), time_duration(12,15,0)));
Expand All @@ -82,7 +82,7 @@ int main() {
wlocal_time_input_facet* wfacet = new wlocal_time_input_facet(L"%m/%d/%y %ZP");
std::locale loc(std::locale::classic(), wfacet);
ws.imbue(loc);
ws.str(L"10/31/04 PST-08PDT,M4.1.0,M10.5.0"); // midnight on end transition day, still in dst
ws.str(L"10/31/04 PST+08PDT,M4.1.0,M10.5.0"); // midnight on end transition day, still in dst
ws >> ldt1;
std::wcout << ldt1.local_time() << std::endl;
check("Wide stream, Eastern US, daylight savings, winter, custom format",
Expand All @@ -94,7 +94,7 @@ int main() {
#endif // BOOST_NO_STD_WSTRING

std::stringstream ss;
ss.str("2005-Feb-25 12:15:00 EST-05EDT,M4.1.0,M10.5.0");
ss.str("2005-Feb-25 12:15:00 EST+05EDT,M4.1.0,M10.5.0");
ss >> ldt1;
check("Eastern US, daylight savings, winter, minimal input",
ldt1.local_time() == ptime(date(2005,2,25), time_duration(12,15,0)));
Expand All @@ -103,7 +103,7 @@ int main() {
check("Eastern US, daylight savings, winter, minimal input", !ldt1.is_dst());
ss.str("");

ss.str("2005-Aug-25 12:15:00 EST-05EDT,M4.1.0,M10.5.0");
ss.str("2005-Aug-25 12:15:00 EST+05EDT,M4.1.0,M10.5.0");
ss >> ldt1;
check("Eastern US, daylight savings, summer, minimal input",
ldt1.local_time() == ptime(date(2005,8,25), time_duration(12,15,0)));
Expand All @@ -112,28 +112,28 @@ int main() {
check("Eastern US, daylight savings, summer, minimal input", ldt1.is_dst());
ss.str("");

ss.str("2005-Apr-03 01:15:00 EST-05EDT,M4.1.0,M10.5.0");
ss.str("2005-Apr-03 01:15:00 EST+05EDT,M4.1.0,M10.5.0");
ss >> ldt1;
check("Eastern US, daylight savings, transition point", !ldt1.is_dst());
ldt1 += hours(1);
check("Eastern US, daylight savings, transition point", ldt1.is_dst());
ss.str("");
ss.str("2005-Apr-03 01:15:00 EST-05EDT,93,303");
ss.str("2005-Apr-03 01:15:00 EST+05EDT,93,303");
ss >> ldt1;
check("Eastern US, daylight savings, transition point", !ldt1.is_dst());
ldt1 += hours(1);
check("Eastern US, daylight savings, transition point", ldt1.is_dst());
ss.str("");

ss.str("2005-Oct-30 00:15:00 EST-05EDT,M4.1.0,M10.5.0");
ss.str("2005-Oct-30 00:15:00 EST+05EDT,M4.1.0,M10.5.0");
ss >> ldt1;
check("Eastern US, daylight savings, transition point", ldt1.is_dst());
ldt1 += hours(1);
check("Eastern US, daylight savings, transition point", ldt1.is_dst());
ldt1 += hours(1);
check("Eastern US, daylight savings, transition point", !ldt1.is_dst());
ss.str("");
ss.str("2005-Oct-30 00:15:00 EST-05EDT,93,303");
ss.str("2005-Oct-30 00:15:00 EST+05EDT,93,303");
ss >> ldt1;
check("Eastern US, daylight savings, transition point", ldt1.is_dst());
ldt1 += hours(1);
Expand All @@ -142,7 +142,7 @@ int main() {
check("Eastern US, daylight savings, transition point", !ldt1.is_dst());
ss.str("");

ss.str("2005-Aug-25 12:15:00 MST-07");
ss.str("2005-Aug-25 12:15:00 MST+07");
ss >> ldt1;
check("Mountain US, no daylight savings",
ldt1.local_time() == ptime(date(2005,8,25), time_duration(12,15,0)));
Expand All @@ -156,7 +156,7 @@ int main() {
new local_time_facet(local_time_input_facet::default_time_input_format);
std::locale loc(std::locale::classic(), out_facet);
ss.imbue(loc);
time_zone_ptr syd_tz(new posix_time_zone("EST+10EST,M10.5.0,M3.5.0/03:00"));
time_zone_ptr syd_tz(new posix_time_zone("EST-10EST,M10.5.0,M3.5.0/03:00"));
ptime pt(date(2005,6,12), hours(0));
local_date_time ldt2(pt, syd_tz);
ss << ldt2;
Expand All @@ -166,7 +166,7 @@ int main() {
ldt1.zone()->dst_local_start_time(2004) == ldt2.zone()->dst_local_start_time(2004));
ss.str("");

time_zone_ptr f_tz(new posix_time_zone("FST+03FDT,90,300"));
time_zone_ptr f_tz(new posix_time_zone("FST-03FDT,90,300"));
ldt2 = local_date_time(ptime(date(2005,6,12), hours(0)), f_tz);
ss << ldt2;
ss >> ldt1;
Expand All @@ -182,7 +182,7 @@ int main() {
check("Missing time_zone spec makes UTC", ldt1.utc_time() == ldt1.local_time());
ss.str("");
{
std::istringstream iss("2005-Aug-25 12:15:00 MST-07");
std::istringstream iss("2005-Aug-25 12:15:00 MST+07");
local_time_input_facet* f = new local_time_input_facet("%Y-%b-%d %H:%M:%S %z");
std::locale loc(std::locale::classic(), f);
iss.imbue(loc);
Expand All @@ -199,39 +199,39 @@ int main() {
time_label_invalid inv_ex("default");
check("Failure test ambiguous time label (w/exceptions)",
failure_test(ldt1,
"2005-Oct-30 01:15:00 EST-05EDT,M4.1.0,M10.5.0",
"2005-Oct-30 01:15:00 EST+05EDT,M4.1.0,M10.5.0",
amb_ex,
new local_time_input_facet()));
check("Failure test ambiguous time label (no exceptions)",
failure_test(ldt1,
"2005-Oct-30 01:15:00 EST-05EDT,M4.1.0,M10.5.0",
"2005-Oct-30 01:15:00 EST+05EDT,M4.1.0,M10.5.0",
new local_time_input_facet()));
check("Failure test ambiguous time label (w/exceptions)",
failure_test(ldt1,
"2005-Oct-30 01:15:00 EST-05EDT,93,303",
"2005-Oct-30 01:15:00 EST+05EDT,93,303",
amb_ex,
new local_time_input_facet()));
check("Failure test ambiguous time label (no exceptions)",
failure_test(ldt1,
"2005-Oct-30 01:15:00 EST-05EDT,93,303",
"2005-Oct-30 01:15:00 EST+05EDT,93,303",
new local_time_input_facet()));
check("Failure test invalid time label (w/exceptions)",
failure_test(ldt1,
"2005-Apr-03 02:15:00 EST-05EDT,M4.1.0,M10.5.0",
"2005-Apr-03 02:15:00 EST+05EDT,M4.1.0,M10.5.0",
inv_ex,
new local_time_input_facet()));
check("Failure test invalid time label (no exceptions)",
failure_test(ldt1,
"2005-Apr-03 02:15:00 EST-05EDT,M4.1.0,M10.5.0",
"2005-Apr-03 02:15:00 EST+05EDT,M4.1.0,M10.5.0",
new local_time_input_facet()));
check("Failure test invalid time label (w/exceptions)",
failure_test(ldt1,
"2005-Apr-03 02:15:00 EST-05EDT,93,303",
"2005-Apr-03 02:15:00 EST+05EDT,93,303",
inv_ex,
new local_time_input_facet()));
check("Failure test invalid time label (no exceptions)",
failure_test(ldt1,
"2005-Apr-03 02:15:00 EST-05EDT,93,303",
"2005-Apr-03 02:15:00 EST+05EDT,93,303",
new local_time_input_facet()));


Expand Down
2 changes: 1 addition & 1 deletion test/local_time/testlocal_time_iterator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ int
main()
{

time_zone_ptr ny_tz(new posix_time_zone("EST-05EDT,M4.1.0,M10.5.0"));
time_zone_ptr ny_tz(new posix_time_zone("EST+05EDT,M4.1.0,M10.5.0"));

//set up a time right on the dst boundary -- iterator will
//jump forward an hour at the boundary
Expand Down
2 changes: 1 addition & 1 deletion test/local_time/testlocal_time_period.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ int main()
using namespace boost::local_time;
date d1(2001,Jan, 1);

time_zone_ptr az_tz(new posix_time_zone("MST-07"));
time_zone_ptr az_tz(new posix_time_zone("MST+07"));

local_date_time t1 (d1,hours(2), az_tz, false);//2001-Jan-1 02:00:00

Expand Down
42 changes: 21 additions & 21 deletions test/local_time/testposix_time_zone.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ int main(){
using namespace boost::local_time;
using namespace boost::posix_time;
using namespace boost::gregorian;
std::string specs[] = {"MST-07", "MST-07:00:00","EST-05EDT,M4.1.0,M10.5.0", "EST-05:00:00EDT+01:00:00,M4.1.0/02:00:00,M10.5.0/02:00:00","PST-08PDT,J46/1:30,J310","PST-08PDT,45,310/0:30:00"};
std::string specs[] = {"MST+07", "MST+07:00:00","EST+05EDT,M4.1.0,M10.5.0", "EST+05:00:00EDT+01:00:00,M4.1.0/02:00:00,M10.5.0/02:00:00","PST+08PDT,J46/1:30,J310","PST+08PDT,45,310/0:30:00"};

posix_time_zone nyc1(specs[2]);
posix_time_zone nyc2(specs[3]);
Expand Down Expand Up @@ -49,9 +49,9 @@ int main(){
check("dst ends match", nyc1.dst_local_end_time(2003) ==
nyc2.dst_local_end_time(2003));
check("to posix string",
nyc1.to_posix_string() == std::string("EST-05EDT+01,M4.1.0/02:00,M10.5.0/02:00"));
nyc1.to_posix_string() == std::string("EST+05EDT+01,M4.1.0/02:00,M10.5.0/02:00"));
check("to posix string",
nyc2.to_posix_string() == std::string("EST-05EDT+01,M4.1.0/02:00,M10.5.0/02:00"));
nyc2.to_posix_string() == std::string("EST+05EDT+01,M4.1.0/02:00,M10.5.0/02:00"));


posix_time_zone az1(specs[0]);
Expand All @@ -75,14 +75,14 @@ int main(){
check("Names", az1.dst_zone_name() == std::string(""));
check("Names", az2.dst_zone_name() == std::string(""));
check("to posix string",
az1.to_posix_string() == std::string("MST-07"));
az1.to_posix_string() == std::string("MST+07"));
check("to posix string",
az2.to_posix_string() == std::string("MST-07"));
az2.to_posix_string() == std::string("MST+07"));


// bizzar time zone spec to fully test parsing
std::cout << "\nFictitious time zone" << std::endl;
posix_time_zone bz("BST+11:21:15BDT-00:28,M2.2.4/03:15:42,M11.5.2/01:08:53");
posix_time_zone bz("BST-11:21:15BDT-00:28,M2.2.4/03:15:42,M11.5.2/01:08:53");
check("hast dst", bz.has_dst());
check("UTC offset", bz.base_utc_offset() == time_duration(11,21,15));
check("Abbrev", bz.std_zone_abbrev() == std::string("BST"));
Expand All @@ -95,8 +95,8 @@ int main(){

// only checking start & end rules w/ 'J' notation
std::cout << "\n'J' notation Start/End rule tests..." << std::endl;
posix_time_zone la1(specs[4]); // "PST-08PDT,J124,J310"
//posix_time_zone la1("PST-08PDT,J1,J365");// Jan1/Dec31
posix_time_zone la1(specs[4]); // "PST+08PDT,J124,J310"
//posix_time_zone la1("PST+08PDT,J1,J365");// Jan1/Dec31
check("dst start", la1.dst_local_start_time(2003) ==
ptime(date(2003,Feb,15),time_duration(1,30,0)));
check("dst end", la1.dst_local_end_time(2003) ==
Expand All @@ -109,44 +109,44 @@ int main(){
* be written in 'n' notation. The reverse is not true so 'n' notation
* is used as the output for to_posix_string(). */
check("to posix string",
la1.to_posix_string() == std::string("PST-08PDT+01,45/01:30,310/02:00"));
la1.to_posix_string() == std::string("PST+08PDT+01,45/01:30,310/02:00"));

// only checking start & end rules w/ 'n' notation
std::cout << "\n'n' notation Start/End rule tests..." << std::endl;
posix_time_zone la2(specs[5]); // "PST-08PDT,124,310"
//posix_time_zone la2("PST-08PDT,0,365");// Jan1/Dec31
posix_time_zone la2(specs[5]); // "PST+08PDT,124,310"
//posix_time_zone la2("PST+08PDT,0,365");// Jan1/Dec31
check("dst start", la2.dst_local_start_time(2003) ==
ptime(date(2003,Feb,15),time_duration(2,0,0)));
check("dst end", la2.dst_local_end_time(2003) ==
ptime(date(2003,Nov,6),time_duration(0,30,0)));
check("to posix string",
la2.to_posix_string() == std::string("PST-08PDT+01,45/02:00,310/00:30"));
la2.to_posix_string() == std::string("PST+08PDT+01,45/02:00,310/00:30"));

// bad posix time zone strings tests
std::cout << "\nInvalid time zone string tests..." << std::endl;
try {
posix_time_zone badz("EST-13");
posix_time_zone badz("EST+13");
check("Exception not thrown: bad UTC offset", false);
}catch(bad_offset& boff){
std::string msg(boff.what());
check("Exception caught: "+msg , true);
}
try {
posix_time_zone badz("EST-5EDT24:00:01,J124/1:30,J310");
posix_time_zone badz("EST+5EDT24:00:01,J124/1:30,J310");
check("Exception not thrown: bad DST adjust", false);
}catch(bad_adjustment& badj){
std::string msg(badj.what());
check("Exception caught: "+msg , true);
}
try {
posix_time_zone badz("EST-5EDT01:00:00,J124/-1:30,J310");
posix_time_zone badz("EST+5EDT01:00:00,J124/-1:30,J310");
check("Exception not thrown: bad DST start/end offset", false);
}catch(bad_offset& boff){
std::string msg(boff.what());
check("Exception caught: "+msg , true);
}
try {
posix_time_zone badz("EST-5EDT01:00:00,J124/1:30,J370");
posix_time_zone badz("EST+5EDT01:00:00,J124/1:30,J370");
check("Exception not thrown: invalid date spec", false);
}catch(boost::gregorian::bad_day_of_month& boff){
std::string msg(boff.what());
Expand All @@ -163,7 +163,7 @@ int main(){
//Test a timezone spec on the positive side of the UTC line.
//This is the time for central europe which is one hour in front of UTC
//Note these Summer time transition rules aren't actually correct.
posix_time_zone cet_tz("CET+01:00:00EDT+01:00:00,M4.1.0/02:00:00,M10.5.0/02:00:00");
posix_time_zone cet_tz("CET-01:00:00EDT+01:00:00,M4.1.0/02:00:00,M10.5.0/02:00:00");
check("Has DST", cet_tz.has_dst());
check("UTC offset", cet_tz.base_utc_offset() == hours(1));
check("Abbrevs", cet_tz.std_zone_abbrev() == std::string("CET"));
Expand All @@ -174,7 +174,7 @@ int main(){
//Test a timezone spec on the positive side of the UTC line.
//This is the time for central europe which is one hour in front of UTC
//Note these Summer time transition rules aren't actually correct.
posix_time_zone caus_tz("CAS+08:30:00CDT+01:00:00,M4.1.0/02:00:00,M10.5.0/02:00:00");
posix_time_zone caus_tz("CAS-08:30:00CDT+01:00:00,M4.1.0/02:00:00,M10.5.0/02:00:00");
check("Has DST", caus_tz.has_dst());
check("UTC offset", caus_tz.base_utc_offset() == hours(8)+minutes(30));
check("Abbrevs", caus_tz.std_zone_abbrev() == std::string("CAS"));
Expand All @@ -183,7 +183,7 @@ int main(){
{
/**** first/last of month Julian & non-Julian tests ****/
// Mar-01 & Oct-31, count begins at 1
std::string spec("FST+3FDT,J60,J304");
std::string spec("FST-3FDT,J60,J304");
posix_time_zone fl_1(spec);
check("Julian First/last of month", fl_1.dst_local_start_time(2003) ==
ptime(date(2003,Mar,1),hours(2)));
Expand All @@ -195,7 +195,7 @@ int main(){
ptime(date(2004,Oct,31),hours(2)));

// Mar-01 & Oct-31 Non-leap year, count begins at 0
spec = "FST+3FDT,59,304"; // "304" is not a mistake here, see posix_time_zone docs
spec = "FST-3FDT,59,304"; // "304" is not a mistake here, see posix_time_zone docs
posix_time_zone fl_2(spec);
try{
check("Non-Julian First/last of month", fl_2.dst_local_start_time(2003) ==
Expand All @@ -207,7 +207,7 @@ int main(){
ptime(date(2003,Oct,31),hours(2)));

// Mar-01 & Oct-31 leap year, count begins at 0
spec = "FST+3FDT,60,304";
spec = "FST-3FDT,60,304";
posix_time_zone fl_3(spec);
check("Non-Julian First/last of month", fl_3.dst_local_start_time(2004) ==
ptime(date(2004,Mar,1),hours(2)));
Expand Down
Loading

0 comments on commit 3204e59

Please sign in to comment.