电话时区检测

对于运行 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 匹配:
  • 美国/丹佛
  • 美国/凤凰

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

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

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

设备正确设置为 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")]}