diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 4b37c1af039323178273fc1706e892aeaf56d730..1bbb37bc10983f38d05fad54c07c3fe738469210 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -28,7 +28,7 @@ Only start working on the Pull Request after the team assigned the issue to you
 
 If you have questions about one of the issues, please comment on them, and one of the maintainers will clarify.
 
-We kindly ask you to follow the [Pull Request Checklist](#Pull-Request-Checklist) to ensure reviews can happen accordingly.
+We kindly ask you to follow the [Pull Request Checklist](https://github.com/corona-warn-app/cwa-app-android/blob/master/.github/pull_request_template.md) to ensure reviews can happen accordingly.
 
 ## Contributing Code
 
@@ -48,26 +48,6 @@ The following rule governs documentation contributions:
 
 * Contributions must be licensed under the same license as code, the [Apache 2.0 License](LICENSE)
 
-## Pull Request Checklist
-
-* Branch from the dev branch and ensure it is up to date with the current dev branch before submitting your pull request. If it doesn't merge cleanly with dev, you may be asked to resolve the conflicts. Pull requests to master will be closed.
-
-* Commits should be as small as possible while ensuring that each commit is correct independently (i.e., each commit should compile and pass tests).
-
-* Pull requests must not contain compiled sources (already set by the default .gitignore) or binary files
-
-* Test your changes as thoroughly as possible before you commit them. Preferably, automate your test by unit/integration tests. If tested manually, provide information about the test scope in the PR description (e.g. “Test passed: Upgrade version from 0.42 to 0.42.23.”).
-
-* Create _Work In Progress [WIP]_ pull requests only if you need clarification or an explicit review before you can continue your work item.
-
-* If your patch is not getting reviewed or you need a specific person to review it, you can @-reply a reviewer asking for a review in the pull request or a comment, or you can ask for a review by contacting us via [email](mailto:corona-warn-app.opensource@sap.com).
-
-* Post review:
-  * If a review requires you to change your commit(s), please test the changes again.
-  * Amend the affected commit(s) and force push onto your branch.
-  * Set respective comments in your GitHub review to resolved.
-  * Create a general PR comment to notify the reviewers that your amendments are ready for another round of review.
-
 ## Issues and Planning
 
 * We use GitHub issues to track bugs and enhancement requests.
diff --git a/Corona-Warn-App/build.gradle b/Corona-Warn-App/build.gradle
index 578782e8fc9f7ecfd9839e7230f4b9eede6f6038..016749966dd1024ab83d10b6ab2ac44671f30014 100644
--- a/Corona-Warn-App/build.gradle
+++ b/Corona-Warn-App/build.gradle
@@ -39,7 +39,7 @@ android {
         applicationId 'de.rki.coronawarnapp'
         minSdkVersion 23
         targetSdkVersion 29
-        versionCode 45
+        versionCode 47
         versionName "1.5.0"
 
         testInstrumentationRunner "testhelpers.TestApplicationUIRunner"
diff --git a/Corona-Warn-App/src/main/assets/terms_de.html b/Corona-Warn-App/src/main/assets/terms_de.html
index 9bdd955479bf6c6252894a872d73e333a0383ac5..03458bc785114d5a938ab96335998898be4184d4 100644
--- a/Corona-Warn-App/src/main/assets/terms_de.html
+++ b/Corona-Warn-App/src/main/assets/terms_de.html
@@ -96,7 +96,7 @@
 </p>
 <p>
     Sie sind für die Einhaltung dieser Nutzungsbedingungen auch dann
-    verantwortlich, wenn Sie das Endgerät, auf dem Sie die App installiert
+    verantwortlich, wenn Sie das Smartphone, auf dem Sie die App installiert
     haben, Dritten überlassen und diese die App verwenden.
 </p>
 <p>
@@ -116,7 +116,7 @@
     Die App nutzt das von Apple und Google bereitgestellte System für
     COVID-19-Begegnungsbenachrichtigungen („<strong>COVID-19-Benachrichtigungssystem</strong>“), das
     integraler
-    Bestandteil des Betriebssystems Ihres Endgeräts ist. Der genaue Name, die
+    Bestandteil des Betriebssystems Ihres Smartphones ist. Der genaue Name, die
     Bedienung und der Funktionsumfang des COVID-19-Benachrichtigungssystems
     können je nach Hersteller und Version Ihres Betriebssystems variieren. Das
     COVID-19-Benachrichtigungssystem ist kein Bestandteil der CWA-Dienste oder
@@ -193,7 +193,7 @@
     eventuellen Krankheitssymptomen an die CWA-Dienste übermitteln, damit
     andere Personen, die die offizielle Corona-App eines am
     länderübergreifenden Warnsystem teilnehmenden Landes nutzen, auf ihrem
-    eigenen Endgerät benachrichtigt werden können, falls sie mit Ihnen eine
+    eigenen Smartphone benachrichtigt werden können, falls sie mit Ihnen eine
     Risiko-Begegnung hatten.
 </p>
 <p>
@@ -302,8 +302,8 @@
     </strong>
     Die Risiko-Begegnung kann vom COVID-19-Benachrichtigungssystem
     beispielsweise zu einem Zeitpunkt aufgezeichnet worden sein, zu dem Sie
-    sich nicht in der Nähe Ihres Endgeräts aufgehalten haben oder während eine
-    andere Person Ihr Endgerät verwendet hat. Die Risiko-Begegnung kann auch
+    sich nicht in der Nähe Ihres Smartphones aufgehalten haben oder während eine
+    andere Person Ihr Smartphone verwendet hat. Die Risiko-Begegnung kann auch
     aufgrund bestehender Grenzen des COVID-19-Benachrichtigungssystems
     fälschlicherweise registriert worden sein (siehe unten Ziffer 8).
 </p>
@@ -334,7 +334,7 @@
 </ul>
 <p>
     o Die App kennt nicht alle Ihre Begegnungen mit anderen Personen, z.B. weil
-    andere Personen die App nicht verwenden, Sie Ihr Endgerät nicht immer bei
+    andere Personen die App nicht verwenden, Sie Ihr Smartphone nicht immer bei
     sich tragen oder die App nicht immer in Betrieb haben oder weil die
     Begegnungsaufzeichnung mit dem COVID-19-Benachrichtigungssystem gewissen
     Grenzen unterliegt (siehe unten Ziffer 8).
@@ -454,39 +454,39 @@
 <p>
     Bestimmte Funktionen der App setzen auf zentrale Dienste und Systeme auf,
     die über die CWA-Dienste zur Verfügung gestellt werden. Diese Funktionen
-    stehen daher nur zur Verfügung, wenn Ihr Endgerät über eine Datenverbindung
+    stehen daher nur zur Verfügung, wenn Ihr Smartpnone über eine Datenverbindung
     mit dem Internet verfügt, z.B. über UMTS, LTE oder WLAN, um hierüber auf
     die CWA-Dienste zugreifen zu können. Ohne Datenverbindung stehen einige
     oder alle Funktionen der App nicht zur Verfügung. Dies gilt auch, wenn Sie
-    Ihr Endgerät in den Flugmodus versetzen oder ausschalten.
+    Ihr Smartphone in den Flugmodus versetzen oder ausschalten.
 </p>
 <p>
     Das COVID-19-Benachrichtigungssystem muss aktiviert sein
 </p>
 <p>
-    Das COVID-19-Benachrichtigungssystem Ihres Endgeräts muss aktiviert und für
+    Das COVID-19-Benachrichtigungssystem Ihres Smartphones muss aktiviert und für
     die Region „Deutschland“ bzw. die App freigegeben sein.
 </p>
 <p>
     <strong><em>Hintergrundaktualisierung</em></strong>
 </p>
 <p>
-    Die App muss dauerhaft im Hintergrundbetrieb laufen. Wenn Sie das Endgerät
+    Die App muss dauerhaft im Hintergrundbetrieb laufen. Wenn Sie das Smartphone
     neu starten (z.B. nach dem Ausschalten, nachdem die Batterie leer war oder
     nach einem Update des Betriebssystems) oder nach einer erzwungenen
     Beendigung der App müssen Sie auch die App neu starten.
 </p>
 <p>
-    Einstellungen im Endgerät
+    Einstellungen im Smartphone
 </p>
 <p>
     Für die Nutzung der App müssen Sie ferner die Bluetooth (BLE)-Funktionen
-    auf Ihrem Endgerät aktivieren und ggf. zur Verwendung durch die App
+    auf Ihrem Smartphone aktivieren und ggf. zur Verwendung durch die App
     freigeben.
 </p>
 <p>
     Für die Nutzung der App empfiehlt das RKI ferner folgende Funktionen auf
-    Ihrem Endgerät zu aktivieren und ggf. zur Verwendung durch die App
+    Ihrem Smartphone zu aktivieren und ggf. zur Verwendung durch die App
     freizugeben, auch wenn diese nicht Voraussetzung für die Nutzung der
     grundlegenden Funktionen der App sind:
 </p>
@@ -499,7 +499,7 @@
     </li>
 </ul>
 <p>
-    Bitte prüfen Sie in den Einstellungen Ihres Endgeräts, ob diese Funktionen
+    Bitte prüfen Sie in den Einstellungen Ihres Smartphones, ob diese Funktionen
     aktiviert und für die Verwendung der App freigegeben sind.
 </p>
 <p>
@@ -558,12 +558,12 @@
     <li>
         Für die Bewertung des Infektionsrisikos nutzt die App die
         Aufzeichnungen zur Dämpfung des Bluetooth-Signals. Eine geringere
-        Dämpfung bedeutet dabei grundsätzlich, dass das andere Endgerät näher
+        Dämpfung bedeutet dabei grundsätzlich, dass das andere Smartphone näher
         ist. Eine höhere Dämpfung kann entweder bedeuten, dass das andere
-        Endgerät weiter entfernt ist (also eine Entfernung von mehr als zwei
-        Metern) oder dass sich zwischen den beiden Endgeräten etwas befindet,
+        Smartphone weiter entfernt ist (also eine Entfernung von mehr als zwei
+        Metern) oder dass sich zwischen den beiden Smartphones etwas befindet,
         was das Signal blockiert. Das können Objekte wie eine Wand oder eine
-        Tasche, in der sich das Endgerät befindet, sein, aber genauso Personen
+        Tasche, in der sich das Smartphone befindet, sein, aber genauso Personen
         oder Tiere.
     </li>
 </ul>
@@ -629,7 +629,7 @@
     Sie dürfen die App und die Schnittstellen zu den CWA-Diensten nicht
     missbräuchlich verwenden. Sie dürfen die CWA-Dienste nicht für andere
     Zwecke nutzen als den bestimmungsgemäßen Betrieb der App auf Ihrem
-    Endgerät. Sie dürfen auf die CWA-Dienste ausschließlich über die App
+    Smartphone. Sie dürfen auf die CWA-Dienste ausschließlich über die App
     zugreifen.
 </p>
 <p>
@@ -670,7 +670,7 @@
 <p>
     Das RKI behält sich vor, diese Nutzungsbedingungen zu ändern. Wenn Sie den
     geänderten Nutzungsbedingungen nicht zustimmen, können Sie die App und die
-    CWA-Dienste nicht mehr nutzen und müssen die App von Ihrem Endgerät
+    CWA-Dienste nicht mehr nutzen und müssen die App von Ihrem Smartphone
     löschen.
 </p>
 <p>
@@ -713,9 +713,9 @@
     </li>
 </ul>
 <p>
-    Für die Datensicherung Ihres Endgeräts sowie ggf. damit verbundener Systeme
+    Für die Datensicherung Ihres Smartphones sowie ggf. damit verbundener Systeme
     sind Sie verantwortlich, inklusive der Datensicherung sämtlicher anderer
-    Apps, welche auf Ihrem Endgerät gespeichert sind.
+    Apps, welche auf Ihrem Smartphone gespeichert sind.
 </p>
 <p>
     12. BESONDERE BEDINGUNGEN FÃœR DIE IOS-VERSION DER APP
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/download/KeyFileDownloader.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/download/KeyFileDownloader.kt
index aa3b394519b2dd83735ddccbc104115312b6a37c..7c70a16f944ea3fb4963af1a4d05eca980c6cf8b 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/download/KeyFileDownloader.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/download/KeyFileDownloader.kt
@@ -93,6 +93,7 @@ class KeyFileDownloader @Inject constructor(
                         Timber.tag(TAG).w("Missing keyfile for : %s", keyInfo)
                         null
                     } else {
+                        Timber.tag(TAG).v("Providing available key: %s", keyInfo)
                         path
                     }
                 }
@@ -172,11 +173,21 @@ class KeyFileDownloader @Inject constructor(
         availableCountries: List<LocationCode>,
         itemLimit: Int
     ): List<CountryHours> {
-
         val availableHours = availableCountries.flatMap { location ->
             var remainingItems = itemLimit
             // Descending because we go backwards newest -> oldest
-            keyServer.getDayIndex(location).sortedDescending().mapNotNull { day ->
+            val indexWithToday = keyServer.getDayIndex(location).let {
+                val lastDayInIndex = it.maxOrNull()
+                Timber.tag(TAG).v("Last day in index: %s", lastDayInIndex)
+                if (lastDayInIndex != null) {
+                    it.plus(lastDayInIndex.plusDays(1))
+                } else {
+                    it
+                }
+            }
+            Timber.tag(TAG).v("Day index with (fake) today entry: %s", indexWithToday)
+
+            indexWithToday.sortedDescending().mapNotNull { day ->
                 // Limit reached, return null (filtered out) instead of new CountryHours object
                 if (remainingItems <= 0) return@mapNotNull null
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/server/DiagnosisKeyServer.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/server/DiagnosisKeyServer.kt
index 7114ff6348838fa96b53ff2d801d483348608d39..decf192f7e4e028a4e4845efcc6bd19ea0c09d31 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/server/DiagnosisKeyServer.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/server/DiagnosisKeyServer.kt
@@ -110,6 +110,6 @@ class DiagnosisKeyServer @Inject constructor(
     companion object {
         private val TAG = DiagnosisKeyServer::class.java.simpleName
         private val DAY_FORMATTER = DateTimeFormat.forPattern("yyyy-MM-dd")
-        private val HOUR_FORMATTER = DateTimeFormat.forPattern("HH")
+        private val HOUR_FORMATTER = DateTimeFormat.forPattern("H")
     }
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/interoperability/InteroperabilityConfigurationFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/interoperability/InteroperabilityConfigurationFragment.kt
index 7b9f389a549f5c356ba6a10e1a0ddfb77f530f82..be8e13c919927fcf9ea8da8c30100b8b8fadfd82 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/interoperability/InteroperabilityConfigurationFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/interoperability/InteroperabilityConfigurationFragment.kt
@@ -6,6 +6,7 @@ import android.os.Bundle
 import android.provider.Settings
 import android.view.View
 import androidx.fragment.app.Fragment
+import de.rki.coronawarnapp.CoronaWarnApplication
 import de.rki.coronawarnapp.R
 import de.rki.coronawarnapp.databinding.FragmentInteroperabilityConfigurationBinding
 import de.rki.coronawarnapp.ui.main.MainActivity
@@ -29,7 +30,6 @@ class InteroperabilityConfigurationFragment :
     private val networkCallback = object : ConnectivityHelper.NetworkCallback() {
         override fun onNetworkAvailable() {
             vm.getAllCountries()
-            unregisterNetworkCallback()
         }
 
         override fun onNetworkUnavailable() {
@@ -44,6 +44,10 @@ class InteroperabilityConfigurationFragment :
             binding.countryData = it
         }
 
+        if (ConnectivityHelper.isNetworkEnabled(CoronaWarnApplication.getAppContext())) {
+            registerNetworkCallback()
+        }
+
         vm.saveInteroperabilityUsed()
 
         binding.interoperabilityConfigurationHeader.headerButtonBack.buttonIcon.setOnClickListener {
@@ -58,14 +62,13 @@ class InteroperabilityConfigurationFragment :
 
         binding.interoperabilityConfigurationCountryList
             .noCountriesRiskdetailsInfoview.riskDetailsOpenSettingsButton.setOnClickListener {
-            val intent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
-                Intent(Settings.Panel.ACTION_INTERNET_CONNECTIVITY)
-            } else {
-                Intent(Settings.ACTION_SETTINGS)
+                val intent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+                    Intent(Settings.Panel.ACTION_INTERNET_CONNECTIVITY)
+                } else {
+                    Intent(Settings.ACTION_SETTINGS)
+                }
+                startActivity(intent)
             }
-            startActivity(intent)
-            registerNetworkCallback()
-        }
     }
 
     private fun registerNetworkCallback() {
@@ -88,4 +91,11 @@ class InteroperabilityConfigurationFragment :
         super.onDestroy()
         unregisterNetworkCallback()
     }
+
+    override fun onResume() {
+        super.onResume()
+        if (ConnectivityHelper.isNetworkEnabled(CoronaWarnApplication.getAppContext())) {
+            registerNetworkCallback()
+        }
+    }
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/download/KeyFileDownloaderTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/download/KeyFileDownloaderTest.kt
index 3b4644059a48bd0042a9f64b5df109560d80f4cb..960dae2060523e92a70b98da9b9b1c7669e3df75 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/download/KeyFileDownloaderTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/download/KeyFileDownloaderTest.kt
@@ -5,6 +5,7 @@ import de.rki.coronawarnapp.diagnosiskeys.server.DiagnosisKeyServer
 import de.rki.coronawarnapp.diagnosiskeys.server.DownloadInfo
 import de.rki.coronawarnapp.diagnosiskeys.server.LocationCode
 import de.rki.coronawarnapp.diagnosiskeys.storage.CachedKeyInfo
+import de.rki.coronawarnapp.diagnosiskeys.storage.CachedKeyInfo.Type
 import de.rki.coronawarnapp.diagnosiskeys.storage.KeyCacheRepository
 import de.rki.coronawarnapp.diagnosiskeys.storage.legacy.LegacyKeyCacheMigration
 import de.rki.coronawarnapp.storage.AppSettings
@@ -48,7 +49,7 @@ class KeyFileDownloaderTest : BaseIOTest() {
     private lateinit var legacyMigration: LegacyKeyCacheMigration
 
     @MockK
-    private lateinit var diagnosisKeyServer: DiagnosisKeyServer
+    private lateinit var server: DiagnosisKeyServer
 
     @MockK
     private lateinit var deviceStorage: DeviceStorage
@@ -59,6 +60,10 @@ class KeyFileDownloaderTest : BaseIOTest() {
     private val testDir = File(IO_TEST_BASEDIR, this::class.simpleName!!)
     private val keyRepoData = mutableMapOf<String, CachedKeyInfo>()
 
+    private val String.loc get() = LocationCode(this)
+    private val String.day get() = LocalDate.parse(this)
+    private val String.hour get() = LocalTime.parse(this)
+
     @BeforeEach
     fun setup() {
         MockKAnnotations.init(this)
@@ -67,44 +72,38 @@ class KeyFileDownloaderTest : BaseIOTest() {
 
         every { settings.isLast3HourModeEnabled } returns false
 
-        coEvery { diagnosisKeyServer.getCountryIndex() } returns listOf(
-            LocationCode("DE"),
-            LocationCode("NL")
-        )
+        coEvery { server.getCountryIndex() } returns listOf("DE".loc, "NL".loc)
         coEvery { deviceStorage.requireSpacePrivateStorage(any()) } returns mockk<DeviceStorage.CheckResult>().apply {
             every { isSpaceAvailable } returns true
         }
 
-        coEvery { diagnosisKeyServer.getCountryIndex() } returns listOf(
-            LocationCode("DE"), LocationCode("NL")
-        )
-        coEvery { diagnosisKeyServer.getDayIndex(LocationCode("DE")) } returns listOf(
-            LocalDate.parse("2020-09-01"), LocalDate.parse("2020-09-02")
+        coEvery { server.getDayIndex("DE".loc) } returns listOf(
+            "2020-09-01".day, "2020-09-02".day
         )
         coEvery {
-            diagnosisKeyServer.getHourIndex(LocationCode("DE"), LocalDate.parse("2020-09-01"))
-        } returns listOf(
-            LocalTime.parse("18"), LocalTime.parse("19"), LocalTime.parse("20")
-        )
+            server.getHourIndex("DE".loc, "2020-09-01".day)
+        } returns (0..23).map { "$it".hour }
         coEvery {
-            diagnosisKeyServer.getHourIndex(LocationCode("DE"), LocalDate.parse("2020-09-02"))
-        } returns listOf(
-            LocalTime.parse("20"), LocalTime.parse("21")
-        )
-        coEvery { diagnosisKeyServer.getDayIndex(LocationCode("NL")) } returns listOf(
-            LocalDate.parse("2020-09-02"), LocalDate.parse("2020-09-03")
-        )
+            server.getHourIndex("DE".loc, "2020-09-02".day)
+        } returns (0..23).map { "$it".hour }
         coEvery {
-            diagnosisKeyServer.getHourIndex(LocationCode("NL"), LocalDate.parse("2020-09-02"))
-        } returns listOf(
-            LocalTime.parse("20"), LocalTime.parse("21"), LocalTime.parse("22")
+            server.getHourIndex("DE".loc, "2020-09-03".day)
+        } returns (0..12).map { "$it".hour }
+
+        coEvery { server.getDayIndex("NL".loc) } returns listOf(
+            "2020-09-01".day, "2020-09-02".day
         )
         coEvery {
-            diagnosisKeyServer.getHourIndex(LocationCode("NL"), LocalDate.parse("2020-09-03"))
-        } returns listOf(
-            LocalTime.parse("22"), LocalTime.parse("23")
-        )
-        coEvery { diagnosisKeyServer.downloadKeyFile(any(), any(), any(), any(), any()) } answers {
+            server.getHourIndex("NL".loc, "2020-09-01".day)
+        } returns (0..23).map { "$it".hour }
+        coEvery {
+            server.getHourIndex("NL".loc, "2020-09-02".day)
+        } returns (0..23).map { "$it".hour }
+        coEvery {
+            server.getHourIndex("NL".loc, "2020-09-03".day)
+        } returns (0..12).map { "$it".hour }
+
+        coEvery { server.downloadKeyFile(any(), any(), any(), any(), any()) } answers {
             mockDownloadServerDownload(
                 locationCode = arg(0),
                 day = arg(1),
@@ -120,7 +119,7 @@ class KeyFileDownloaderTest : BaseIOTest() {
             mockKeyCacheUpdateComplete(arg(0), arg(1))
         }
         coEvery { keyCache.getEntriesForType(any()) } answers {
-            val type = arg<CachedKeyInfo.Type>(0)
+            val type = arg<Type>(0)
             keyRepoData.values.filter { it.type == type }.map { it to File(testDir, it.id) }
         }
         coEvery { keyCache.getAllCachedKeys() } answers {
@@ -144,7 +143,7 @@ class KeyFileDownloaderTest : BaseIOTest() {
     }
 
     private fun mockKeyCacheCreateEntry(
-        type: CachedKeyInfo.Type,
+        type: Type,
         location: LocationCode,
         dayIdentifier: LocalDate,
         hourIdentifier: LocalTime?
@@ -167,7 +166,8 @@ class KeyFileDownloaderTest : BaseIOTest() {
         checksum: String
     ) {
         keyRepoData[keyInfo.id] = keyInfo.copy(
-            isDownloadComplete = true, checksumMD5 = checksum
+            isDownloadComplete = true,
+            checksumMD5 = checksum
         )
     }
 
@@ -187,7 +187,7 @@ class KeyFileDownloaderTest : BaseIOTest() {
     }
 
     private fun mockAddData(
-        type: CachedKeyInfo.Type,
+        type: Type,
         location: LocationCode,
         day: LocalDate,
         hour: LocalTime?,
@@ -209,7 +209,7 @@ class KeyFileDownloaderTest : BaseIOTest() {
     private fun createDownloader(): KeyFileDownloader {
         val downloader = KeyFileDownloader(
             deviceStorage = deviceStorage,
-            keyServer = diagnosisKeyServer,
+            keyServer = server,
             keyCache = keyCache,
             legacyKeyCache = legacyMigration,
             settings = settings,
@@ -247,7 +247,7 @@ class KeyFileDownloaderTest : BaseIOTest() {
 
         runBlocking {
             shouldThrow<InsufficientStorageException> {
-                downloader.asyncFetchKeyFiles(listOf(LocationCode("DE")))
+                downloader.asyncFetchKeyFiles(listOf("DE".loc))
             }
         }
     }
@@ -264,20 +264,20 @@ class KeyFileDownloaderTest : BaseIOTest() {
 
         runBlocking {
             shouldThrow<InsufficientStorageException> {
-                downloader.asyncFetchKeyFiles(listOf(LocationCode("DE")))
+                downloader.asyncFetchKeyFiles(listOf("DE".loc))
             }
         }
     }
 
     @Test
     fun `error during country index fetch`() {
-        coEvery { diagnosisKeyServer.getCountryIndex() } throws IOException()
+        coEvery { server.getCountryIndex() } throws IOException()
 
         val downloader = createDownloader()
 
         runBlocking {
             shouldThrow<IOException> {
-                downloader.asyncFetchKeyFiles(listOf(LocationCode("DE")))
+                downloader.asyncFetchKeyFiles(listOf("DE".loc))
             }
         }
     }
@@ -287,34 +287,32 @@ class KeyFileDownloaderTest : BaseIOTest() {
         val downloader = createDownloader()
 
         runBlocking {
-            downloader.asyncFetchKeyFiles(
-                listOf(LocationCode("DE"), LocationCode("NL"))
-            ).size shouldBe 4
+            downloader.asyncFetchKeyFiles(listOf("DE".loc, "NL".loc)).size shouldBe 4
         }
 
         coVerify {
             keyCache.createCacheEntry(
-                type = CachedKeyInfo.Type.COUNTRY_DAY,
-                location = LocationCode("DE"),
-                dayIdentifier = LocalDate.parse("2020-09-01"),
+                type = Type.COUNTRY_DAY,
+                location = "DE".loc,
+                dayIdentifier = "2020-09-01".day,
                 hourIdentifier = null
             )
             keyCache.createCacheEntry(
-                type = CachedKeyInfo.Type.COUNTRY_DAY,
-                location = LocationCode("DE"),
-                dayIdentifier = LocalDate.parse("2020-09-02"),
+                type = Type.COUNTRY_DAY,
+                location = "DE".loc,
+                dayIdentifier = "2020-09-02".day,
                 hourIdentifier = null
             )
             keyCache.createCacheEntry(
-                type = CachedKeyInfo.Type.COUNTRY_DAY,
-                location = LocationCode("NL"),
-                dayIdentifier = LocalDate.parse("2020-09-02"),
+                type = Type.COUNTRY_DAY,
+                location = "NL".loc,
+                dayIdentifier = "2020-09-01".day,
                 hourIdentifier = null
             )
             keyCache.createCacheEntry(
-                type = CachedKeyInfo.Type.COUNTRY_DAY,
-                location = LocationCode("NL"),
-                dayIdentifier = LocalDate.parse("2020-09-03"),
+                type = Type.COUNTRY_DAY,
+                location = "NL".loc,
+                dayIdentifier = "2020-09-02".day,
                 hourIdentifier = null
             )
         }
@@ -326,17 +324,16 @@ class KeyFileDownloaderTest : BaseIOTest() {
     @Test
     fun `day fetch with existing data`() {
         mockAddData(
-            type = CachedKeyInfo.Type.COUNTRY_DAY,
-            location = LocationCode("DE"),
-            day = LocalDate.parse("2020-09-01"),
+            type = Type.COUNTRY_DAY,
+            location = "DE".loc,
+            day = "2020-09-01".day,
             hour = null,
             isCompleted = true
         )
-
         mockAddData(
-            type = CachedKeyInfo.Type.COUNTRY_DAY,
-            location = LocationCode("NL"),
-            day = LocalDate.parse("2020-09-02"),
+            type = Type.COUNTRY_DAY,
+            location = "NL".loc,
+            day = "2020-09-02".day,
             hour = null,
             isCompleted = true
         )
@@ -344,22 +341,20 @@ class KeyFileDownloaderTest : BaseIOTest() {
         val downloader = createDownloader()
 
         runBlocking {
-            downloader.asyncFetchKeyFiles(
-                listOf(LocationCode("DE"), LocationCode("NL"))
-            ).size shouldBe 4
+            downloader.asyncFetchKeyFiles(listOf("DE".loc, "NL".loc)).size shouldBe 4
         }
 
         coVerify {
             keyCache.createCacheEntry(
-                type = CachedKeyInfo.Type.COUNTRY_DAY,
-                location = LocationCode("DE"),
-                dayIdentifier = LocalDate.parse("2020-09-02"),
+                type = Type.COUNTRY_DAY,
+                location = "DE".loc,
+                dayIdentifier = "2020-09-02".day,
                 hourIdentifier = null
             )
             keyCache.createCacheEntry(
-                type = CachedKeyInfo.Type.COUNTRY_DAY,
-                location = LocationCode("NL"),
-                dayIdentifier = LocalDate.parse("2020-09-03"),
+                type = Type.COUNTRY_DAY,
+                location = "NL".loc,
+                dayIdentifier = "2020-09-01".day,
                 hourIdentifier = null
             )
         }
@@ -372,21 +367,19 @@ class KeyFileDownloaderTest : BaseIOTest() {
 
     @Test
     fun `day fetch deletes stale data`() {
-        coEvery { diagnosisKeyServer.getDayIndex(LocationCode("DE")) } returns listOf(
-            LocalDate.parse("2020-09-02")
-        )
+        coEvery { server.getDayIndex("DE".loc) } returns listOf("2020-09-02".day)
         val (staleKeyInfo, _) = mockAddData(
-            type = CachedKeyInfo.Type.COUNTRY_DAY,
-            location = LocationCode("DE"),
-            day = LocalDate.parse("2020-09-01"),
+            type = Type.COUNTRY_DAY,
+            location = "DE".loc,
+            day = "2020-09-01".day,
             hour = null,
             isCompleted = true
         )
 
         mockAddData(
-            type = CachedKeyInfo.Type.COUNTRY_DAY,
-            location = LocationCode("NL"),
-            day = LocalDate.parse("2020-09-02"),
+            type = Type.COUNTRY_DAY,
+            location = "NL".loc,
+            day = "2020-09-02".day,
             hour = null,
             isCompleted = true
         )
@@ -394,22 +387,20 @@ class KeyFileDownloaderTest : BaseIOTest() {
         val downloader = createDownloader()
 
         runBlocking {
-            downloader.asyncFetchKeyFiles(
-                listOf(LocationCode("DE"), LocationCode("NL"))
-            ).size shouldBe 3
+            downloader.asyncFetchKeyFiles(listOf("DE".loc, "NL".loc)).size shouldBe 3
         }
 
         coVerify {
             keyCache.createCacheEntry(
-                type = CachedKeyInfo.Type.COUNTRY_DAY,
-                location = LocationCode("DE"),
-                dayIdentifier = LocalDate.parse("2020-09-02"),
+                type = Type.COUNTRY_DAY,
+                location = "DE".loc,
+                dayIdentifier = "2020-09-02".day,
                 hourIdentifier = null
             )
             keyCache.createCacheEntry(
-                type = CachedKeyInfo.Type.COUNTRY_DAY,
-                location = LocationCode("NL"),
-                dayIdentifier = LocalDate.parse("2020-09-03"),
+                type = Type.COUNTRY_DAY,
+                location = "NL".loc,
+                dayIdentifier = "2020-09-01".day,
                 hourIdentifier = null
             )
         }
@@ -421,7 +412,7 @@ class KeyFileDownloaderTest : BaseIOTest() {
     @Test
     fun `day fetch skips single download failures`() {
         var dlCounter = 0
-        coEvery { diagnosisKeyServer.downloadKeyFile(any(), any(), any(), any(), any()) } answers {
+        coEvery { server.downloadKeyFile(any(), any(), any(), any(), any()) } answers {
             dlCounter++
             if (dlCounter == 2) throw IOException("Timeout")
             mockDownloadServerDownload(
@@ -435,9 +426,7 @@ class KeyFileDownloaderTest : BaseIOTest() {
         val downloader = createDownloader()
 
         runBlocking {
-            downloader.asyncFetchKeyFiles(
-                listOf(LocationCode("DE"), LocationCode("NL"))
-            ).size shouldBe 3
+            downloader.asyncFetchKeyFiles(listOf("DE".loc, "NL".loc)).size shouldBe 3
         }
 
         // We delete the entry for the failed download
@@ -451,48 +440,46 @@ class KeyFileDownloaderTest : BaseIOTest() {
         val downloader = createDownloader()
 
         runBlocking {
-            downloader.asyncFetchKeyFiles(
-                listOf(LocationCode("DE"), LocationCode("NL"))
-            ).size shouldBe 6
+            downloader.asyncFetchKeyFiles(listOf("DE".loc, "NL".loc)).size shouldBe 6
         }
 
         coVerify {
             keyCache.createCacheEntry(
-                type = CachedKeyInfo.Type.COUNTRY_HOUR,
-                location = LocationCode("DE"),
-                dayIdentifier = LocalDate.parse("2020-09-02"),
-                hourIdentifier = LocalTime.parse("21")
+                type = Type.COUNTRY_HOUR,
+                location = "DE".loc,
+                dayIdentifier = "2020-09-03".day,
+                hourIdentifier = "12".hour
             )
             keyCache.createCacheEntry(
-                type = CachedKeyInfo.Type.COUNTRY_HOUR,
-                location = LocationCode("DE"),
-                dayIdentifier = LocalDate.parse("2020-09-02"),
-                hourIdentifier = LocalTime.parse("20")
+                type = Type.COUNTRY_HOUR,
+                location = "DE".loc,
+                dayIdentifier = "2020-09-03".day,
+                hourIdentifier = "11".hour
             )
             keyCache.createCacheEntry(
-                type = CachedKeyInfo.Type.COUNTRY_HOUR,
-                location = LocationCode("DE"),
-                dayIdentifier = LocalDate.parse("2020-09-01"),
-                hourIdentifier = LocalTime.parse("20")
+                type = Type.COUNTRY_HOUR,
+                location = "DE".loc,
+                dayIdentifier = "2020-09-03".day,
+                hourIdentifier = "10".hour
             )
 
             keyCache.createCacheEntry(
-                type = CachedKeyInfo.Type.COUNTRY_HOUR,
-                location = LocationCode("NL"),
-                dayIdentifier = LocalDate.parse("2020-09-03"),
-                hourIdentifier = LocalTime.parse("23")
+                type = Type.COUNTRY_HOUR,
+                location = "NL".loc,
+                dayIdentifier = "2020-09-03".day,
+                hourIdentifier = "12".hour
             )
             keyCache.createCacheEntry(
-                type = CachedKeyInfo.Type.COUNTRY_HOUR,
-                location = LocationCode("NL"),
-                dayIdentifier = LocalDate.parse("2020-09-03"),
-                hourIdentifier = LocalTime.parse("22")
+                type = Type.COUNTRY_HOUR,
+                location = "NL".loc,
+                dayIdentifier = "2020-09-03".day,
+                hourIdentifier = "11".hour
             )
             keyCache.createCacheEntry(
-                type = CachedKeyInfo.Type.COUNTRY_HOUR,
-                location = LocationCode("NL"),
-                dayIdentifier = LocalDate.parse("2020-09-02"),
-                hourIdentifier = LocalTime.parse("22")
+                type = Type.COUNTRY_HOUR,
+                location = "NL".loc,
+                dayIdentifier = "2020-09-03".day,
+                hourIdentifier = "10".hour
             )
         }
         coVerify(exactly = 6) { keyCache.markKeyComplete(any(), any()) }
@@ -508,17 +495,17 @@ class KeyFileDownloaderTest : BaseIOTest() {
         every { settings.isLast3HourModeEnabled } returns true
 
         mockAddData(
-            type = CachedKeyInfo.Type.COUNTRY_HOUR,
-            location = LocationCode("DE"),
-            day = LocalDate.parse("2020-09-01"),
-            hour = LocalTime.parse("20"),
+            type = Type.COUNTRY_HOUR,
+            location = "DE".loc,
+            day = "2020-09-03".day,
+            hour = "11".hour,
             isCompleted = true
         )
         mockAddData(
-            type = CachedKeyInfo.Type.COUNTRY_HOUR,
-            location = LocationCode("NL"),
-            day = LocalDate.parse("2020-09-02"),
-            hour = LocalTime.parse("22"),
+            type = Type.COUNTRY_HOUR,
+            location = "NL".loc,
+            day = "2020-09-03".day,
+            hour = "11".hour,
             isCompleted = true
         )
 
@@ -526,45 +513,39 @@ class KeyFileDownloaderTest : BaseIOTest() {
 
         runBlocking {
             downloader.asyncFetchKeyFiles(
-                listOf(LocationCode("DE"), LocationCode("NL"))
+                listOf("DE".loc, "NL".loc)
             ).size shouldBe 6
         }
 
         coVerify {
             keyCache.createCacheEntry(
-                type = CachedKeyInfo.Type.COUNTRY_HOUR,
-                location = LocationCode("DE"),
-                dayIdentifier = LocalDate.parse("2020-09-02"),
-                hourIdentifier = LocalTime.parse("21")
+                type = Type.COUNTRY_HOUR,
+                location = "DE".loc,
+                dayIdentifier = "2020-09-03".day,
+                hourIdentifier = "12".hour
             )
             keyCache.createCacheEntry(
-                type = CachedKeyInfo.Type.COUNTRY_HOUR,
-                location = LocationCode("DE"),
-                dayIdentifier = LocalDate.parse("2020-09-02"),
-                hourIdentifier = LocalTime.parse("20")
+                type = Type.COUNTRY_HOUR,
+                location = "DE".loc,
+                dayIdentifier = "2020-09-03".day,
+                hourIdentifier = "10".hour
             )
 
             keyCache.createCacheEntry(
-                type = CachedKeyInfo.Type.COUNTRY_HOUR,
-                location = LocationCode("NL"),
-                dayIdentifier = LocalDate.parse("2020-09-03"),
-                hourIdentifier = LocalTime.parse("23")
+                type = Type.COUNTRY_HOUR,
+                location = "NL".loc,
+                dayIdentifier = "2020-09-03".day,
+                hourIdentifier = "12".hour
             )
             keyCache.createCacheEntry(
-                type = CachedKeyInfo.Type.COUNTRY_HOUR,
-                location = LocationCode("NL"),
-                dayIdentifier = LocalDate.parse("2020-09-03"),
-                hourIdentifier = LocalTime.parse("22")
+                type = Type.COUNTRY_HOUR,
+                location = "NL".loc,
+                dayIdentifier = "2020-09-03".day,
+                hourIdentifier = "10".hour
             )
         }
         coVerify(exactly = 4) {
-            diagnosisKeyServer.downloadKeyFile(
-                any(),
-                any(),
-                any(),
-                any(),
-                any()
-            )
+            server.downloadKeyFile(any(), any(), any(), any(), any())
         }
         coVerify { deviceStorage.requireSpacePrivateStorage(90112L) }
     }
@@ -574,79 +555,71 @@ class KeyFileDownloaderTest : BaseIOTest() {
         every { settings.isLast3HourModeEnabled } returns true
 
         val (staleKey1, _) = mockAddData(
-            type = CachedKeyInfo.Type.COUNTRY_HOUR,
-            location = LocationCode("NL"),
-            day = LocalDate.parse("2020-09-02"),
-            hour = LocalTime.parse("12"), // Stale hour
+            type = Type.COUNTRY_HOUR,
+            location = "DE".loc,
+            day = "2020-09-02".day,
+            hour = "01".hour, // Stale hour
             isCompleted = true
         )
 
         val (staleKey2, _) = mockAddData(
-            type = CachedKeyInfo.Type.COUNTRY_HOUR,
-            location = LocationCode("NL"),
-            day = LocalDate.parse("2020-09-01"), // Stale day
-            hour = LocalTime.parse("22"),
+            type = Type.COUNTRY_HOUR,
+            location = "NL".loc,
+            day = "2020-09-02".day, // Stale day
+            hour = "01".hour,
             isCompleted = true
         )
 
         mockAddData(
-            type = CachedKeyInfo.Type.COUNTRY_HOUR,
-            location = LocationCode("DE"),
-            day = LocalDate.parse("2020-09-01"),
-            hour = LocalTime.parse("20"),
+            type = Type.COUNTRY_HOUR,
+            location = "DE".loc,
+            day = "2020-09-03".day,
+            hour = "10".hour,
             isCompleted = true
         )
         mockAddData(
-            type = CachedKeyInfo.Type.COUNTRY_HOUR,
-            location = LocationCode("NL"),
-            day = LocalDate.parse("2020-09-02"),
-            hour = LocalTime.parse("22"),
+            type = Type.COUNTRY_HOUR,
+            location = "NL".loc,
+            day = "2020-09-03".day,
+            hour = "10".hour,
             isCompleted = true
         )
 
         val downloader = createDownloader()
 
         runBlocking {
-            downloader.asyncFetchKeyFiles(
-                listOf(LocationCode("DE"), LocationCode("NL"))
-            ).size shouldBe 6
+            downloader.asyncFetchKeyFiles(listOf("DE".loc, "NL".loc)).size shouldBe 6
         }
 
         coVerify {
             keyCache.createCacheEntry(
-                type = CachedKeyInfo.Type.COUNTRY_HOUR,
-                location = LocationCode("DE"),
-                dayIdentifier = LocalDate.parse("2020-09-02"),
-                hourIdentifier = LocalTime.parse("21")
+                type = Type.COUNTRY_HOUR,
+                location = "DE".loc,
+                dayIdentifier = "2020-09-03".day,
+                hourIdentifier = "12".hour
             )
             keyCache.createCacheEntry(
-                type = CachedKeyInfo.Type.COUNTRY_HOUR,
-                location = LocationCode("DE"),
-                dayIdentifier = LocalDate.parse("2020-09-02"),
-                hourIdentifier = LocalTime.parse("20")
+                type = Type.COUNTRY_HOUR,
+                location = "DE".loc,
+                dayIdentifier = "2020-09-03".day,
+                hourIdentifier = "11".hour
             )
 
             keyCache.createCacheEntry(
-                type = CachedKeyInfo.Type.COUNTRY_HOUR,
-                location = LocationCode("NL"),
-                dayIdentifier = LocalDate.parse("2020-09-03"),
-                hourIdentifier = LocalTime.parse("23")
+                type = Type.COUNTRY_HOUR,
+                location = "NL".loc,
+                dayIdentifier = "2020-09-03".day,
+                hourIdentifier = "12".hour
             )
             keyCache.createCacheEntry(
-                type = CachedKeyInfo.Type.COUNTRY_HOUR,
-                location = LocationCode("NL"),
-                dayIdentifier = LocalDate.parse("2020-09-03"),
-                hourIdentifier = LocalTime.parse("22")
+                type = Type.COUNTRY_HOUR,
+                location = "NL".loc,
+                dayIdentifier = "2020-09-03".day,
+                hourIdentifier = "11".hour
             )
         }
         coVerify(exactly = 4) {
-            diagnosisKeyServer.downloadKeyFile(
-                any(),
-                any(),
-                any(),
-                any(),
-                any()
-            )
+            server.downloadKeyFile(any(), any(), any(), any(), any())
         }
         coVerify(exactly = 1) { keyCache.delete(listOf(staleKey1, staleKey2)) }
     }
@@ -656,7 +629,7 @@ class KeyFileDownloaderTest : BaseIOTest() {
         every { settings.isLast3HourModeEnabled } returns true
 
         var dlCounter = 0
-        coEvery { diagnosisKeyServer.downloadKeyFile(any(), any(), any(), any(), any()) } answers {
+        coEvery { server.downloadKeyFile(any(), any(), any(), any(), any()) } answers {
             dlCounter++
             if (dlCounter == 2) throw IOException("Timeout")
             mockDownloadServerDownload(
@@ -670,9 +643,7 @@ class KeyFileDownloaderTest : BaseIOTest() {
         val downloader = createDownloader()
 
         runBlocking {
-            downloader.asyncFetchKeyFiles(
-                listOf(LocationCode("DE"), LocationCode("NL"))
-            ).size shouldBe 5
+            downloader.asyncFetchKeyFiles(listOf("DE".loc, "NL".loc)).size shouldBe 5
         }
 
         // We delete the entry for the failed download
@@ -682,9 +653,9 @@ class KeyFileDownloaderTest : BaseIOTest() {
     @Test
     fun `not completed cache entries are overwritten`() {
         mockAddData(
-            type = CachedKeyInfo.Type.COUNTRY_DAY,
-            location = LocationCode("DE"),
-            day = LocalDate.parse("2020-09-01"),
+            type = Type.COUNTRY_DAY,
+            location = "DE".loc,
+            day = "2020-09-01".day,
             hour = null,
             isCompleted = false
         )
@@ -692,16 +663,14 @@ class KeyFileDownloaderTest : BaseIOTest() {
         val downloader = createDownloader()
 
         runBlocking {
-            downloader.asyncFetchKeyFiles(
-                listOf(LocationCode("DE"), LocationCode("NL"))
-            ).size shouldBe 4
+            downloader.asyncFetchKeyFiles(listOf("DE".loc, "NL".loc)).size shouldBe 4
         }
 
         coVerify {
             keyCache.createCacheEntry(
-                type = CachedKeyInfo.Type.COUNTRY_DAY,
-                location = LocationCode("DE"),
-                dayIdentifier = LocalDate.parse("2020-09-01"),
+                type = Type.COUNTRY_DAY,
+                location = "DE".loc,
+                dayIdentifier = "2020-09-01".day,
                 hourIdentifier = null
             )
         }
@@ -719,42 +688,30 @@ class KeyFileDownloaderTest : BaseIOTest() {
         val downloader = createDownloader()
 
         runBlocking {
-            downloader.asyncFetchKeyFiles(
-                listOf(LocationCode("DE"), LocationCode("NL"))
-            ).size shouldBe 3
+            downloader.asyncFetchKeyFiles(listOf("DE".loc, "NL".loc)).size shouldBe 3
         }
 
         coVerify(exactly = 4) {
-            diagnosisKeyServer.downloadKeyFile(
-                any(),
-                any(),
-                any(),
-                any(),
-                any()
-            )
+            server.downloadKeyFile(any(), any(), any(), any(), any())
         }
     }
 
     @Test
     fun `store server md5`() {
-        coEvery { diagnosisKeyServer.getCountryIndex() } returns listOf(LocationCode("DE"))
-        coEvery { diagnosisKeyServer.getDayIndex(LocationCode("DE")) } returns listOf(
-            LocalDate.parse("2020-09-01")
-        )
+        coEvery { server.getCountryIndex() } returns listOf("DE".loc)
+        coEvery { server.getDayIndex("DE".loc) } returns listOf("2020-09-01".day)
 
         val downloader = createDownloader()
 
         runBlocking {
-            downloader.asyncFetchKeyFiles(
-                listOf(LocationCode("DE"))
-            ).size shouldBe 1
+            downloader.asyncFetchKeyFiles(listOf("DE".loc)).size shouldBe 1
         }
 
         coVerify {
             keyCache.createCacheEntry(
-                type = CachedKeyInfo.Type.COUNTRY_DAY,
-                location = LocationCode("DE"),
-                dayIdentifier = LocalDate.parse("2020-09-01"),
+                type = Type.COUNTRY_DAY,
+                location = "DE".loc,
+                dayIdentifier = "2020-09-01".day,
                 hourIdentifier = null
             )
         }
@@ -767,11 +724,9 @@ class KeyFileDownloaderTest : BaseIOTest() {
 
     @Test
     fun `use local MD5 as fallback if there is none available from the server`() {
-        coEvery { diagnosisKeyServer.getCountryIndex() } returns listOf(LocationCode("DE"))
-        coEvery { diagnosisKeyServer.getDayIndex(LocationCode("DE")) } returns listOf(
-            LocalDate.parse("2020-09-01")
-        )
-        coEvery { diagnosisKeyServer.downloadKeyFile(any(), any(), any(), any(), any()) } answers {
+        coEvery { server.getCountryIndex() } returns listOf("DE".loc)
+        coEvery { server.getDayIndex("DE".loc) } returns listOf("2020-09-01".day)
+        coEvery { server.downloadKeyFile(any(), any(), any(), any(), any()) } answers {
             mockDownloadServerDownload(
                 locationCode = arg(0),
                 day = arg(1),
@@ -784,16 +739,14 @@ class KeyFileDownloaderTest : BaseIOTest() {
         val downloader = createDownloader()
 
         runBlocking {
-            downloader.asyncFetchKeyFiles(
-                listOf(LocationCode("DE"))
-            ).size shouldBe 1
+            downloader.asyncFetchKeyFiles(listOf("DE".loc)).size shouldBe 1
         }
 
         coVerify {
             keyCache.createCacheEntry(
-                type = CachedKeyInfo.Type.COUNTRY_DAY,
-                location = LocationCode("DE"),
-                dayIdentifier = LocalDate.parse("2020-09-01"),
+                type = Type.COUNTRY_DAY,
+                location = "DE".loc,
+                dayIdentifier = "2020-09-01".day,
                 hourIdentifier = null
             )
         }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/server/DiagnosisKeyServerTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/server/DiagnosisKeyServerTest.kt
index bce772243e8ac7803287c082889e2d06c06c527c..08aed5e5ad0fcfd395d52169b7c3b3d760e9b049 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/server/DiagnosisKeyServerTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/server/DiagnosisKeyServerTest.kt
@@ -81,7 +81,7 @@ class DiagnosisKeyServerTest : BaseIOTest() {
     fun `download hour index for country and day`() {
         val downloadServer = createDownloadServer()
         coEvery { api.getHourIndex("DE", "2000-01-01") } returns listOf(
-            "20", "21"
+            "1", "2", "20", "21"
         )
 
         runBlocking {
@@ -89,7 +89,7 @@ class DiagnosisKeyServerTest : BaseIOTest() {
                 LocationCode("DE"),
                 LocalDate.parse("2000-01-01")
             ) shouldBe listOf(
-                "20:00", "21:00"
+                "01:00", "02:00", "20:00", "21:00"
             ).map { LocalTime.parse(it) }
         }
 
@@ -122,28 +122,51 @@ class DiagnosisKeyServerTest : BaseIOTest() {
     }
 
     @Test
-    fun `download key files for hour`() {
+    fun `download key files for hour and check hour format`() {
         val downloadServer = createDownloadServer()
-        coEvery {
-            api.downloadKeyFileForHour(
-                "DE",
-                "2000-01-01",
-                "01"
-            )
-        } returns Response.success("testdata-hour".toResponseBody())
-
-        val targetFile = File(testDir, "hour-keys")
 
         runBlocking {
+            coEvery {
+                api.downloadKeyFileForHour(
+                    "DE",
+                    "2000-01-01",
+                    "1" // no leading ZEROS!
+                )
+            } returns Response.success("testdata-hour".toResponseBody())
+
+            val targetFile = File(testDir, "hour-keys")
+
             downloadServer.downloadKeyFile(
                 locationCode = LocationCode("DE"),
                 day = LocalDate.parse("2000-01-01"),
                 hour = LocalTime.parse("01:00"),
                 saveTo = targetFile
             )
+
+            targetFile.exists() shouldBe true
+            targetFile.readText() shouldBe "testdata-hour"
         }
 
-        targetFile.exists() shouldBe true
-        targetFile.readText() shouldBe "testdata-hour"
+        runBlocking {
+            coEvery {
+                api.downloadKeyFileForHour(
+                    "DE",
+                    "2000-01-01",
+                    "13"
+                )
+            } returns Response.success("testdata-hour".toResponseBody())
+
+            val targetFile = File(testDir, "hour-keys")
+
+            downloadServer.downloadKeyFile(
+                locationCode = LocationCode("DE"),
+                day = LocalDate.parse("2000-01-01"),
+                hour = LocalTime.parse("13:00"),
+                saveTo = targetFile
+            )
+
+            targetFile.exists() shouldBe true
+            targetFile.readText() shouldBe "testdata-hour"
+        }
     }
 }