22 #include <ktimezones.h>
26 #include <kstringhandler.h>
27 #include <tdetempfile.h>
29 #include <tqdatetime.h>
32 #include <tqstringlist.h>
33 #include <tqtextstream.h>
41 #define UTC_ZONE "UTC"
51 class AbbreviationsMatch :
55 AbbreviationsMatch(
const TQString &stdZone,
const TQString &dstZone =
"")
64 m_foundDst = m_dstZone.isEmpty();
69 return (m_foundStd && m_foundDst);
80 if (m_stdZone == value)
84 if (m_dstZone == value)
116 OffsetFind(
unsigned dateTime)
118 m_dateTime = dateTime;
123 m_transitionTimeIndex = 0;
124 m_localTimeIndex = -1;
141 TQString abbreviation()
148 int m_transitionTimeIndex;
149 int m_localTimeIndex;
157 if (transitionTime <= m_dateTime)
160 m_transitionTimeIndex = index;
166 if (index == m_transitionTimeIndex)
169 m_localTimeIndex = localTimeIndex;
173 virtual void gotLocalTime(
int index,
int gmtOff,
bool isDst,
unsigned abbrInd)
175 if (index == m_localTimeIndex)
180 m_abbrIndex = abbrInd;
186 if (index == m_abbrIndex)
197 return (latitude >= -90.0) && (latitude <= 90.0);
202 return (longitude >= -180.0) && (longitude <= 180.0);
207 const TQString &countryCode,
float latitude,
float longitude,
208 const TQString &comment) :
211 m_countryCode(countryCode),
212 m_latitude(latitude),
213 m_longitude(longitude),
218 if (m_latitude * m_latitude > 90 * 90)
220 if (m_longitude * m_longitude > 180 * 180)
224 KTimezone::~KTimezone()
237 char *originalZone = ::getenv(
"TZ");
240 ::setenv(
"TZ", m_name.utf8(), 1);
242 unsigned utc = dateTime.toTime_t();
245 ::setenv(
"TZ", newZone->
name().utf8(), 1);
247 TQDateTime remoteTime;
248 remoteTime.setTime_t(utc, Qt::LocalTime);
257 ::setenv(
"TZ", originalZone, 1);
265 return m_countryCode;
285 char *originalZone = ::getenv(
"TZ");
288 TQDateTime basisTime = TQDateTime::currentDateTime(basisSpec);
291 ::setenv(
"TZ", m_name.utf8(), 1);
293 TQDateTime remoteTime = TQDateTime::currentDateTime(Qt::LocalTime);
294 int offset = remoteTime.secsTo(basisTime);
303 ::setenv(
"TZ", originalZone, 1);
311 OffsetFind finder(dateTime.toTime_t());
315 result = finder.offset();
323 bool result = m_db->
parse(m_name, dataReceiver);
328 KTimezones::KTimezones() :
335 m_UTC =
new KTimezone(
new DummySource(), UTC_ZONE);
339 KTimezones::~KTimezones()
347 for (ZoneMap::ConstIterator it = m_zones->begin(); it != m_zones->end(); ++it)
357 m_zones->insert(zone->
name(),
zone);
365 m_zones =
new ZoneMap();
374 m_zoneinfoDir =
"/usr/share/zoneinfo";
375 f.setName(m_zoneinfoDir +
"/zone.tab");
376 if (!f.open(IO_ReadOnly))
378 kdDebug() <<
"Can't open " << f.name() <<
endl;
379 m_zoneinfoDir =
"/usr/lib/zoneinfo";
380 f.setName(m_zoneinfoDir +
"/zone.tab");
381 if (!f.open(IO_ReadOnly))
383 kdDebug() <<
"Can't open " << f.name() <<
endl;
384 m_zoneinfoDir = ::getenv(
"TZDIR");
385 f.setName(m_zoneinfoDir +
"/zone.tab");
386 if (m_zoneinfoDir.isEmpty() || !f.open(IO_ReadOnly))
388 kdDebug() <<
"Can't open " << f.name() <<
endl;
396 m_zoneinfoDir =
"/usr/share/lib/zoneinfo";
399 reader <<
"/bin/grep" <<
"-h" <<
"^Zone" << m_zoneinfoDir <<
"/src/*" << temp.
name() <<
"|" <<
400 "/bin/awk" <<
"'{print \"??\\t+9999+99999\\t\" $2}'";
404 f.setName(temp.
name());
405 if (!temp.
status() || !f.open(IO_ReadOnly))
407 kdDebug() <<
"Can't open " << f.name() <<
endl;
415 TQTextStream str(&f);
416 TQRegExp lineSeparator(
"[ \t]");
417 TQRegExp ordinateSeparator(
"[+-]");
421 TQString line = str.readLine();
422 if (line.isEmpty() ||
'#' == line[0])
425 if (tokens.count() < 3)
427 kdError() <<
"invalid record: " << line <<
endl;
433 if (ordinates.count() < 2)
435 kdError() <<
"invalid coordinates: " << tokens[1] <<
endl;
439 float latitude = convertCoordinate(ordinates[1]);
440 float longitude = convertCoordinate(ordinates[2]);
443 if (tokens[0] ==
"??")
445 KTimezone *timezone =
new KTimezone(db, tokens[2], tokens[0], latitude, longitude, tokens[3]);
455 float KTimezones::convertCoordinate(
const TQString &coordinate)
457 int value = coordinate.toInt();
462 if (coordinate.length() > 11)
464 degrees = value / 10000;
465 value -= degrees * 10000;
466 minutes = value / 100;
467 value -= minutes * 100;
472 degrees = value / 100;
473 value -= degrees * 100;
476 value = degrees * 3600 + minutes * 60 + seconds;
477 return value / 3600.0;
485 char *envZone = ::getenv(
"TZ");
488 if (envZone[0] ==
'\0')
493 if (envZone[0] ==
':')
497 local =
zone(envZone);
504 f.setName(
"/etc/localtime");
505 if (f.open(IO_ReadOnly))
510 context.
update(TQT_TQIODEVICE_OBJECT(f));
511 TQIODevice::Offset referenceSize = f.size();
512 TQString referenceMd5Sum = context.
hexDigest();
514 if (!m_zoneinfoDir.isEmpty())
517 for (ZoneMap::Iterator it = m_zones->begin(); it != m_zones->end(); ++it)
520 f.setName(m_zoneinfoDir +
'/' + zone->
name());
521 if (f.open(IO_ReadOnly))
523 TQIODevice::Offset candidateSize = f.size();
524 TQString candidateMd5Sum;
525 if (candidateSize == referenceSize)
529 context.
update(TQT_TQIODEVICE_OBJECT(f));
533 if (candidateMd5Sum == referenceMd5Sum)
548 f.setName(
"/etc/timezone");
549 if (!f.open(IO_ReadOnly))
551 kdDebug() <<
"Can't open " << f.name() <<
endl;
554 f.setName(
"/etc/default/init");
555 if (!f.open(IO_ReadOnly))
557 kdDebug() <<
"Can't open " << f.name() <<
endl;
562 ts.setEncoding(TQTextStream::Latin1);
567 fileZone = ts.readLine();
568 if (fileZone.startsWith(
"TZ="))
570 fileZone = fileZone.mid(3);
573 local =
zone(fileZone);
582 ts.setEncoding(TQTextStream::Latin1);
587 fileZone = ts.readLine();
590 local =
zone(fileZone);
600 if (!m_zoneinfoDir.isEmpty())
603 AbbreviationsMatch matcher(tzname[0], tzname[1]);
604 int bestOffset = INT_MAX;
605 for (ZoneMap::Iterator it = m_zones->begin(); it != m_zones->end(); ++it)
608 int candidateOffset = QABS(zone->
offset(Qt::LocalTime));
609 if (zone->
parse(matcher) && matcher.test() && (candidateOffset < bestOffset))
612 bestOffset = candidateOffset;
626 ZoneMap::ConstIterator it = m_zones->find(name);
627 if (it != m_zones->end())
634 KTimezoneDetails::KTimezoneDetails()
638 KTimezoneDetails::~KTimezoneDetails()
646 unsigned,
unsigned,
unsigned,
647 unsigned,
unsigned,
unsigned)
674 KTimezoneSource::KTimezoneSource(
const TQString &db) :
679 KTimezoneSource::~KTimezoneSource()
690 TQFile f(m_db +
'/' + zone);
691 if (!f.open(IO_ReadOnly))
693 kdError() <<
"Cannot open " << f.name() <<
endl;
698 TQ_UINT8 T, z, i_, f_;
701 TQ_UINT32 ttisgmtcnt;
702 TQ_UINT32 ttisstdcnt;
708 TQ_UINT32 transitionTime;
709 TQ_UINT8 localTimeIndex;
717 TQ_UINT32 leapSeconds;
721 TQDataStream str(&f);
722 str >> T >> z >> i_ >> f_;
725 for (i = 0; i < 4; i++)
726 str >> tzh.ttisgmtcnt;
727 str >> tzh.ttisgmtcnt >> tzh.ttisstdcnt >> tzh.leapcnt >> tzh.timecnt >> tzh.typecnt >> tzh.charcnt;
730 dataReceiver.
gotHeader(tzh.ttisgmtcnt, tzh.ttisstdcnt, tzh.leapcnt, tzh.timecnt, tzh.typecnt, tzh.charcnt);
731 for (i = 0; i < tzh.timecnt; i++)
733 str >> transitionTime;
736 for (i = 0; i < tzh.timecnt; i++)
739 str >> localTimeIndex;
742 for (i = 0; i < tzh.typecnt; i++)
744 str >> tt.gmtoff >> tt.isdst >> tt.abbrind;
746 dataReceiver.
gotLocalTime(i, tt.gmtoff, (tt.isdst != 0), tt.abbrind);
750 if (tzh.charcnt > 64)
752 kdError() <<
"excessive length for timezone abbreviations: " << tzh.charcnt <<
endl;
755 TQByteArray array(tzh.charcnt);
756 str.readRawBytes(array.data(), array.size());
757 char *abbrs = array.data();
758 if (abbrs[tzh.charcnt - 1] != 0)
761 kdError() <<
"timezone abbreviations not terminated: " << abbrs[tzh.charcnt - 1] <<
endl;
765 while (abbr < abbrs + tzh.charcnt)
769 abbr += strlen(abbr) + 1;
771 for (i = 0; i < tzh.leapcnt; i++)
773 str >> leapTime >> leapSeconds;
777 for (i = 0; i < tzh.ttisstdcnt; i++)
783 for (i = 0; i < tzh.ttisgmtcnt; i++)
787 dataReceiver.
gotIsUTC(i, (isUTC != 0));