1 | /* Copyright (c) 2003-2004 CrystalClear Software, Inc. |
2 | * Subject to the Boost Software License, Version 1.0. |
3 | * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) |
4 | * Author: Jeff Garland, Bart Garst |
5 | * $Date$ |
6 | */ |
7 | |
8 | |
9 | #include "boost/date_time/gregorian/gregorian.hpp" |
10 | //#include "boost/date_time/local_time/time_zone.hpp" |
11 | #include "../testfrmwk.hpp" |
12 | |
13 | #include "boost/date_time/local_time/posix_time_zone.hpp" |
14 | |
15 | #include <string> |
16 | #include <iostream> |
17 | |
18 | int main(){ |
19 | using namespace boost::local_time; |
20 | using namespace boost::posix_time; |
21 | using namespace boost::gregorian; |
22 | |
23 | typedef posix_time_zone_base<wchar_t> w_posix_time_zone; |
24 | |
25 | std::wstring specs[] = {L"MST-07" , L"MST-07:00:00" ,L"EST-05EDT,M4.1.0,M10.5.0" , L"EST-05:00:00EDT+01:00:00,M4.1.0/02:00:00,M10.5.0/02:00:00" ,L"PST-08PDT,J46/1:30,J310" ,L"PST-08PDT,45,310/0:30:00" }; |
26 | |
27 | w_posix_time_zone nyc1(specs[2]); |
28 | w_posix_time_zone nyc2(specs[3]); |
29 | time_duration td = hours(-5); |
30 | |
31 | check(testname: "Has DST" , testcond: nyc1.has_dst() && nyc2.has_dst()); |
32 | check(testname: "UTC offset" , testcond: nyc1.base_utc_offset() == td); |
33 | check(testname: "UTC offsets match" , testcond: nyc1.base_utc_offset() == nyc2.base_utc_offset()); |
34 | check(testname: "Abbrevs" , testcond: nyc1.std_zone_abbrev() == std::wstring(L"EST" )); |
35 | check(testname: "Abbrevs" , testcond: nyc2.std_zone_abbrev() == std::wstring(L"EST" )); |
36 | check(testname: "Abbrevs" , testcond: nyc1.dst_zone_abbrev() == std::wstring(L"EDT" )); |
37 | check(testname: "Abbrevs" , testcond: nyc2.dst_zone_abbrev() == std::wstring(L"EDT" )); |
38 | // names not available for w_posix_time_zone, abbrevs used in their place |
39 | check(testname: "Names" , testcond: nyc1.std_zone_name() == std::wstring(L"EST" )); |
40 | check(testname: "Names" , testcond: nyc2.std_zone_name() == std::wstring(L"EST" )); |
41 | check(testname: "Names" , testcond: nyc1.dst_zone_name() == std::wstring(L"EDT" )); |
42 | check(testname: "Names" , testcond: nyc2.dst_zone_name() == std::wstring(L"EDT" )); |
43 | td = hours(1); |
44 | check(testname: "dst offset" , testcond: nyc1.dst_offset() == td); |
45 | check(testname: "dst offsets match" , testcond: nyc1.dst_offset() == nyc2.dst_offset()); |
46 | check(testname: "dst start" , testcond: nyc1.dst_local_start_time(y: 2003) == |
47 | ptime(date(2003,Apr,6),time_duration(2,0,0))); |
48 | check(testname: "dst starts match" , testcond: nyc1.dst_local_start_time(y: 2003) == |
49 | nyc2.dst_local_start_time(y: 2003)); |
50 | check(testname: "dst end" , testcond: nyc1.dst_local_end_time(y: 2003) == |
51 | ptime(date(2003,Oct,26),time_duration(2,0,0))); |
52 | check(testname: "dst ends match" , testcond: nyc1.dst_local_end_time(y: 2003) == |
53 | nyc2.dst_local_end_time(y: 2003)); |
54 | check(testname: "to posix string" , |
55 | testcond: nyc1.to_posix_string() == std::wstring(L"EST-05EDT+01,M4.1.0/02:00,M10.5.0/02:00" )); |
56 | check(testname: "to posix string" , |
57 | testcond: nyc2.to_posix_string() == std::wstring(L"EST-05EDT+01,M4.1.0/02:00,M10.5.0/02:00" )); |
58 | |
59 | |
60 | w_posix_time_zone az1(specs[0]); |
61 | w_posix_time_zone az2(specs[1]); |
62 | td = hours(-7); |
63 | |
64 | check(testname: "Has DST" , testcond: !az1.has_dst() && !az2.has_dst()); |
65 | check(testname: "UTC offset" , testcond: az1.base_utc_offset() == td); |
66 | check(testname: "UTC offsets match" , testcond: az1.base_utc_offset() == az2.base_utc_offset()); |
67 | check(testname: "dst start in non-dst zone" , |
68 | testcond: az1.dst_local_start_time(y: 2005) == ptime(not_a_date_time)); |
69 | check(testname: "dst end in non-dst zone" , |
70 | testcond: az2.dst_local_end_time(y: 2005) == ptime(not_a_date_time)); |
71 | check(testname: "Abbrevs" , testcond: az1.std_zone_abbrev() == std::wstring(L"MST" )); |
72 | check(testname: "Abbrevs" , testcond: az2.std_zone_abbrev() == std::wstring(L"MST" )); |
73 | // non-dst zones default to empty strings for dst names & abbrevs |
74 | check(testname: "Abbrevs" , testcond: az1.dst_zone_abbrev() == std::wstring(L"" )); |
75 | check(testname: "Abbrevs" , testcond: az2.dst_zone_abbrev() == std::wstring(L"" )); |
76 | check(testname: "Names" , testcond: az1.std_zone_name() == std::wstring(L"MST" )); |
77 | check(testname: "Names" , testcond: az2.std_zone_name() == std::wstring(L"MST" )); |
78 | check(testname: "Names" , testcond: az1.dst_zone_name() == std::wstring(L"" )); |
79 | check(testname: "Names" , testcond: az2.dst_zone_name() == std::wstring(L"" )); |
80 | check(testname: "to posix string" , |
81 | testcond: az1.to_posix_string() == std::wstring(L"MST-07" )); |
82 | check(testname: "to posix string" , |
83 | testcond: az2.to_posix_string() == std::wstring(L"MST-07" )); |
84 | |
85 | |
86 | // bizzar time zone spec to fully test parsing |
87 | std::cout << "\nFictitious time zone" << std::endl; |
88 | w_posix_time_zone bz(L"BST+11:21:15BDT-00:28,M2.2.4/03:15:42,M11.5.2/01:08:53" ); |
89 | check(testname: "hast dst" , testcond: bz.has_dst()); |
90 | check(testname: "UTC offset" , testcond: bz.base_utc_offset() == time_duration(11,21,15)); |
91 | check(testname: "Abbrev" , testcond: bz.std_zone_abbrev() == std::wstring(L"BST" )); |
92 | check(testname: "Abbrev" , testcond: bz.dst_zone_abbrev() == std::wstring(L"BDT" )); |
93 | check(testname: "dst offset" , testcond: bz.dst_offset() == time_duration(0,-28,0)); |
94 | check(testname: "dst start" , testcond: bz.dst_local_start_time(y: 1962) == |
95 | ptime(date(1962,Feb,8),time_duration(3,15,42))); |
96 | check(testname: "dst end" , testcond: bz.dst_local_end_time(y: 1962) == |
97 | ptime(date(1962,Nov,27),time_duration(1,8,53))); |
98 | |
99 | // only checking start & end rules w/ 'J' notation |
100 | std::cout << "\n'J' notation Start/End rule tests..." << std::endl; |
101 | w_posix_time_zone la1(specs[4]); // "PST-08PDT,J124,J310" |
102 | //w_posix_time_zone la1("PST-08PDT,J1,J365");// Jan1/Dec31 |
103 | check(testname: "dst start" , testcond: la1.dst_local_start_time(y: 2003) == |
104 | ptime(date(2003,Feb,15),time_duration(1,30,0))); |
105 | check(testname: "dst end" , testcond: la1.dst_local_end_time(y: 2003) == |
106 | ptime(date(2003,Nov,6),time_duration(2,0,0))); |
107 | /* NOTE: la1 was created from a 'J' notation string but to_posix_string |
108 | * returns an 'n' notation string. The difference between the two |
109 | * is Feb-29 is always counted in an 'n' notation string and numbering |
110 | * starts at zero ('J' notation starts at one). |
111 | * Every possible date spec that can be written in 'J' notation can also |
112 | * be written in 'n' notation. The reverse is not true so 'n' notation |
113 | * is used as the output for to_posix_string(). */ |
114 | check(testname: "to posix string" , |
115 | testcond: la1.to_posix_string() == std::wstring(L"PST-08PDT+01,45/01:30,310/02:00" )); |
116 | |
117 | // only checking start & end rules w/ 'n' notation |
118 | std::cout << "\n'n' notation Start/End rule tests..." << std::endl; |
119 | w_posix_time_zone la2(specs[5]); // "PST-08PDT,124,310" |
120 | //w_posix_time_zone la2("PST-08PDT,0,365");// Jan1/Dec31 |
121 | check(testname: "dst start" , testcond: la2.dst_local_start_time(y: 2003) == |
122 | ptime(date(2003,Feb,15),time_duration(2,0,0))); |
123 | check(testname: "dst end" , testcond: la2.dst_local_end_time(y: 2003) == |
124 | ptime(date(2003,Nov,6),time_duration(0,30,0))); |
125 | check(testname: "to posix string" , |
126 | testcond: la2.to_posix_string() == std::wstring(L"PST-08PDT+01,45/02:00,310/00:30" )); |
127 | |
128 | // bad posix time zone strings tests |
129 | std::cout << "\nInvalid time zone string tests..." << std::endl; |
130 | try { |
131 | w_posix_time_zone badz(L"EST-13" ); |
132 | check(testname: "Exception not thrown: bad UTC offset" , testcond: false); |
133 | }catch(bad_offset& boff){ |
134 | std::string msg(boff.what()); |
135 | check(testname: "Exception caught: " +msg , testcond: true); |
136 | } |
137 | try { |
138 | w_posix_time_zone badz(L"EST-5EDT24:00:01,J124/1:30,J310" ); |
139 | check(testname: "Exception not thrown: bad DST adjust" , testcond: false); |
140 | }catch(bad_adjustment& badj){ |
141 | std::string msg(badj.what()); |
142 | check(testname: "Exception caught: " +msg , testcond: true); |
143 | } |
144 | try { |
145 | w_posix_time_zone badz(L"EST-5EDT01:00:00,J124/-1:30,J310" ); |
146 | check(testname: "Exception not thrown: bad DST start/end offset" , testcond: false); |
147 | }catch(bad_offset& boff){ |
148 | std::string msg(boff.what()); |
149 | check(testname: "Exception caught: " +msg , testcond: true); |
150 | } |
151 | try { |
152 | w_posix_time_zone badz(L"EST-5EDT01:00:00,J124/1:30,J370" ); |
153 | check(testname: "Exception not thrown: invalid date spec" , testcond: false); |
154 | }catch(boost::gregorian::bad_day_of_month& boff){ |
155 | std::string msg(boff.what()); |
156 | check(testname: "Exception caught: " +msg , testcond: true); |
157 | }catch(boost::gregorian::bad_month& boff){ |
158 | std::string msg(boff.what()); |
159 | check(testname: "Exception caught: " +msg , testcond: true); |
160 | }catch(...){ |
161 | check(testname: "Unexpected exception caught: " , testcond: false); |
162 | } |
163 | |
164 | std::cout << "\nTest some Central Europe specs" << std::endl; |
165 | |
166 | //Test a timezone spec on the positive side of the UTC line. |
167 | //This is the time for central europe which is one hour in front of UTC |
168 | //Note these Summer time transition rules aren't actually correct. |
169 | w_posix_time_zone cet_tz(L"CET+01:00:00EDT+01:00:00,M4.1.0/02:00:00,M10.5.0/02:00:00" ); |
170 | check(testname: "Has DST" , testcond: cet_tz.has_dst()); |
171 | check(testname: "UTC offset" , testcond: cet_tz.base_utc_offset() == hours(1)); |
172 | check(testname: "Abbrevs" , testcond: cet_tz.std_zone_abbrev() == std::wstring(L"CET" )); |
173 | // check("Abbrevs", nyc2.std_zone_abbrev() == std::wstring("EST")); |
174 | |
175 | std::cout << "\nTest some Central Austrialia UTC+8:30" << std::endl; |
176 | |
177 | //Test a timezone spec on the positive side of the UTC line. |
178 | //This is the time for central europe which is one hour in front of UTC |
179 | //Note these Summer time transition rules aren't actually correct. |
180 | w_posix_time_zone caus_tz(L"CAS+08:30:00CDT+01:00:00,M4.1.0/02:00:00,M10.5.0/02:00:00" ); |
181 | check(testname: "Has DST" , testcond: caus_tz.has_dst()); |
182 | check(testname: "UTC offset" , testcond: caus_tz.base_utc_offset() == hours(8)+minutes(30)); |
183 | check(testname: "Abbrevs" , testcond: caus_tz.std_zone_abbrev() == std::wstring(L"CAS" )); |
184 | // check("Abbrevs", nyc2.std_zone_abbrev() == std::wstring("EST")); |
185 | |
186 | { |
187 | /**** first/last of month Julian & non-Julian tests ****/ |
188 | // Mar-01 & Oct-31, count begins at 1 |
189 | std::wstring spec(L"FST+3FDT,J60,J304" ); |
190 | w_posix_time_zone fl_1(spec); |
191 | check(testname: "Julian First/last of month" , testcond: fl_1.dst_local_start_time(y: 2003) == |
192 | ptime(date(2003,Mar,1),hours(2))); |
193 | check(testname: "Julian First/last of month" , testcond: fl_1.dst_local_end_time(y: 2003) == |
194 | ptime(date(2003,Oct,31),hours(2))); |
195 | check(testname: "Julian First/last of month" , testcond: fl_1.dst_local_start_time(y: 2004) == |
196 | ptime(date(2004,Mar,1),hours(2))); |
197 | check(testname: "Julian First/last of month" , testcond: fl_1.dst_local_end_time(y: 2004) == |
198 | ptime(date(2004,Oct,31),hours(2))); |
199 | |
200 | // Mar-01 & Oct-31 Non-leap year, count begins at 0 |
201 | spec = L"FST+3FDT,59,304" ; // "304" is not a mistake here, see posix_time_zone docs |
202 | w_posix_time_zone fl_2(spec); |
203 | try{ |
204 | check(testname: "Non-Julian First/last of month" , testcond: fl_2.dst_local_start_time(y: 2003) == |
205 | ptime(date(2003,Mar,1),hours(2))); |
206 | }catch(std::exception& e){ |
207 | check(testname: "Expected exception caught for Non-Julian day of 59, in non-leap year (Feb-29)" , testcond: true); |
208 | } |
209 | check(testname: "Non-Julian First/last of month" , testcond: fl_2.dst_local_end_time(y: 2003) == |
210 | ptime(date(2003,Oct,31),hours(2))); |
211 | |
212 | // Mar-01 & Oct-31 leap year, count begins at 0 |
213 | spec = L"FST+3FDT,60,304" ; |
214 | w_posix_time_zone fl_3(spec); |
215 | check(testname: "Non-Julian First/last of month" , testcond: fl_3.dst_local_start_time(y: 2004) == |
216 | ptime(date(2004,Mar,1),hours(2))); |
217 | check(testname: "Non-Julian First/last of month" , testcond: fl_3.dst_local_end_time(y: 2004) == |
218 | ptime(date(2004,Oct,31),hours(2))); |
219 | } |
220 | |
221 | printTestStats(); |
222 | return 0; |
223 | } |
224 | |
225 | |