iosswiftnscalendar

How to convert Gregorian dates to Chinese (not Sexagenary Cycle) in Swift


I am trying to convert Chinese New Years to the Gregorian calendar. But I am running into trouble with iOS because the SDK is returning the year between 1 and 60 (the Sexagenary Cycle) not on an absolute scale. Here is the code from an Xcode playground...

let inputGregorianYear = 2020

let chineseCalendar = Calendar(identifier: .chinese)
let gregorianCalendar = Calendar(identifier: .gregorian)

var formatter = DateFormatter()
formatter.dateFormat = "MM/dd/yyyy"

var gregorianComponents = DateComponents()

gregorianComponents.month = 1
gregorianComponents.day = 25
gregorianComponents.year = inputGregorianYear

let chineseNewYear = gregorianCalendar.date(from: gregorianComponents)

formatter.calendar = chineseCalendar
let chineseDateStr = formatter.string(from: chineseNewYear!)
print("Chinese date: \(chineseDateStr)")     //  Chinese date: 01/01/0037 Should be 01/01/4718?

formatter.calendar = gregorianCalendar
let gregorianDateStr = formatter.string(from: chineseNewYear!)
print("Gregorian date: \(gregorianDateStr)") // Gregorian date: 01/25/2020

Seems like I am missing some setting to switch from Sexagenary to normal years but I can't find it anywhere.

More detail... this is the crux of my problem...

//  Here is the problem...
let chineseCalendar = Calendar(identifier: .chinese)
let gregorianCalendar = Calendar(identifier: .gregorian)

var components = DateComponents()
components.day = 1
components.month = 1
components.year = 4658

let chineseNewYear = chineseCalendar.date(from: components)

var formatter = DateFormatter()
formatter.dateFormat = "MM/dd/YYYY"

formatter.calendar = chineseCalendar
let chineseDateStr = formatter.string(from: chineseNewYear!)
print("Chinese date: \(chineseDateStr)")     //  "Chinese date:  01/01/9278" Should be 1/1/4658?

formatter.calendar = gregorianCalendar
let gregorianDateStr = formatter.string(from: chineseNewYear!)
print("Gregorian date: \(gregorianDateStr)") // "Gregorian date: 01/30/6641" Should be 02/12/2021

Why doesn't this work? The formatter fix does not address the components.year. The only thing that works is components.year in the range of 1..60 for the sexagenary cycle.


Solution

  • Your code is also fine. Just change format to this:

    formatter.dateFormat = "MM/dd/YYYY"
    

    This is how I convert dates.

    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "dd/MM/YYYY"
    dateFormatter.calendar = Calendar(identifier: .gregorian)
    let date = Date()
    let dateInGregorian = dateFormatter.string(from: date)
    
    print(dateInGregorian)
    
    dateFormatter.calendar = Calendar(identifier: .chinese)
    dateFormatter.dateFormat = "dd/MM/YYYY"
    print("Converted date to Chinese = \(dateFormatter.string(from: date))")
    

    To convert to Gregorian:

    dateFormatter.calendar = Calendar(identifier: .gregorian)
    dateFormatter.dateFormat = "dd/MM/YYYY"
    print("Converted date to Gregorian = \(dateFormatter.string(from: date))")
    

    We have different format when working with chinese date, use "dd MMM YYYY". To convert Chinese to Gregorian

    func convertDateFrom(dateString: String, dateFormat: String) -> Date? {
    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = dateFormat
    dateFormatter.locale = Locale(identifier: "en_us")
    guard let date = dateFormatter.date(from: dateString) else {return nil}
    return date
    }
    
    let dateGregorian = convertDateFrom(dateString: "09/03/4657", dateFormat: "dd MMM YYYY") ?? Date()
    
    print("Converted date to Gregorian = \(dateGregorian)")