File Coverage

src/panda/time/timezone.cc
Criterion Covered Total %
statement 87 94 92.5
branch 71 122 58.2
condition n/a
subroutine n/a
pod n/a
total 158 216 73.1


line stmt bran cond sub pod time code
1             #include "timezone.h"
2             #include "util.h"
3             #include "osdep.h"
4             #include "tzparse.h"
5             #include
6             #include
7             #include
8             #include
9             #include
10              
11             namespace panda { namespace time {
12              
13 26           static panda::unordered_string_map _tzcache;
14 26           static string _tzdir;
15 26           static TimezoneSP _localzone;
16              
17             static TimezoneSP _tzget (const string_view& zname);
18             static bool _virtual_zone (const string_view& zonename, Timezone* zone);
19             static void _virtual_fallback (Timezone* zone);
20              
21 38150           TimezoneSP tzlocal () {
22 38150 50         if (!_localzone) tzset();
    0          
23 38150           return _localzone;
24             }
25              
26 1369           TimezoneSP tzget (const string_view& zonename) {
27 1369 100         if (!zonename.length()) return tzlocal();
    50          
28 1368 50         auto it = _tzcache.find(zonename);
29 1368 100         if (it != _tzcache.cend()) return it->second;
30 2670 50         auto strname = string(zonename);
31 2602 50         auto zone = _tzget(strname);
32 1301 50         _tzcache.emplace(strname, zone);
33 1301           return zone;
34             }
35              
36 112           void tzset (const TimezoneSP& zn) {
37 224           TimezoneSP zone;
38 112 100         if (zn) zone = zn;
    50          
39             else {
40 3           const char* s = getenv("TZ");
41 3 100         string_view etzname = s ? s : "";
42 3 100         if (etzname.length()) zone = tzget(etzname);
    50          
43 3 50         else zone = _tzget("");
44             }
45 112 100         if (_localzone == zone) return;
46 101 100         if (_localzone) _localzone->is_local = false;
47 101 50         _localzone = zone;
48 112 100         _localzone->is_local = true;
49             }
50              
51 111           void tzset (const string_view& zonename) {
52 111 100         if (zonename.length()) tzset(tzget(zonename));
    50          
53 3 50         else tzset();
54 111           }
55              
56 2608 100         const string& tzdir () { return _tzdir ? _tzdir : tzsysdir(); }
57 54           const string& tzsysdir () { return ZONEDIR; }
58              
59 26           bool tzdir (const string& dir) {
60 26           _tzcache.clear();
61 26           _tzdir = dir;
62 26           return true;
63             }
64              
65 1302           static TimezoneSP _tzget (const string_view& zname) {
66 2604 50         auto zonename = string(zname);
67             //printf("ptime: tzget for zone %s\n", zonename);
68 1302 50         auto zone = new Timezone();
    50          
69 1302           zone->is_local = false;
70            
71 1302 100         if (!zonename.length()) {
72 1 50         zonename = tz_lzname();
    50          
73 1           zone->is_local = true;
74 1 50         assert(zonename.length());
75             }
76            
77 1302 50         if (zonename.length() > TZNAME_MAX) {
78             //fprintf(stderr, "ptime: tzrule too long\n");
79 0 0         _virtual_fallback(zone);
80 0           return zone;
81             }
82              
83 2604           string filename;
84 1302 50         if (zonename.front() == ':') {
    100          
85 1 50         filename = zonename.substr(1);
    50          
86 1 50         zone->name = zonename;
87             }
88             else {
89 2602 50         string dir = tzdir();
    50          
90 1301 50         if (!dir) {
91 0 0         fprintf(stderr, "ptime: tzget: this OS has no olson timezone files, you must explicitly set tzdir(DIR)\n");
92 0 0         _virtual_fallback(zone);
93 0           return zone;
94             }
95 1301 50         zone->name = zonename;
96 1301 50         filename = dir + '/' + zonename;
    50          
    50          
    50          
97             }
98            
99 2604 50         string content = readfile(filename);
100              
101 1302 100         if (!content) { // tz rule
102             //printf("ptime: tzget rule %s\n", zonename);
103 51 50         if (!_virtual_zone(zonename, zone)) {
    100          
104             //fprintf(stderr, "ptime: parsing rule '%s' failed\n", zonename);
105 29 50         _virtual_fallback(zone);
106 29           return zone;
107             }
108             }
109             else { // tz file
110             //printf("ptime: tzget file %s\n", filename.c_str());
111 1251 50         bool result = tzparse(content, zone);
112 1251 50         if (!result) {
113             //fprintf(stderr, "ptime: parsing file '%s' failed\n", filename.c_str());
114 0 0         _virtual_fallback(zone);
115 0           return zone;
116             }
117             }
118            
119 1273           return zone;
120             }
121              
122 29           static void _virtual_fallback (Timezone* zone) {
123             //fprintf(stderr, "ptime: fallback to '%s'\n", PTIME_GMT_FALLBACK);
124 29 50         assert(_virtual_zone(GMT_FALLBACK, zone) == true);
    50          
125 29           zone->name = GMT_FALLBACK;
126 29           zone->is_local = false;
127 29           }
128              
129 80           static bool _virtual_zone (const string_view& zonename, Timezone* zone) {
130             //printf("ptime: virtual zone %s\n", zonename);
131 80 100         if (!tzparse_rule(zonename, &zone->future)) return false;
132 51           zone->future.outer.offset = zone->future.outer.gmt_offset;
133 51           zone->future.inner.offset = zone->future.inner.gmt_offset;
134 51           zone->future.delta = zone->future.inner.offset - zone->future.outer.offset;
135 51           zone->future.max_offset = std::max(zone->future.outer.offset, zone->future.inner.offset);
136            
137 51           zone->leaps_cnt = 0;
138 51           zone->leaps = NULL;
139 51           zone->trans_cnt = 1;
140 51 50         zone->trans = new Timezone::Transition[zone->trans_cnt];
141 51           std::memset(zone->trans, 0, sizeof(Timezone::Transition));
142 51           zone->trans[0].start = EPOCH_NEGINF;
143 51           zone->trans[0].local_start = EPOCH_NEGINF;
144 51           zone->trans[0].local_lower = EPOCH_NEGINF;
145 51           zone->trans[0].local_upper = EPOCH_NEGINF;
146 51           zone->trans[0].leap_corr = 0;
147 51           zone->trans[0].leap_delta = 0;
148 51           zone->trans[0].leap_end = EPOCH_NEGINF;
149 51           zone->trans[0].leap_lend = EPOCH_NEGINF;
150 51           zone->ltrans = zone->trans[0];
151 51           return true;
152             }
153              
154 104 50         }}
    50