diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt index a1afdcfc1d9..674a9c38838 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt @@ -390,6 +390,7 @@ import org.thoughtcrime.securesms.wallpaper.ChatWallpaperDimLevelUtil import java.time.Instant import java.time.LocalDateTime import java.time.ZoneId +import java.time.ZoneOffset import java.util.Locale import java.util.Optional import java.util.concurrent.ExecutionException @@ -5247,7 +5248,7 @@ class ConversationFragment : datePicker.addOnPositiveButtonClickListener { selectedDate -> if (selectedDate != null) { val localMidnightTimestamp = Instant.ofEpochMilli(selectedDate) - .atZone(ZoneId.systemDefault()) + .atZone(ZoneOffset.UTC) .toLocalDate() .atStartOfDay(ZoneId.systemDefault()) .toInstant() diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/JumpToDateValidator.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/JumpToDateValidator.kt index 4187032070e..ad988856d3c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/JumpToDateValidator.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/JumpToDateValidator.kt @@ -16,6 +16,7 @@ import java.time.Instant import java.time.LocalDate import java.time.LocalDateTime import java.time.ZoneId +import java.time.ZoneOffset import java.time.temporal.TemporalAdjusters import java.util.concurrent.Executor import kotlin.time.Duration.Companion.days @@ -105,7 +106,7 @@ class JumpToDateValidator private constructor( private fun normalizeToLocalMidnight(timestamp: Long): Long { return Instant.ofEpochMilli(timestamp) - .atZone(zoneId) + .atZone(ZoneOffset.UTC) .toLocalDate() .atStartOfDay(zoneId) .toInstant() diff --git a/app/src/test/java/org/thoughtcrime/securesms/conversation/v2/JumpToDateValidatorTest.kt b/app/src/test/java/org/thoughtcrime/securesms/conversation/v2/JumpToDateValidatorTest.kt index c3e5d57b409..16a8f79c16c 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/conversation/v2/JumpToDateValidatorTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/conversation/v2/JumpToDateValidatorTest.kt @@ -187,4 +187,27 @@ class JumpToDateValidatorTest { assertThat(validator.isValid(june15Utc)).isTrue() } + + @Test + fun `picker date maps to the same calendar day in a negative-offset zone`() { + val newYorkZone = ZoneId.of("America/New_York") + + // Days are keyed by local midnight in the database. + val june15NewYorkMidnight = LocalDate.of(2024, 6, 15) + .atStartOfDay(newYorkZone) + .toInstant() + .toEpochMilli() + + val lookup = { dates: Collection -> + dates.associateWith { it == june15NewYorkMidnight } + } + val validator = createValidator(lookup, zone = newYorkZone) + + // The picker reports June 15 as UTC midnight; it must map to June 15 locally, not June 14. + val june15PickerUtc = timestampForDate(2024, 6, 15) + + validator.isValid(june15PickerUtc) + + assertThat(validator.isValid(june15PickerUtc)).isTrue() + } }