Commits

Kaya Kupferschmidt committed 3bc85d9

Initial timezone loader

  • Participants
  • Parent commits 580ab17

Comments (0)

Files changed (8)

File source/libs/magnum_core/conf/SConscript

-subdirs = ['locales', 'encodings']
+subdirs = ['locales', 'encodings','tzdata']
 SConscript(dirs=subdirs)

File source/libs/magnum_core/conf/tzdata/SConscript

+Import('Sources', 'installer')
+
+installer.Install(dir = '#/installed/conf/tzdata', source = 'zone.tab')
+installer.Install(dir = '#/installed/conf/tzdata', source = ['CET','CST6CDT','EET','EST','EST5EDT','GMT','GMT0','GMT-0','GMT+0','HST','MET','MST','MST7MDT','NZ','posixrules','PRC','PST8PDT','ROC','ROK','UCT','UTC','WET'])
+installer.Install(dir = '#/installed/conf/tzdata/Africa', source = Glob('Africa/*'))
+installer.Install(dir = '#/installed/conf/tzdata/Antarctica', source = Glob('Antarctica/*'))
+installer.Install(dir = '#/installed/conf/tzdata/Arctic', source = Glob('Arctic/*'))
+installer.Install(dir = '#/installed/conf/tzdata/Asia', source = Glob('Asia/*'))
+installer.Install(dir = '#/installed/conf/tzdata/Australia', source = Glob('Australia/*'))
+installer.Install(dir = '#/installed/conf/tzdata/Brazil', source = Glob('Brazil/*'))
+installer.Install(dir = '#/installed/conf/tzdata/Canada', source = Glob('Canada/*'))
+installer.Install(dir = '#/installed/conf/tzdata/Chile', source = Glob('Chile/*'))
+installer.Install(dir = '#/installed/conf/tzdata/Etc', source = Glob('Etc/*'))
+installer.Install(dir = '#/installed/conf/tzdata/Europe', source = Glob('Europe/*'))
+installer.Install(dir = '#/installed/conf/tzdata/Indian', source = Glob('Indian/*'))
+installer.Install(dir = '#/installed/conf/tzdata/Mexico', source = Glob('Mexico/*'))
+installer.Install(dir = '#/installed/conf/tzdata/Mideast', source = Glob('Mideast/*'))
+installer.Install(dir = '#/installed/conf/tzdata/Pacific', source = Glob('Pacific/*'))
+installer.Install(dir = '#/installed/conf/tzdata/SystemV', source = Glob('SystemV/*'))
+installer.Install(dir = '#/installed/conf/tzdata/US', source = Glob('US/*'))
+
+#installer.Install(dir = '#/installed/conf/tzdata/America', source = Glob('America/*'))
+#installer.Install(dir = '#/installed/conf/tzdata/posix', source = Glob('posix/*'))
+#installer.Install(dir = '#/installed/conf/tzdata/right', source = Glob('right/*'))

File source/libs/magnum_core/source/magnum/locale/TimeZone.cpp

 
 #include "magnum/system/RuntimeRegistrar.h"
 #include "magnum/util/props/Exception.h"
+#include "magnum/util/DateTime.h"
 #include "magnum/locale/Locale.h"
 #include "magnum/locale/Exception.h"
 #include "magnum/locale/spi/TimeZoneProvider.h"
 using magnum::object::Nil;
 using magnum::types::index_t;
 using magnum::object::NullPointerException;
+using magnum::util::DateTime;
 
 const TimeZone* m_SystemTimeZone = 0;
 const TimeZone* m_DefaultTimeZone = 0;
 }
 
 
