ios - DateFormatter 返回 nil 以及 TimeZone 和 Locale 的特定组合

标签 ios swift foundation

在我们的应用程序中,存在从字符串创建日期的问题,但只能通过非常特定的组合来重现。不幸的是,无法从遇到该问题的用户那里获取该信息,因此我决定尝试所有可能的组合:

import Foundation

var dateOnlyDateFormatter: (String, String) -> DateFormatter = { timeZoneS, localeS in
    let formatter = DateFormatter()
    formatter.dateFormat = "yyyy-MM-dd"
    formatter.timeZone = TimeZone(identifier: timeZoneS)
    formatter.locale = Locale(identifier: localeS)
    return formatter
}

let date = "2022-05-27"
let time = "06:15"

for timeZone in TimeZone.knownTimeZoneIdentifiers {
    for locale in Locale.availableIdentifiers {
        let dateFormatter = dateOnlyDateFormatter(timeZone, locale)
        let printDate = dateFormatter.date(from: date)
        if printDate == nil {
            print("TimeZone: \(timeZone), Locale: \(locale)")
        }
    }
}

结果:

TimeZone: America/Asuncion, Locale: ar_SA
TimeZone: America/Asuncion, Locale: en_SA

我不太确定处理此问题的最佳方法是什么。显然,我们的 BE 可以使用特定的区域设置返回日期,例如 en_US_POSIX,但我对此几乎没有控制权,因为我是一个更大的旧系统的一部分。有人遇到过这样的问题吗?

最佳答案

如果您阅读 DateFormatter 文档的“Working With Fixed Format Date Representations ”部分,您会发现:

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.

您可能应该遵循此处的建议...但这可能就是为什么 SA 和巴拉圭时区产生 nil 的原因。

在该部分的更下方,有一个指向 technical Q&A 的链接。其中对此进行了更详细的解释。与您的问题最相关的部分是:

A user can change their calendar (using System Preferences > Language & Region > Calendar on OS X, or Settings > General > International > Calendar on iOS). In that case NSDateFormatter will treat the numbers in the string you parse as if they were in the user's chosen calendar. For example, if the user selects the Buddhist calendar, parsing the year "2010" will yield an NSDate in 1467, because the year 2010 on the Buddhist calendar was the year 1467 on the (Gregorian) calendar that we use day-to-day.

在区域设置 SA 中,日期字符串的数字似乎使用 Islamic Calendar 进行解释。 。查看使用 en_SA 和 America/New_York 格式化的今天的日期。

let dateFormatter = dateOnlyDateFormatter("America/New_York", "en_SA")
let printDate = dateFormatter.string(from: .init())
print(printDate)
// 1443-10-26

另请查看 en_SA 和 America/New_York 解析的非零日期

let dateFormatter = dateOnlyDateFormatter("America/New_York", "en_SA")
let printDate = dateFormatter.date(from: date)
print(printDate)
// 2583-10-05 04:00:00 +0000

请注意,10-05 是 2583 年的第一个星期日(请参阅 this calendar )。如果巴拉圭仍然使用the same DST rules就像现在在 2583 年所做的那样,那么这意味着在 2583-10-05 00:00:00 存在 DST 间隙过渡,从 DST 周期开始。从 00:00:00 开始的小时将被跳过,因此 00:00:00 将不存在。

仅解析日期时,DateFormatter 会尝试将时间分量设置为格式化程序时区中的 00:00:00,但 00:00:00 不存在,因此解析失败。


无论如何,设置dateFormat后,只需将locale设置为posix,将timeZone设置为UTC即可。

关于ios - DateFormatter 返回 nil 以及 TimeZone 和 Locale 的特定组合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72406774/

相关文章:

ios - OpenGLES 帧缓冲区问题

objective-c - 整数未存储在数据库中(sqlite3)

ios - 如何在 XCode 中开发和测试 iOS 框架

swift - 方舟 : place object on a plane doesn't work properly

swift - 所有下载完成后停止事件指示器

objective-c - 是否可以更改 NSTimer 的用户信息?

ios - 如何在 Swift 中为 UserDefaults 使用 KVO?

ios - PINCache objectForKey 返回 NSCoding 并且无法转换它

ios - 裁剪为圆形 cell.imageView?

iphone - 使用 XCode 5 的 iPhone 弹出窗口 View