1 #include "date/tz.h"
2 #include <iostream>
3 
4 void
test_info(const date::time_zone * zone,const date::sys_info & info)5 test_info(const date::time_zone* zone, const date::sys_info& info)
6 {
7     using namespace date;
8     using namespace std::chrono;
9     auto begin = info.begin;
10     auto end = info.end - microseconds{1};
11     auto mid = begin + (end - begin) /2;
12     using sys_microseconds = sys_time<microseconds>;
13     using zoned_microseconds = zoned_time<microseconds>;
14     zoned_microseconds local{zone};
15 
16     if (begin > sys_days{jan/1/1700})
17     {
18         auto prev_local = local;
19         local = begin;
20         prev_local = begin - seconds{1};
21         auto slocal = local.get_local_time();
22         auto plocal = prev_local.get_local_time();
23         if (plocal < slocal - seconds{1})
24         {
25             assert(sys_microseconds{local} == begin);
26             try
27             {
28                 local = plocal + (slocal - seconds{1} - plocal) / 2;
29                 assert(false);
30             }
31             catch (const nonexistent_local_time&)
32             {
33             }
34         }
35         else if (plocal > slocal - seconds{1})
36         {
37             try
38             {
39                 local = slocal - seconds{1} + (plocal - (slocal - seconds{1})) / 2;
40                 assert(false);
41             }
42             catch (const ambiguous_local_time&)
43             {
44             }
45         }
46     }
47 
48     local = mid;
49     assert(sys_microseconds{local} == mid);
50 
51     if (end < sys_days{jan/1/3000})
52     {
53         local = end;
54         auto next_local = local;
55         next_local = info.end;
56         auto slocal = local.get_local_time();
57         auto nlocal = next_local.get_local_time();
58         if (nlocal < slocal + microseconds{1})
59         {
60             try
61             {
62                 local = nlocal + (slocal + microseconds{1} - nlocal) / 2;
63                 assert(false);
64             }
65             catch (const ambiguous_local_time&)
66             {
67             }
68         }
69         else if (nlocal > slocal + microseconds{1})
70         {
71             assert(sys_microseconds{local} == end);
72             try
73             {
74                 local = slocal + microseconds{1} +
75                         (nlocal - (slocal + microseconds{1})) / 2;
76                 assert(false);
77             }
78             catch (const nonexistent_local_time&)
79             {
80             }
81         }
82     }
83 }
84 
85 void
tzmain()86 tzmain()
87 {
88     using namespace date;
89     using namespace std::chrono;
90     auto& db = get_tzdb();
91     std::vector<std::string> names;
92 #if USE_OS_TZDB
93     names.reserve(db.zones.size());
94     for (auto& zone : db.zones)
95         names.push_back(zone.name());
96 #else  // !USE_OS_TZDB
97     names.reserve(db.zones.size() + db.links.size());
98     for (auto& zone : db.zones)
99         names.push_back(zone.name());
100     for (auto& link : db.links)
101         names.push_back(link.name());
102     std::sort(names.begin(), names.end());
103 #endif  // !USE_OS_TZDB
104     std::cout << db.version << "\n\n";
105     for (auto const& name : names)
106     {
107         std::cout << name << '\n';
108         auto z = locate_zone(name);
109         auto begin = sys_days(jan/1/year::min()) + seconds{0};
110         auto end   = sys_days(jan/1/2035) + seconds{0};
111         auto info = z->get_info(begin);
112         std::cout << "Initially:           ";
113         if (info.offset >= seconds{0})
114             std::cout << '+';
115         std::cout << make_time(info.offset);
116         if (info.save == minutes{0})
117             std::cout << " standard ";
118         else
119             std::cout << " daylight ";
120         std::cout << info.abbrev << '\n';
121         test_info(z, info);
122         auto prev_offset = info.offset;
123         auto prev_abbrev = info.abbrev;
124         auto prev_save = info.save;
125         for (begin = info.end; begin < end; begin = info.end)
126         {
127             info = z->get_info(begin);
128             test_info(z, info);
129             if (info.offset == prev_offset && info.abbrev == prev_abbrev &&
130                     info.save == prev_save)
131                 continue;
132             auto dp = floor<days>(begin);
133             auto ymd = year_month_day(dp);
134             auto time = make_time(begin - dp);
135             std::cout << ymd << ' ' << time << "Z ";
136             if (info.offset >= seconds{0})
137                 std::cout << '+';
138             std::cout << make_time(info.offset);
139             if (info.save == minutes{0})
140                 std::cout << " standard ";
141             else
142                 std::cout << " daylight ";
143             std::cout << info.abbrev << '\n';
144             prev_offset = info.offset;
145             prev_abbrev = info.abbrev;
146             prev_save = info.save;
147         }
148         std::cout << '\n';
149     }
150 }
151 
152 int
main()153 main()
154 {
155     try
156     {
157         tzmain();
158     }
159     catch(const std::exception& ex)
160     {
161         std::cout << "An exception occured: " << ex.what() << std::endl;
162         return EXIT_FAILURE;
163     }
164     return EXIT_SUCCESS;
165 }
166