diff --git a/src/libcalamares/locale/TimeZone.cpp b/src/libcalamares/locale/TimeZone.cpp
index 8144a407b..784d77b9c 100644
--- a/src/libcalamares/locale/TimeZone.cpp
+++ b/src/libcalamares/locale/TimeZone.cpp
@@ -94,25 +94,21 @@ TZRegion::tr() const
     return QObject::tr( m_human, "tz_regions" );
 }
 
-QString
-TZZone::tr() const
+TZRegion::~TZRegion()
 {
-    // NOTE: context name must match what's used in zone-extractor.py
-    return QObject::tr( m_human, "tz_names" );
+    qDeleteAll( m_zones );
 }
 
-TZRegionModel::TZRegionModel() {}
-
-std::shared_ptr< TZRegionModel >
-TZRegionModel::fromZoneTab()
+TZRegionList
+TZRegion::fromZoneTab()
 {
-    return TZRegionModel::fromFile( TZ_DATA_FILE );
+    return TZRegion::fromFile( TZ_DATA_FILE );
 }
 
-std::shared_ptr< TZRegionModel >
-TZRegionModel::fromFile( const char* fileName )
+TZRegionList
+TZRegion::fromFile( const char* fileName )
 {
-    auto model = std::make_shared< TZRegionModel >();
+    TZRegionList model;
 
     QFile file( fileName );
     if ( !file.open( QIODevice::ReadOnly | QIODevice::Text ) )
@@ -120,7 +116,6 @@ TZRegionModel::fromFile( const char* fileName )
         return model;
     }
 
-    model->m_regions.reserve( 12 );  // There's 10 in the file right now
     QStringList regions;
 
     QTextStream in( &file );
@@ -154,21 +149,28 @@ TZRegionModel::fromFile( const char* fileName )
         if ( !regions.contains( region ) )
         {
             regions.append( region );
-            model->m_regions.append( new TZRegion( region.toUtf8().data() ) );
+            model.append( new TZRegion( region.toUtf8().data() ) );
         }
     }
 
-    std::sort( model->m_regions.begin(), model->m_regions.end(), []( const TZRegion* l, const TZRegion* r ) {
-        return *l < *r;
-    } );
+    std::sort( model.begin(), model.end(), []( const TZRegion* l, const TZRegion* r ) { return *l < *r; } );
     return model;
 }
 
-TZRegionModel::~TZRegionModel()
+QString
+TZZone::tr() const
+{
+    // NOTE: context name must match what's used in zone-extractor.py
+    return QObject::tr( m_human, "tz_names" );
+}
+
+TZRegionModel::TZRegionModel( TZRegionList l )
+    : m_regions( l )
 {
-    qDeleteAll( m_regions );
 }
 
+TZRegionModel::~TZRegionModel() {}
+
 int
 TZRegionModel::rowCount( const QModelIndex& parent ) const
 {
@@ -197,7 +199,7 @@ TZRegionModel::region( int index ) const
 {
     if ( ( index < 0 ) || ( index >= m_regions.count() ) )
     {
-        index = 0;
+        return nullptr;
     }
     return m_regions[ index ];
 }
diff --git a/src/libcalamares/locale/TimeZone.h b/src/libcalamares/locale/TimeZone.h
index 4311997a4..ff92141fa 100644
--- a/src/libcalamares/locale/TimeZone.h
+++ b/src/libcalamares/locale/TimeZone.h
@@ -63,14 +63,35 @@ protected:
     QString m_key;
 };
 
+class TZZone;
+class TZRegion;
+using TZZoneList = QList< TZZone* >;
+using TZRegionList = QList< TZRegion* >;
+
 /// @brief A pair of strings for timezone regions (e.g. "America")
 class TZRegion : public CStringPair
 {
 public:
     using CStringPair::CStringPair;
+    virtual ~TZRegion();
     QString tr() const override;
 
     bool operator<( const TZRegion& other ) const { return m_key < other.m_key; }
+
+    /** @brief Create model from a zone.tab-like file
+     *
+     * Returns a list of all the regions; each region has a list
+     * of zones within that region.
+     *
+     * The list owns the regions, and the regions own their own list of zones.
+     * When getting rid of the list, remember to qDeleteAll() on it.
+     */
+    static TZRegionList fromFile( const char* fileName );
+    /// @brief Calls fromFile with the standard zone.tab name
+    static TZRegionList fromZoneTab();
+
+private:
+    TZZoneList m_zones;
 };
 
 /// @brief A pair of strings for specific timezone names (e.g. "New_York")
@@ -84,15 +105,12 @@ public:
 class DLLEXPORT TZRegionModel : public QAbstractListModel
 {
 public:
-    /// @brief Create empty model (useless)
+    /// @brief Create empty model
     TZRegionModel();
+    /// @brief Create model from list (non-owning)
+    TZRegionModel( TZRegionList );
     virtual ~TZRegionModel() override;
 
-    /// @brief Create model from a zone.tab-like file
-    static std::shared_ptr< TZRegionModel > fromFile( const char* fileName );
-    /// @brief Calls fromFile with the standard zone.tab name
-    static std::shared_ptr< TZRegionModel > fromZoneTab();
-
     int rowCount( const QModelIndex& parent ) const override;
 
     QVariant data( const QModelIndex& index, int role ) const override;
@@ -100,7 +118,7 @@ public:
     const TZRegion* region( int index ) const;
 
 private:
-    QList< TZRegion* > m_regions;
+    TZRegionList m_regions;
 };
 
 }  // namespace Locale
diff --git a/src/modules/locale/LocalePage.cpp b/src/modules/locale/LocalePage.cpp
index 5dfad3516..e5d14027f 100644
--- a/src/modules/locale/LocalePage.cpp
+++ b/src/modules/locale/LocalePage.cpp
@@ -110,7 +110,10 @@ LocalePage::LocalePage( QWidget* parent )
 }
 
 
-LocalePage::~LocalePage() {}
+LocalePage::~LocalePage()
+{
+    qDeleteAll( m_regionList );
+}
 
 
 void
@@ -144,7 +147,8 @@ containsLocation( const QList< LocaleGlobal::Location >& locations, const QStrin
 void
 LocalePage::init( const QString& initialRegion, const QString& initialZone, const QString& localeGenPath )
 {
-    m_regionModel = CalamaresUtils::Locale::TZRegionModel::fromZoneTab();
+    m_regionList = CalamaresUtils::Locale::TZRegion::fromZoneTab();
+    m_regionModel = std::make_unique< CalamaresUtils::Locale::TZRegionModel >( m_regionList );
     m_regionCombo->setModel( m_regionModel.get() );
 
     // Setup locations
diff --git a/src/modules/locale/LocalePage.h b/src/modules/locale/LocalePage.h
index e918076d9..07f9fe0f2 100644
--- a/src/modules/locale/LocalePage.h
+++ b/src/modules/locale/LocalePage.h
@@ -74,7 +74,8 @@ private:
     void changeLocale();
     void changeFormats();
 
-    std::shared_ptr< CalamaresUtils::Locale::TZRegionModel > m_regionModel;
+    CalamaresUtils::Locale::TZRegionList m_regionList;
+    std::unique_ptr< CalamaresUtils::Locale::TZRegionModel > m_regionModel;
 
     TimeZoneWidget* m_tzWidget;
     QComboBox* m_regionCombo;