API: lib: renamed record parser class from Timezone to TimeZone
[barry/progweb.git] / src / r_timezone.cc
blobd69021e2f053b0022e8b99cdba5e6addb1220b82
1 ///
2 /// \file r_timezone.cc
3 /// Record parsing class for the timezone database.
4 ///
6 /*
7 Copyright (C) 2005-2012, Net Direct Inc. (http://www.netdirect.ca/)
8 Copyright (C) 2008, Brian Edginton
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License in the COPYING file at the
20 root directory of this project for more details.
23 #include "r_timezone.h"
24 #include "record-internal.h"
25 #include "protostructs.h"
26 #include "data.h"
27 #include "time.h"
28 #include "iconv.h"
29 #include "debug.h"
30 #include <iostream>
31 #include <sstream>
32 #include <iomanip>
33 #include "ios_state.h"
35 using namespace std;
36 using namespace Barry::Protocol;
38 namespace Barry
41 ///////////////////////////////////////////////////////////////////////////////
42 // TimeZone Class
44 // TimeZone Field Codes
45 #define TZFC_INDEX 0x01
46 #define TZFC_NAME 0x02
47 #define TZFC_OFFSET 0x03
48 #define TZFC_DST 0x04
49 #define TZFC_STARTMONTH 0x06
50 #define TZFC_ENDMONTH 0x0B
51 #define TZFC_TZTYPE 0x64
53 #define TZFC_END 0xffff
55 static FieldLink<TimeZone> TimeZoneFieldLinks[] = {
56 { TZFC_NAME, "Name", 0, 0, &TimeZone::Name, 0, 0, 0, 0, true },
57 { TZFC_END, "End of List", 0, 0, 0, 0, 0, 0, 0, false },
60 TimeZone::TimeZone()
62 Clear();
65 TimeZone::TimeZone(int utc_offset)
67 Clear();
69 UTCOffset = utc_offset;
72 TimeZone::TimeZone(int hours, int minutes)
74 Clear();
76 // make sure that minutes are always positive, for our logic
77 if( minutes < 0 )
78 minutes = -minutes;
80 // calculate offset in total minutes
81 UTCOffset = hours * 60;
82 if( hours < 0 )
83 UTCOffset -= minutes;
84 else
85 UTCOffset += minutes;
88 TimeZone::~TimeZone()
92 const unsigned char* TimeZone::ParseField(const unsigned char *begin,
93 const unsigned char *end,
94 const IConverter *ic)
96 const CommonField *field = (const CommonField *) begin;
98 // advance and check size
99 begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size);
100 if( begin > end ) // if begin==end, we are ok
101 return begin;
103 if( !btohs(field->size) ) // if field has no size, something's up
104 return begin;
106 if( field->type == TZFC_TZTYPE ) {
107 if( ( TZType = field->u.uint32 ) != 1 ) {
108 throw Error("TimeZone::ParseField: TimeZone Type is not valid");
110 return begin;
113 // cycle through the type table
114 for( FieldLink<TimeZone> *b = TimeZoneFieldLinks;
115 b->type != TZFC_END;
116 b++ )
118 if( b->type == field->type ) {
119 if( b->strMember ) {
120 std::string &s = this->*(b->strMember);
121 s = ParseFieldString(field);
122 if( b->iconvNeeded && ic )
123 s = ic->FromBB(s);
124 return begin; // done!
129 switch( field->type )
131 case TZFC_INDEX:
132 Index = btohl(field->u.uint32);
133 return begin;
135 case TZFC_OFFSET:
136 UTCOffset = btohs(field->u.int16);
137 return begin;
139 case TZFC_DST:
140 DSTOffset = btohl(field->u.uint32);
141 if (DSTOffset) {
142 UseDST = true;
144 return begin;
146 case TZFC_STARTMONTH:
147 StartMonth = btohl(field->u.uint32);
148 return begin;
150 case TZFC_ENDMONTH:
151 EndMonth = btohl(field->u.uint32);
152 return begin;
155 // if still not handled, add to the Unknowns list
156 UnknownField uf;
157 uf.type = field->type;
158 uf.data.assign((const char*)field->u.raw, btohs(field->size));
159 Unknowns.push_back(uf);
161 // return new pointer for next field
162 return begin;
165 void TimeZone::ParseHeader(const Data &data, size_t &offset)
167 // no header in Task records
170 void TimeZone::ParseFields(const Data &data, size_t &offset, const IConverter *ic)
172 const unsigned char *finish = ParseCommonFields(*this,
173 data.GetData() + offset, data.GetData() + data.GetSize(), ic);
174 offset += finish - (data.GetData() + offset);
177 void TimeZone::Validate() const
181 void TimeZone::BuildHeader(Data &data, size_t &offset) const
183 // not yet implemented
186 void TimeZone::BuildFields(Data &data, size_t &offset, const IConverter *ic) const
188 // not yet implemented
191 void TimeZone::Clear()
193 RecType = GetDefaultRecType();
194 RecordId = 0;
196 Name.clear();
197 Index = 0;
198 UTCOffset = 0;
200 UseDST = false;
201 DSTOffset = 0;
202 StartMonth = -1;
203 EndMonth = -1;
205 TZType = 0;
207 Unknowns.clear();
210 const FieldHandle<TimeZone>::ListT& TimeZone::GetFieldHandles()
212 static FieldHandle<TimeZone>::ListT fhv;
214 if( fhv.size() )
215 return fhv;
217 #undef CONTAINER_OBJECT_NAME
218 #define CONTAINER_OBJECT_NAME fhv
220 #undef RECORD_CLASS_NAME
221 #define RECORD_CLASS_NAME TimeZone
223 FHP(RecType, "Record Type Code");
224 FHP(RecordId, "Unique Record ID");
226 FHD(Name, "TimeZone Name", TZFC_NAME, true);
227 FHD(Index, "Index", TZFC_INDEX, false);
228 FHD(UTCOffset, "TimeZone Offset in Minutes", TZFC_OFFSET, false);
229 FHD(UseDST, "Use DST?", TZFC_DST, false);
230 FHD(DSTOffset, "DST Offset", TZFC_DST, false);
231 FHD(StartMonth, "Start Month", TZFC_STARTMONTH, false);
232 FHD(EndMonth, "End Month", TZFC_ENDMONTH, false);
233 FHD(TZType, "TimeZone Type", TZFC_TZTYPE, false);
235 FHP(Unknowns, "Unknown Fields");
237 return fhv;
240 std::string TimeZone::GetDescription() const
242 ostringstream oss;
243 oss << Name << " (" << dec << (UTCOffset / 60.0) << ")";
244 return oss.str();
247 void TimeZone::Dump(std::ostream &os) const
249 ios_format_state state(os);
251 static const char *month[] = {
252 "Jan", "Feb", "Mar", "Apr", "May",
253 "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
256 os << "TimeZone entry: 0x" << setbase(16) << RecordId
257 << " (" << (unsigned int)RecType << ")\n";
259 // cycle through the type table
260 for( const FieldLink<TimeZone> *b = TimeZoneFieldLinks;
261 b->type != TZFC_END;
262 b++ )
264 if( b->strMember ) {
265 const std::string &s = this->*(b->strMember);
266 if( s.size() )
267 os << " " << b->name << ": " << s << "\n";
271 int hours, minutes;
272 Split(&hours, &minutes);
274 os << " Desc: " << GetDescription() << "\n";
275 os << " Index: 0x" <<setw(2) << Index << "\n";
276 os << " Type: 0x" <<setw(2) << (unsigned int)TZType << "\n";
277 os << " Offset: " << setbase(10) << UTCOffset << " minutes ("
278 << dec << (UTCOffset / 60.0) << ")\n";
279 os << " Split Offset: hours: "
280 << dec << hours << ", minutes: " << minutes << "\n";
281 os << " Sample TZ: " << GetTz("E") << "\n";
282 os << " Use DST: " << (UseDST ? "true" : "false") << "\n";
283 if (UseDST) {
284 os << " DST Offset: " << setbase(10) << DSTOffset << "\n";
285 if ((StartMonth > 0) && (StartMonth < 11))
286 os << "Start Month: " << month[StartMonth] << "\n";
287 else
288 os << "Start Month: unknown (" << setbase(10) << StartMonth << ")\n";
289 if ((EndMonth > 0) && (EndMonth < 11))
290 os << " End Month: " << month[EndMonth] << "\n";
291 else
292 os << " End Month: unknown (" << setbase(10) << EndMonth << ")\n";
295 os << Unknowns;
296 os << "\n\n";
300 void TimeZone::Split(int *hours, int *minutes) const
302 *hours = UTCOffset / 60;
303 *minutes = UTCOffset % 60;
304 if( *minutes < 0 )
305 *minutes = -*minutes;
308 void TimeZone::SplitAbsolute(bool *west,
309 unsigned int *hours,
310 unsigned int *minutes) const
312 int tmphours, tmpminutes;
313 Split(&tmphours, &tmpminutes);
315 if( tmphours < 0 ) {
316 *west = true;
317 tmphours = -tmphours;
319 else {
320 *west = false;
323 *hours = tmphours;
324 *minutes = tmpminutes;
327 std::string TimeZone::GetTz(const std::string &prefix) const
329 int hours, minutes;
330 Split(&hours, &minutes);
332 // TZ variable uses positive for west, and negative for east,
333 // so swap the hour value. Minutes is always positive for
334 // our purposes, so leave it alone.
335 hours = -hours;
337 // standard time first
338 ostringstream oss;
339 oss << prefix << "ST"
340 << hours << ":"
341 << setfill('0') << setw(2) << minutes
342 << ":00";
344 // daylight saving time next, if available
345 if( UseDST ) {
346 TimeZone dst(UTCOffset + DSTOffset);
348 dst.Split(&hours, &minutes);
350 // swap again for TZ semantics...
351 hours = -hours;
353 oss << prefix << "DT"
354 << hours << ":"
355 << setfill('0') << setw(2) << minutes
356 << ":00";
358 // assume second Sunday of start month to first Sunday of
359 // end month, since we don't have enough data to be more
360 // precise
361 oss << ",M" << (StartMonth + 1) << ".2.0";
362 oss << ",M" << (EndMonth + 1) << ".1.0";
365 return oss.str();
368 } // namespace Barry