Commits

Kaya Kupferschmidt  committed 2167fbc

Added inverse lookups for TimeZones

  • Participants
  • Parent commits 7094e24
  • Branches kaya_001

Comments (0)

Files changed (10)

File misc/vc9/Magnum.ncb

Binary file modified.

File misc/vc9/Magnum.suo

Binary file modified.

File misc/vc9/Test_DateTime.vcproj

+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9,00"
+	Name="Test_DateTime"
+	ProjectGUID="{1AA3C16E-021B-4B36-A028-6A88127EB60F}"
+	Keyword="MakeFileProj"
+	TargetFrameworkVersion="131072"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="Debug"
+			ConfigurationType="0"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			>
+			<Tool
+				Name="VCNMakeTool"
+				BuildCommandLine=""
+				ReBuildCommandLine=""
+				CleanCommandLine=""
+				Output="Test_DateTime.exe"
+				PreprocessorDefinitions=""
+				IncludeSearchPath=""
+				ForcedIncludes=""
+				AssemblySearchPath=""
+				ForcedUsingAssemblies=""
+				CompileAsManaged=""
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="Release"
+			ConfigurationType="0"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			>
+			<Tool
+				Name="VCNMakeTool"
+				BuildCommandLine=""
+				ReBuildCommandLine=""
+				CleanCommandLine=""
+				Output="Test_DateTime.exe"
+				PreprocessorDefinitions=""
+				IncludeSearchPath=""
+				ForcedIncludes=""
+				AssemblySearchPath=""
+				ForcedUsingAssemblies=""
+				CompileAsManaged=""
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+	</Files>
+</VisualStudioProject>

File source/libs/magnum_core/source/magnum/datetime/SimpleTimeZone.cpp

     }
 
     int64 time = cdate.getTotalSecondsSince1970() + timeOfDay;