+/*--------------------------------------------------------------------------*/
+/**
+ */
 const TimeZone* TimeZone::getTimeZone(const String& name)
 {
     // Look if we already loaded the desired time zone
 /*--------------------------------------------------------------------------*/
 /**
  */
+void TimeZone::insertZoneDefinition(const TimeZone::ZoneDefinition& def)
+{
+    m_ZoneDefinitions.insert(def);
+}
+
+
+/*--------------------------------------------------------------------------*/
+/**
+ */
+void TimeZone::insertZoneDefinition(const String& name, int offset, bool isDst)
+{
+    ZoneDefinition zd;
+    zd.name = name;
+    zd.offset = offset;
+    zd.tickOffset = DateTime::TicksPerSecond * offset;
+    zd.isDst = isDst;
+    m_ZoneDefinitions.insert(zd);
+}
+
+
+/*--------------------------------------------------------------------------*/
+/**
+ */
+void TimeZone::insertZoneEntry(const TimeZone::ZoneEntry& entry)
+{
+    m_ZoneEntries.insert(entry);
+}
+
+
+/*--------------------------------------------------------------------------*/
+/**
+ */
+void TimeZone::insertZoneEntry(int64 secsSince1970, int idx)
+{
+    ZoneEntry entry;
+    entry.idx = idx;
+    entry.secondsSince1970 = secsSince1970;
+    entry.ticksSince1601 = DateTime::posixTimeToTicks(secsSince1970);
+    m_ZoneEntries.insert(entry);
+}
+
+
+/*--------------------------------------------------------------------------*/
+/**
+ */
+void TimeZone::insertLeapSecondEntry(const TimeZone::LeapSecondEntry& entry)
+{
+    m_LeapSeconds.insert(entry);
+}
+
+
+/*--------------------------------------------------------------------------*/
+/**
+ */
+void TimeZone::insertLeapSecondEntry(int64 secsSince1970, int adjustment)
+{
+    LeapSecondEntry entry;
+    entry.secondsSince1970 = secsSince1970;
+    entry.ticksSince1601 = DateTime::posixTimeToTicks(secsSince1970);
+    entry.adjustment = adjustment;
+    entry.offset = adjustment;
+    m_LeapSeconds.insert(entry);
+}
+
+
+/*--------------------------------------------------------------------------*/
+/**
+ */
 void TimeZone::setDefaultTimeZone(const TimeZone* tz)
 {
     if (tz == 0)
 #endif
         m_SystemTimeZone = getTimeZone(tzName);
         if (!m_SystemTimeZone) {
-            //m_SystemTimeZone = CLocale::getInstance();
+            m_SystemTimeZone = new TimeZone(tzName);
         }
 
         // Add reference to system time zone

File source/libs/magnum_core/source/magnum/locale/TimeZone.h

 #define __MAGNUM_LOCALE_TIMEZONE_H
 
 #include "magnum/object/Object.h"
+#include "magnum/object/Array.h"
 
 #include "magnum/object/Object.inl"
+#include "magnum/object/Array.inl"
 
 
 namespace magnum { namespace locale {
 using magnum::object::Object;
+using magnum::object::Array;
 using magnum::types::String;
+using magnum::types::int64;
 
 class Locale;
 
 class MAGNUM_CORE_API TimeZone : public Object {
 OBJECT_METAINFO(TimeZone);
 public:
+    struct ZoneDefinition {
+        //! Name of zone entry
+        String name;
+        //! Offset from GMT in seconds
+        int offset;
+        //! Offset from GMT in ticks
+        int tickOffset;
+        //! True if daylight savings time
+        bool isDst;
+    };
+    struct LeapSecondEntry {
+        int64 secondsSince1970;
+        int64 ticksSince1601;
+        //! Number of seconds to add at the given date
+        int adjustment;
+        //! Total number of seconds to add since 1601
+        int offset;
+    };
+    struct ZoneEntry {
+        int64 secondsSince1970;
+        int64 ticksSince1601;
+        //! ZoneDefinition index
+        int idx;
+    };
+
+public:
     explicit TimeZone(const String& name);
     virtual ~TimeZone();
 
     String getDisplayName(bool daylight, const Locale* locale) const;
     String getDisplayName(const Locale* locale) const;
 
+    inline const Array<ZoneDefinition>& getZoneDefinitions() const
+        { return m_ZoneDefinitions; }
+    inline int getZoneDefinitionCount() const
+        { return (int)m_ZoneDefinitions.getSize(); }
+    inline const ZoneDefinition& getZoneDefinition(int idx) const
+        { return m_ZoneDefinitions[idx]; }
+    void insertZoneDefinition(const ZoneDefinition& def);
+    void insertZoneDefinition(const String& name, int offset, bool isDst);
+
+    inline const Array<ZoneEntry>& getZoneEntries() const
+        { return m_ZoneEntries; }
+    inline int getZoneEntryCount() const
+        { return (int)m_ZoneEntries.getSize(); }
+    inline const ZoneEntry& getZoneEntry(int idx) const
+        { return m_ZoneEntries[idx]; }
+    void insertZoneEntry(const ZoneEntry& entry);
+    void insertZoneEntry(int64 secsSince1970, int idx);
+
+    inline const Array<LeapSecondEntry> getLeapSecondEntries() const
+        { return m_LeapSeconds; }
+    inline int getLeapSecondEntryCount() const
+        { return (int)m_LeapSeconds.getSize(); }
+    inline const LeapSecondEntry& getLeapSecondEntry(int idx) const
+        { return m_LeapSeconds[idx]; }
+    void insertLeapSecondEntry(const LeapSecondEntry& entry);
+    void insertLeapSecondEntry(int64 secondsSince1970, int adjustment);
+
     static void setDefaultTimeZone(const TimeZone* );
     static void setDefaultTimeZone(const String& );
     static const TimeZone* getTimeZone(const String& );
 
 private:
     String m_Name;
+    Array<ZoneDefinition> m_ZoneDefinitions;
+    Array<LeapSecondEntry> m_LeapSeconds;
+    Array<ZoneEntry> m_ZoneEntries;
 };
 
 } }

File source/libs/magnum_core/source/magnum/locale/spi/TimeZoneProviderImpl.cpp

   Kaya Kupferschmidt  (k.kupferschmidt@dimajix.de)
 */
 
+#include "magnum/object/ObjectGuard.h"
+#include "magnum/system/Runtime.h"
+#include "magnum/io/DataInput.h"
+#include "magnum/filesystem/LocalFile.h"
+#include "magnum/filesystem/Path.h"
+#include "magnum/locale/Exception.h"
 #include "magnum/locale/spi/TimeZoneProviderImpl.h"
 
 
 namespace magnum { namespace locale { namespace spi {
+using magnum::object::Reference;
+using magnum::object::ObjectGuard;
+using magnum::io::InputStream;
+using magnum::io::DataInput;
+using magnum::filesystem::Path;
+using magnum::filesystem::File;
+using magnum::filesystem::LocalFile;
 
 
 /*--------------------------------------------------------------------------*/
 /*--------------------------------------------------------------------------*/
 /**
  */
+const TimeZone* TimeZoneProviderImpl::readZoneInfo(const String& name, InputStream* in)
+{
+    ObjectGuard<TimeZone> guard;
+    Reference<TimeZone> tz = new TimeZone(name);
+
+    // read header
+    DataInput ds(in);
+    ds.setEndianness(DataInput::MSB);
+    ds.skip(20);
+    int ttisgmtcnt = ds.readDword();
+    int ttisstdcnt = ds.readDword();
+    int leapcnt = ds.readDword();
+    int timecnt = ds.readDword();
+    int typecnt = ds.readDword();
+    int charcnt = ds.readDword();
+
+    // load DST transition data
+    Array<int> transTimes(timecnt);
+    for (int i = 0; i < timecnt; ++i)
+        transTimes[i] = ds.readDword();
+    Array<int> transTypes(timecnt);
+    for (int i = 0; i < timecnt; ++i)
+        transTypes[i] = ds.readByte();
+    for (int i = 0; i < timecnt; ++i)
+        tz->insertZoneEntry(transTimes[i], transTypes[i]);
+
+    // load TZ type data
+    Array<int> offset(typecnt);
+    Array<int> dst(typecnt);
+    Array<int> idx(typecnt);
+    for (int i = 0; i < typecnt; ++i) {
+        offset[i] = ds.readDword();
+        dst[i] = ds.readByte();
+        idx[i] = ds.readByte();
+    }
+
+    // Read array containing all zone names
+    Array<char> str(charcnt);
+    ds.read(str.getArray(), charcnt);
+
+    // Create zone entries
+    for (int i = 0; i < typecnt; ++i) {
+        // extract zone name
+        int pos = idx[i];
+        int end = pos;
+        while (str[end] != 0)
+            ++end;
+
+        String name(&str[pos], end - pos);
+        tz->insertZoneDefinition(name, offset[i], dst[i] != 0);
+    }
+
+    // load leap seconds table
+    for (; leapcnt > 0; --leapcnt) {
+        int secsSince1970 = ds.readDword();
+        int offset = ds.readDword();
+        tz->insertLeapSecondEntry(secsSince1970, offset);
+    }
+
+    return guard(tz);
+}
+
+
+/*--------------------------------------------------------------------------*/
+/**
+ */
 const TimeZone* TimeZoneProviderImpl::createTimeZone(const String& name)
 {
-    return new TimeZone(name);
+    Path confDir = magnum::system::Runtime::getSystemDirectory();
+    confDir /= "conf";
+    confDir /= "tzdata";
+
+    Path tzFile = confDir / name;
+
+    try {
+        Reference<File> file = LocalFile::open(tzFile);
+        return readZoneInfo(name, file->getInputStream());
+    }
+    catch(...) {
+        return 0;
+    }
 }
 
 } } }

File source/libs/magnum_core/source/magnum/locale/spi/TimeZoneProviderImpl.h

 #ifndef __MAGNUM_LOCALE_SPI_TIMEZONEPROVIDERIMPL_H
 #define __MAGNUM_LOCALE_SPI_TIMEZONEPROVIDERIMPL_H
 
+#include "magnum/io/InputStream.h"
 #include "magnum/locale/spi/TimeZoneProvider.h"
 
 
 namespace magnum { namespace locale { namespace spi {
+using magnum::io::InputStream;
 
 
 /*--------------------------------------------------------------------------*/
     virtual ~TimeZoneProviderImpl();
 
     virtual const TimeZone* createTimeZone(const String& );
+
+private:
+    const TimeZone* readZoneInfo(const String& name, InputStream* in);
 };
 
 } } }

File source/libs/magnum_core/source/magnum/util/DateTime.cpp

     return (m_Date != other.m_Date || m_Time != other.m_Time);
 }
 
