Swift中如何基于App设置而非设备配置UIDatePicker的12/24小时制
解决UIDatePicker跟随App内12/24小时制设置及日本和历显示问题
要实现UIDatePicker不受系统时间制设置影响、完全遵循App内配置,同时保证日本和历能正常显示「令和」前缀,需要分历法动态配置Picker的Locale、Calendar以及时间周期(hourCycle),而非单纯切换Locale。具体方案如下:
核心思路
- 公历场景:通过修改Locale的
hourCycle属性控制12/24小时制,避免切换Locale导致其他历法异常 - 日本和历场景:明确指定Picker的
calendar为JapaneseCalendar,并使用ja_JPLocale,同时通过hourCycle控制时间制,确保和历前缀正常显示 - TextField的日期格式化完全遵循App内用户设置的格式,与Picker显示解耦
关键实现代码
import UIKit class ViewController: UIViewController { let dateTextField = UITextField() let datePickerContainer = UIView() let datePicker = UIDatePicker() let toolbar = UIToolbar() // 模拟App内用户配置:实际开发中替换为UserDefaults读取逻辑 var userPrefers24Hour: Bool { return true // true=24小时制,false=12小时制 } var userPrefersJapaneseCalendar: Bool { return false // true=使用日本和历 } override func viewDidLoad() { super.viewDidLoad() setupDateTextField() setupDatePickerContainer() setupToolbar() setupDatePicker() } // 原setupDateTextField、setupDatePickerContainer、setupToolbar代码保留,此处省略 func setupDatePicker() { datePicker.datePickerMode = .dateAndTime datePicker.preferredDatePickerStyle = .inline datePicker.translatesAutoresizingMaskIntoConstraints = false datePicker.addTarget(self, action: #selector(dateChanged), for: .valueChanged) datePickerContainer.addSubview(datePicker) // 动态配置Picker的Locale、Calendar和时间制 configureDatePickerLocaleAndCalendar() // 约束配置 NSLayoutConstraint.activate([ datePicker.leadingAnchor.constraint(equalTo: datePickerContainer.leadingAnchor, constant: 10), datePicker.trailingAnchor.constraint(equalTo: datePickerContainer.trailingAnchor, constant: -10), datePicker.topAnchor.constraint(equalTo: datePickerContainer.topAnchor, constant: 10), datePicker.bottomAnchor.constraint(equalTo: toolbar.topAnchor, constant: -10) ]) } /// 动态配置UIDatePicker的Locale、Calendar和时间周期 private func configureDatePickerLocaleAndCalendar() { var locale: Locale var calendar: Calendar if userPrefersJapaneseCalendar { // 日本和历场景:指定ja_JP Locale和JapaneseCalendar locale = Locale(identifier: "ja_JP") calendar = Calendar(identifier: .japanese) } else { // 公历场景:使用en_POSIX作为基础Locale,避免系统区域干扰 locale = Locale(identifier: "en_POSIX") calendar = Calendar(identifier: .gregorian) } // 根据用户设置修改Locale的时间周期 locale = locale.withHourCycle(userPrefers24Hour ? .h24 : .h12) datePicker.locale = locale datePicker.calendar = calendar } @objc func dateChanged() { let dateFormatter = DateFormatter() dateFormatter.dateFormat = getUserPreferredDateFormat() // 日本和历时同步修改Formatter的Calendar,保证输出格式正确 if userPrefersJapaneseCalendar { dateFormatter.calendar = Calendar(identifier: .japanese) } dateTextField.text = dateFormatter.string(from: datePicker.date) } // 原showDatePicker、doneButtonTapped代码保留,此处省略 func getUserPreferredDateFormat() -> String { // 根据用户时间制返回对应格式 return userPrefers24Hour ? "dd/MM/yyyy HH:mm" : "dd/MM/yyyy hh:mm a" } } // 扩展Locale,简化时间周期设置 extension Locale { func withHourCycle(_ hourCycle: HourCycle) -> Locale { var components = self.languageComponents components.hourCycle = hourCycle.rawValue return Locale(languageComponents: components) } enum HourCycle: String { case h12 = "h12" case h24 = "h24" } }
代码说明
- 用户配置模拟:
userPrefers24Hour和userPrefersJapaneseCalendar模拟从UserDefaults读取的真实配置,实际开发中替换为对应逻辑即可 - Locale扩展:封装了修改Locale时间周期的逻辑,iOS 13+支持该属性,无需切换整个Locale就能控制时间显示格式
- Picker动态配置:
- 日本和历时强制使用
JapaneseCalendar和ja_JPLocale,确保Picker显示「令和」等和历前缀 - 公历场景使用
en_POSIX作为基础Locale,避免系统区域设置干扰,同时通过hourCycle精准控制时间制
- 日本和历时强制使用
- 日期格式化:TextField显示严格遵循用户设置的格式,日本和历时同步修改Formatter的Calendar,保证输出格式与Picker显示一致
内容的提问来源于stack exchange,提问作者AJITHKUMAR
相关产品推荐
相关产品推荐

