电话时区检测

对于运行 Android 11 或更低版本的设备,AOSP 中的自动时区检测依赖于来自电话子系统的信号。由于依赖于电话子系统,因此 Android 11 或更低版本上的自动时区检测仅限于电话设备。

当电话时区检测可用时,它使用移动国家/地区代码 (MCC)网络身份和时区 (NITZ)信号工作。

例如,法国的设备可以仅根据附近蜂窝基站报告的 MCC 来识别时区。这是可能的,因为已知法国使用单个时区。

当一个国家/地区使用多个时区时,仅靠 MCC 不足以识别时区。对于这些国家/地区,设备还使用 NITZ 信号来识别正确的时区。这在世界许多地方都运行良好,但这需要 NITZ 信号既可用又正确,因此它依赖于运营商。

电话时区检测是一种被动检测器。它始终运行,因此即使在活动 time_zone_detector 算法当前不是电话时区检测算法时,也经常提出电话时区建议。

电话时区检测的局限性

即使有正确的 NITZ 信号可用,电话时区检测也并非总是在每个国家/地区都运行良好。这是因为 NITZ 仅包含偏移和夏令时信息,这些信息并不总是足以唯一地识别时区。

世界上有很多地方可能会出现这种时区问题。例如,美国科罗拉多州丹佛市和亚利桑那州凤凰城在冬季无法使用 NITZ 信号区分,但在其他季节可以区分。任何具有类似重叠时区的位置都可能遇到此类问题。

下表以丹佛和凤凰城为例,细分了设备行为,具体取决于季节

位置和季节 来自 MCC 或 NITZ 的信息 检测到的时区和行为
科罗拉多州丹佛市
冬季
时间:2021 年 1 月 1 日 12:00:00
国家/地区:美国
偏移:UTC-7,无夏令时
两个时区 ID 匹配
  • America/Denver
  • America/Phoenix

设备正确设置为 America/Denver。
亚利桑那州凤凰城
冬季
时间:2021 年 1 月 1 日 12:00:00
国家/地区:美国
偏移:UTC-7,无夏令时
两个时区 ID 匹配
  • America/Denver
  • America/Phoenix

设备错误设置为 America/Denver。
科罗拉多州丹佛市
夏季
时间:2021 年 7 月 1 日 12:00:00
国家/地区:美国
偏移:UTC-6,夏令时
一个时区 ID 匹配
  • America/Denver

设备正确设置为 America/Denver。
亚利桑那州凤凰城
夏季
时间:2021 年 7 月 1 日 12:00:00
国家/地区:美国
偏移:UTC-7,无夏令时
一个时区 ID 匹配
  • America/Phoenix

设备正确设置为 America/Phoenix。

以上示例表明,在冬季,丹佛或亚利桑那州的 Android 设备必须选择两个匹配的时区 ID 之一,这对于某些设备可能不正确,但仍然显示明显正确的本地时间。即使时区 ID 不正确,设备时钟、日历和其他应用也会显示预期的本地时间,因为两个时区 ID 在冬季都计算相同的本地时间。

但是,在春季,当丹佛实行夏令时而凤凰城不实行夏令时时,如果某些设备设置为用户位置的错误时区 ID,则可能会暂时显示不正确的本地时间。一旦设备收到新的 NITZ 信号(特别是包含“UTC-7,无夏令时”偏移信息的信号),就会纠正此问题,但这可能需要一些时间,并且取决于运营商。

因此,日历或其他应用如果存储冬季的时区 ID 或将其延续到春季,则可能会显示和使用错误的本地时间,直到相关应用更新时区 ID。

调试和测试

以下部分介绍用于调试和测试电话时区检测功能的 shell 命令。

测试环境设置

测试人员通常使用包含测试或模拟电话基站的测试环境来检查电话时区检测行为。测试基站可用于模拟具有不同 MCC 的网络,并向设备发送 NITZ 信号,然后监控其效果。

为了使设备检测到时区,NITZ 信号信息必须正确,与 MCC 一致,并与设备 IANA TZDB(时区规则)的副本匹配。与 MCC 不一致的 NITZ 信号会导致电话算法变得不确定。

例如,如果测试基站使用的 MCC 是美国的,则 NITZ 信号必须包含“世界标准时间”、偏移量和夏令时信息,这些信息对于美国某地是正确的。

与 com.android.phone 服务交互

要验证设备是否接收到正确的电话时区建议,请使用

adb shell dumpsys activity service \
    com.android.phone/com.android.phone.TelephonyDebugService

这会转储电话信息,这些信息也可以在 Android 错误报告中找到。在具有多个 SIM 卡的设备上,每个 SIM 卡无线电都有信息。

“时区日志”显示电话进程已发送给 time_zone_detector 的建议以及发送建议的原因。

TimeServiceHelperImpl:
          SystemClock.elapsedRealtime()=11864061
          System.currentTimeMillis()=1620652067178
          Time Logs:
...

Time zone Logs:
    18602 / 2021-05-10T09:50:21.718Z - Suggesting time zone update:
    TelephonyTimeZoneSuggestion{mSlotIndex=0, mZoneId='null', mMatchType=0, mQuality=0,
    mDebugInfo=[getTimeZoneSuggestion: nitzSignal=TimestampedValue{mReferenceTimeMillis=14098,
    mValue=NitzData{mOriginalString=21/05/10,09:50:18+04,01, mZoneOffset=3600000,
    mDstOffset=3600000, mCurrentTimeMillis=1620640218000, mEmulatorHostTimeZone=null}},
    countryIsoCode=null, Detection
    reason=handleNitzReceived(TimestampedValue{mReferenceTimeMillis=14098,
    mValue=NitzData{mOriginalString=21/05/10,09:50:18+04,01, mZoneOffset=3600000,
    mDstOffset=3600000, mCurrentTimeMillis=1620640218000, mEmulatorHostTimeZone=null}})]}
    18831 / 2021-05-10T09:50:21.948Z - Suggesting time zone update:
    TelephonyTimeZoneSuggestion{mSlotIndex=0, mZoneId='Europe/London', mMatchType=3, mQuality=1,
    mDebugInfo=[findTimeZoneFromCountryAndNitz: countryIsoCode=gb,
    nitzSignal=TimestampedValue{mReferenceTimeMillis=14098,
    mValue=NitzData{mOriginalString=21/05/10,09:50:18+04,01, mZoneOffset=3600000,
    mDstOffset=3600000, mCurrentTimeMillis=1620640218000, mEmulatorHostTimeZone=null}},
    findTimeZoneFromCountryAndNitz: lookupResult=OffsetResult{mTimeZone(ID)=Europe/London,
    mIsOnlyMatch=true}, Detection reason=handleCountryDetected("gb")]}