Skip to content

Commit 2bcedec

Browse files
adinauerclaude
andcommitted
fix(android): Preserve locale timezone extension
Keep the Calendar-based timezone path for Android 13+ locales that carry a Unicode tz extension. This preserves the existing device timezone behavior while keeping the direct default timezone fast path for normal locales. Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 093c050 commit 2bcedec

2 files changed

Lines changed: 35 additions & 0 deletions

File tree

sentry-android-core/src/main/java/io/sentry/android/core/DeviceInfoUtil.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import android.os.BatteryManager;
1111
import android.os.Build;
1212
import android.os.Environment;
13+
import android.os.LocaleList;
1314
import android.os.StatFs;
1415
import android.os.SystemClock;
1516
import android.util.DisplayMetrics;
@@ -24,6 +25,7 @@
2425
import io.sentry.protocol.OperatingSystem;
2526
import io.sentry.util.AutoClosableReentrantLock;
2627
import java.io.File;
28+
import java.util.Calendar;
2729
import java.util.Collections;
2830
import java.util.Date;
2931
import java.util.List;
@@ -252,8 +254,18 @@ private void setDeviceIO(
252254
}
253255
}
254256

257+
@SuppressWarnings("NewApi")
255258
@NotNull
256259
private TimeZone getTimeZone() {
260+
if (buildInfoProvider.getSdkInfoVersion() >= Build.VERSION_CODES.TIRAMISU) {
261+
LocaleList locales = context.getResources().getConfiguration().getLocales();
262+
if (!locales.isEmpty()) {
263+
Locale locale = locales.get(0);
264+
if (locale.getUnicodeLocaleType("tz") != null) {
265+
return Calendar.getInstance(locale).getTimeZone();
266+
}
267+
}
268+
}
257269
return TimeZone.getDefault();
258270
}
259271

sentry-android-core/src/test/java/io/sentry/android/core/DeviceInfoUtilTest.kt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,22 @@ package io.sentry.android.core
22

33
import android.content.Context
44
import android.content.Intent
5+
import android.content.res.Configuration
56
import android.os.BatteryManager
7+
import android.os.Build
8+
import android.os.LocaleList
69
import androidx.test.core.app.ApplicationProvider
710
import androidx.test.ext.junit.runners.AndroidJUnit4
811
import io.sentry.android.core.internal.util.CpuInfoUtils
12+
import java.util.Locale
913
import java.util.TimeZone
1014
import kotlin.test.BeforeTest
1115
import kotlin.test.Test
1216
import kotlin.test.assertEquals
1317
import kotlin.test.assertNotNull
1418
import kotlin.test.assertNull
1519
import org.junit.runner.RunWith
20+
import org.robolectric.annotation.Config
1621

1722
@RunWith(AndroidJUnit4::class)
1823
class DeviceInfoUtilTest {
@@ -56,6 +61,24 @@ class DeviceInfoUtilTest {
5661
assertEquals(TimeZone.getDefault(), deviceInfo.timezone)
5762
}
5863

64+
@Test
65+
@Config(sdk = [Build.VERSION_CODES.TIRAMISU])
66+
fun `preserves timezone from locale unicode extension`() {
67+
val defaultTimeZone = TimeZone.getDefault()
68+
try {
69+
TimeZone.setDefault(TimeZone.getTimeZone("UTC"))
70+
val configuration = Configuration(context.resources.configuration)
71+
configuration.setLocales(LocaleList(Locale.forLanguageTag("en-US-u-tz-usnyc")))
72+
val localizedContext = context.createConfigurationContext(configuration)
73+
val deviceInfoUtil = DeviceInfoUtil(localizedContext, SentryAndroidOptions())
74+
val deviceInfo = deviceInfoUtil.collectDeviceInformation(false, false)
75+
76+
assertEquals("America/New_York", deviceInfo.timezone?.id)
77+
} finally {
78+
TimeZone.setDefault(defaultTimeZone)
79+
}
80+
}
81+
5982
@Test
6083
fun `does include cpu data`() {
6184
CpuInfoUtils.getInstance().setCpuMaxFrequencies(listOf(1024))

0 commit comments

Comments
 (0)