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
18int 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

source code of boost/libs/date_time/test/local_time/testwposix_time_zone.cpp