我們的 iOS APP 有一個小 Bug,場景簡化後是這樣:
介面返回一個時間字串,APP 裡比較它與當前時間,如果當前時間晚於它,就顯示一個按鈕,否則不顯示。
本來是一個很簡單的邏輯,但是,有一部分使用者反饋,按鈕該顯示的時候卻沒有顯示。
分析
結合使用者反饋的資訊,經過多次嘗試後,才發現這個行為竟然與使用者手機的時間制式有關——如果使用者手機設定裡的 24小時制 開關沒有開啟,那麼這個 Bug 就會出現。
相關的邏輯是這樣寫的:
NSDate *remoteDate = [NSDate dateFromStr:remoteDateString]; if (remoteDate) { // 比較 remoteDate 和 本地當前時間,控制按鈕顯隱 }
這個 dateFromStr:
是一個 category 方法,實現是這樣的:
+ (NSDate*)dateFromStr:(NSString *)dateStr { NSDateFormatter * dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; return [dateFormatter dateFromString:dateStr]; }
經過除錯,發現 remoteDate
在 24小時制 開關關閉時,返回的是 nil
,而在開啟時,返回的是正確的時間。
蘋果官方文件裡,NSDateFormatter
的 dateFromString:
方法是這樣描述的:
Returns a date representation of a given string interpreted using the receiver’s current settings.
Return Value
A date representation of string. If dateFromString: can’t parse the string, returns nil.
同時還給出了 Working With Fixed Format Date Representations 的參考連結,裡面有說明:
When working with fixed format dates, such as RFC 3339, you set the dateFormat property to specify a format string. For most fixed formats, you should also set the locale property to a POSIX locale ("en_US_POSIX"), and set the timeZone property to UTC.
這個頁面裡還給出了一個 QA 連結 Technical Q&A QA1480 “NSDateFormatter and Internet Dates”,裡面有這樣的描述:
On iOS, the user can override the default AM/PM versus 24-hour time setting (via Settings > General > Date & Time > 24-Hour Time), which causes NSDateFormatter to rewrite the format string you set, which can cause your time parsing to fail.
...
On the other hand, if you're working with fixed-format dates, you should first set the locale of the date formatter to something appropriate for your fixed format.
裡面提到了使用者可以透過設定 24小時制 來影響 NSDateFormatter
的行為,還提到了當嘗試把固定格式的日期字串轉換成日期物件時,應該設定 locale
。
至此破案了,這個 Bug 就是由於沒有設定 NSDateFormatter
的 locale
屬性導致的。
解決
修改後的程式碼是這樣的,僅加了一行 locale
設定:
+ (NSDate*)dateFromStr:(NSString *)dateStr { NSDateFormatter * dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; [dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"zh_CN"]]; return [dateFormatter dateFromString:dateStr]; }
經過測試功能正常了,不管使用者手機的 24小時制 開關是否開啟,都能正常解析服務端返回的時間字串了。