-    int64 start = getStart(cdate, year);
-    int64 end = getEnd(cdate, year);
+    int64 start = getTransition(year, m_StartRule);
+    int64 end = getTransition(year, m_EndRule);
     int offset = m_RawOffset;
     if (start <= end) {
         if (time >= start && time < end) {
     }
     else {
         if (time < end) {
-            // TODO: support Gregorian cutover. The previous year
-            // may be in the other calendar system.
-            start = getStart(cdate, year - 1);
+            // support Gregorian cutover. The previous year may be in the other calendar system.
+            start = getTransition(year == 1 ? -1 : year-1, m_StartRule);
             if (time >= start) {
                 offset += m_DstSaving;
             }
         }
         else if (time >= start) {
-            // TODO: support Gregorian cutover. The next year
-            // may be in the other calendar system.
-            end = getEnd(cdate, year + 1);
+            // support Gregorian cutover. The next year may be in the other calendar system.
+            end = getTransition(year == -1 ? 1 : year + 1, m_EndRule);
             if (time < end) {
                 offset += m_DstSaving;
             }
 }
 
 
-int64 SimpleTimeZone::getStart(const Date& cdate, int year) const
+int64 SimpleTimeZone::getTransition(int year, const SimpleTimeZone::Rule& rule) const
 {
-    return getTransition(cdate, year, m_StartRule);
-}
-
-int64 SimpleTimeZone::getEnd(const Date& cdate, int year) const
-{
-    return getTransition(cdate, year, m_EndRule);
-}
-
-int64 SimpleTimeZone::getTransition(const Date& cdate, int year, const SimpleTimeZone::Rule& rule) const
-{
-    Date date(cdate);
-    date.setYear(year);
-    date.setMonth((Date::Month)rule.month);
+    Date date(year, rule.month, 1);
     switch (rule.mode) {
         case DOM_MODE:
             date.setDayOfMonth(rule.dom);
 }
 
 
-int SimpleTimeZone::getOffsetFromLocal(Date::Era era, int year, int month, int day, int dow, int time) const
+/*--------------------------------------------------------------------------*/
+/**
+ */
+int SimpleTimeZone::getOffsetFromLocal(Date::Era era, int year, int month, int day, int dow, int timeOfDay) const
 {
     // No STD / DST time?
     if (m_DstOffset == m_RawOffset)
         return -m_RawOffset;
     }
 
-    return 0;
+    int64 time = cdate.getTotalSecondsSince1970() + timeOfDay;
+    int64 start = getTransition(year, m_StartRule) + m_DstOffset;
+    int64 end = getTransition(year, m_EndRule) + m_RawOffset;
+    int offset = -m_RawOffset;
+    if (start <= end) {
+        if (time >= start && time < end) {
+            offset -= m_DstSaving;
+        }
+    }
+    else {
+        if (time < end) {
+            // support Gregorian cutover. The previous year may be in the other calendar system.
+            start = getTransition(year == 1 ? -1 : year - 1, m_StartRule) + m_DstOffset;
+            if (time >= start) {
+                offset -= m_DstSaving;
+            }
+        }
+        else if (time >= start) {
+            // support Gregorian cutover. The next year may be in the other calendar system.
+            end = getTransition(year == -1 ? 1 : year + 1, m_EndRule) + m_RawOffset;
+            if (time < end) {
+                offset -= m_DstSaving;
+            }
+        }
+    }
+    return offset;
 }
 
 

File source/libs/magnum_core/source/magnum/datetime/SimpleTimeZone.h

         RuleType mode;
     };
 
-    int64 getStart(const Date& cdate, int year) const;
-    int64 getEnd(const Date& cdate, int year) const;
-    int64 getTransition(const Date& cdate, int year, const SimpleTimeZone::Rule& rule) const;
+    int64 getTransition(int year, const SimpleTimeZone::Rule& rule) const;
 
     static int parseTime(const StringRef& );
     static void parseDate(const StringRef& date, Rule& rule);

File source/libs/magnum_core/source/magnum/datetime/spi/TimeZoneImpl.cpp

 /*--------------------------------------------------------------------------*/
 /**
  */
-int TimeZoneImpl::findTransition(int64 secs) const
+int TimeZoneImpl::findTransition(const Array<ZoneEntry>& entries, int64 secs)
 {
-    if (m_ZoneEntries.isEmpty())
+    if (entries.isEmpty())
         return -1;
 
-    if (secs < m_ZoneEntries[0].secondsSince1970)
-        return m_ZoneEntries[0].idx;
+    if (secs < entries[0].secondsSince1970)
+        return entries[0].idx;
 
-    if (secs >= m_ZoneEntries[m_ZoneEntries.getSize()-1].secondsSince1970)
+    if (secs >= entries[entries.getSize()-1].secondsSince1970)
         return -1;
 
     int lo = 1;
-    int hi = (int)m_ZoneEntries.getSize();
+    int hi = (int)entries.getSize();
     int mid = 1;
     while (lo < hi) {
         mid = (lo + hi) / 2;
-        if (secs < m_ZoneEntries[mid-1].secondsSince1970)
+        if (secs < entries[mid-1].secondsSince1970)
             hi = mid;
-        else if (secs >= m_ZoneEntries[mid].secondsSince1970)
+        else if (secs >= entries[mid].secondsSince1970)
             lo = mid + 1;
         else
             break;
     }
 
-    return m_ZoneEntries[mid].idx;
+    return entries[mid].idx;
 }
 
 
     Date date(era, year, month, day);
     int64 secs = date.getTotalSecondsSince1970() + time;
 
-    int transition = findTransition(secs);
+    int transition = findTransition(m_ZoneEntries, secs);
 
     // For times on or after last transition use lastRule.
     if (transition < 0) {
 
 int TimeZoneImpl::getOffsetFromLocal(Date::Era era, int year, int month, int day, int dow, int time) const
 {
-    return 0;
+    Date date(era, year, month, day);
+    int64 secs = date.getTotalSecondsSince1970() + time;
+
+    int transition = findTransition(m_InverseZoneEntries ,secs);
+
+    // For times on or after last transition use lastRule.
+    if (transition < 0) {
+        if (m_LastRule)
+            return m_LastRule->getOffsetFromUtc(era, year, month, day, dow, time);
+        else
+            return -m_RawOffset;
+    }
+
+    return -m_ZoneDefinitions[transition].offset;
 }
 
 
     zd.name = name;
     zd.offset = offset;
     zd.isDst = isDst;
-    m_ZoneDefinitions.insert(zd);
+    insertZoneDefinition(zd);
 }
 
 
 /*--------------------------------------------------------------------------*/
 /**
  */
-void TimeZoneImpl::insertZoneEntry(const TimeZoneImpl::ZoneEntry& entry)
+void TimeZoneImpl::insertZoneEntry(const TimeZoneImpl::ZoneEntry& entry, int offset)
 {
     m_ZoneEntries.insert(entry);
+    ZoneEntry inverseEntry = entry;
+    inverseEntry.secondsSince1970 += offset;
+    m_InverseZoneEntries.insert(inverseEntry);
 }
 
 
 /*--------------------------------------------------------------------------*/
 /**
  */
-void TimeZoneImpl::insertZoneEntry(int64 secsSince1970, int idx)
+void TimeZoneImpl::insertZoneEntry(int64 secsSince1970, int idx, int offset)
 {
     ZoneEntry entry;
     entry.idx = idx;
     entry.secondsSince1970 = secsSince1970;
-    m_ZoneEntries.insert(entry);
+    insertZoneEntry(entry, offset);
 }
 
 

File source/libs/magnum_core/source/magnum/datetime/spi/TimeZoneImpl.h

         { 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);
+    void insertZoneEntry(const ZoneEntry& entry, int offset);
+    void insertZoneEntry(int64 secsSince1970, int idx, int offset);
 
     inline const Array<LeapSecondEntry> getLeapSecondEntries() const
         { return m_LeapSeconds; }
     void insertLeapSecondEntry(int64 secondsSince1970, int adjustment);
 
 private:
-    int findTransition(int64 secs) const;
+    static int findTransition(const Array<ZoneEntry>& entries, int64 secs);
 
 private:
     Array<ZoneDefinition> m_ZoneDefinitions;
     Array<LeapSecondEntry> m_LeapSeconds;
     Array<ZoneEntry> m_ZoneEntries;
+    Array<ZoneEntry> m_InverseZoneEntries;
     Reference<const TimeZone> m_LastRule;
     int m_RawOffset;
     int m_DstSaving;

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

     // Create transitions
     int timecnt = (int)zone.transitions.getSize();
     if (timecnt > 0) {
-        tz->insertZoneEntry(zone.transitions[0].time, zone.transitions[0].type);
+        int offset = zone.periods[zone.transitions[0].type].offset;
+        tz->insertZoneEntry(zone.transitions[0].time, zone.transitions[0].type, offset);
         for (int i = 1; i < timecnt; ++i) {
-            tz->insertZoneEntry(zone.transitions[i].time, zone.transitions[i-1].type);
+            int offset = zone.periods[zone.transitions[i].type].offset;
+            tz->insertZoneEntry(zone.transitions[i].time, zone.transitions[i-1].type, offset);
         }
     }
 

File source/unittest/datetime/Test_SimpleTimeZone.h

     TEST_ASSERT( tz->getOffsetFromUtc(Date::AD, 2012, 10, 28, Date::Sunday, 3599) == 7200 );
     TEST_ASSERT( tz->getOffsetFromUtc(Date::AD, 2012, 10, 28, Date::Sunday, 3600) == 3600 );
     TEST_ASSERT( tz->getOffsetFromUtc(Date::AD, 2012, 10, 29, Date::Monday, 0) == 3600 );
+
+    TEST_ASSERT( tz->getOffsetFromLocal(Date::AD, 2012, 3, 24, Date::Saturday, 0) == -3600 );
+    TEST_ASSERT( tz->getOffsetFromLocal(Date::AD, 2012, 3, 25, Date::Sunday, 0) == -3600 );
+    TEST_ASSERT( tz->getOffsetFromLocal(Date::AD, 2012, 3, 25, Date::Sunday, 7199) == -3600 );
+    TEST_ASSERT( tz->getOffsetFromLocal(Date::AD, 2012, 3, 25, Date::Sunday, 7200) == -3600 );
+    TEST_ASSERT( tz->getOffsetFromLocal(Date::AD, 2012, 3, 25, Date::Sunday, 10800) == -7200 );
+    TEST_ASSERT( tz->getOffsetFromLocal(Date::AD, 2012, 3, 26, Date::Monday, 0) == -7200 );
+
+    TEST_ASSERT( tz->getOffsetFromLocal(Date::AD, 2012, 10, 27, Date::Saturday, 0) == -7200 );
+    TEST_ASSERT( tz->getOffsetFromLocal(Date::AD, 2012, 10, 28, Date::Sunday, 0) == -7200 );
+    TEST_ASSERT( tz->getOffsetFromLocal(Date::AD, 2012, 10, 28, Date::Sunday, 7200) == -3600 );
+    TEST_ASSERT( tz->getOffsetFromLocal(Date::AD, 2012, 10, 28, Date::Sunday, 7199) == -7200 );
+    TEST_ASSERT( tz->getOffsetFromLocal(Date::AD, 2012, 10, 29, Date::Monday, 0) == -3600 );
 }
 
 

