File Coverage

src/panda/time/timezone.cc
Criterion Covered Total %
statement 94 101 93.0
branch 65 112 58.0
condition n/a
subroutine n/a
pod n/a
total 159 213 74.6


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