+
+/*--------------------------------------------------------------------------*/
+/** Convert standard unix time (number of seconds since 1.1.1970) to
+ * ticks since 1.1.1601
+ */
+int64 DateTime::posixTimeToTicks(int64 ptime)
+{
+    return ptime * TicksPerSecond + UnixEpoch;
+}
+
+
+/*--------------------------------------------------------------------------*/
+/** Convert ticks since 1.1.1601 to unix time.
+ */
+int64 DateTime::ticksToPosixTime(int64 ticks)
+{
+    return (ticks - UnixEpoch) / TicksPerSecond;
+}
+
 } }

File source/libs/magnum_core/source/magnum/util/DateTime.h

     static const int64 TicksPerMinute = Time::TicksPerMinute;
     static const int64 TicksPerHour = Time::TicksPerHour;
     static const int64 TicksPerDay = Time::TicksPerDay;
+    static const int64 UnixEpoch = 2440587LL * TicksPerDay;
 
     static const DateTime Invalid;
 
 	inline DateTime& operator-=(const Weeks& time)
         { addDays(-time.getTotalDays()); return *this; }
 
+    static int64 posixTimeToTicks(int64 ptime);
+    static int64 ticksToPosixTime(int64 );
+
 private:
     void setAbsolute(int julianDay, int64 ticks);