File source/unittest/datetime/Test_TimeZone.h

     TEST_ASSERT( tz->getOffsetFromUtc(Date::AD, 2012, 10, 28, Date::Sunday, 3599) == 7200 );
     TEST_ASSERT( tz->getOffsetFromUtc(Date::AD, 2012, 10, 28, Date::Sunday, 3600) == 3600 );
     TEST_ASSERT( tz->getOffsetFromUtc(Date::AD, 2012, 10, 29, Date::Monday, 0) == 3600 );
-    //TEST_ASSERT( tz->getLeapSecondEntryCount() == 0 );
-    //TEST_ASSERT( tz->getZoneDefinitionCount() == 8 );
-    //TEST_ASSERT( tz->getZoneEntryCount() == 144 );
+
+    TEST_ASSERT( tz->getOffsetFromLocal(Date::AD, 2012, 3, 24, Date::Saturday, 0) == -3600 );
+    TEST_ASSERT( tz->getOffsetFromLocal(Date::AD, 2012, 3, 25, Date::Sunday, 0) == -3600 );
+    TEST_ASSERT( tz->getOffsetFromLocal(Date::AD, 2012, 3, 25, Date::Sunday, 7199) == -3600 );
+    TEST_ASSERT( tz->getOffsetFromLocal(Date::AD, 2012, 3, 25, Date::Sunday, 7200) == -3600 );
+    TEST_ASSERT( tz->getOffsetFromLocal(Date::AD, 2012, 3, 25, Date::Sunday, 10800) == -7200 );
+    TEST_ASSERT( tz->getOffsetFromLocal(Date::AD, 2012, 3, 26, Date::Monday, 0) == -7200 );
+
+    TEST_ASSERT( tz->getOffsetFromLocal(Date::AD, 2012, 10, 27, Date::Saturday, 0) == -7200 );
+    TEST_ASSERT( tz->getOffsetFromLocal(Date::AD, 2012, 10, 28, Date::Sunday, 0) == -7200 );
+    TEST_ASSERT( tz->getOffsetFromLocal(Date::AD, 2012, 10, 28, Date::Sunday, 7200) == -3600 );
+    TEST_ASSERT( tz->getOffsetFromLocal(Date::AD, 2012, 10, 28, Date::Sunday, 7199) == -7200 );
+    TEST_ASSERT( tz->getOffsetFromLocal(Date::AD, 2012, 10, 29, Date::Monday, 0) == -3600 );
 }