電話時區檢測

對於運行 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。
亞利桑那州鳳凰城
冬天
時間:2021年1月1日 12:00:00
國家: 美國
偏移:UTC-7,無夏令時
兩個區域 ID 匹配:
  • 美洲/丹佛
  • 美洲/菲尼克斯

設備未正確設定為美國/丹佛。
科羅拉多州丹佛
夏天
時間:2021年7月1日 12:00:00
國家: 美國
偏移量:UTC-6,夏令時
一個區域 ID 匹配:
  • 美洲/丹佛

設備已正確設定為 America/Denver。
亞利桑那州鳳凰城
夏天
時間: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")]}