简体   繁体   中英

NSDateFormatter dateFrom String with era

I am trying to parse dates that only consist of years like 145 or 123 BC into NSDate Objects - with not much success so far.

NSDateFormatter f = [[NSDateFormatter alloc]init];
[f setTimeZone:[NSTimeZone systemTimeZone]];
[f setFormatterBehavior:NSDateFormatterBehaviorDefault];
[f setDateFormat:@"y GG"];
date = [f dateFromString:yearString];

yearString contains eg 145 or 123 BC

The results are:
I get nil if I specify the era (GG) in the dateFormat.
If I just specify the year (y) in setDateFormat and the year I parse is 145 I get a date, but it is actually 1 hour before 145.

Two questions:
1. What is the proper way to parse years with era suffixes into NSStrings? 2. Why do I get the hour difference?

how come the hour difference?

Your time zone is probably GMT+1. So you're not actually getting a date one hour earlier but (because your date formatter is set to your time zone), you are parsing the date as 145-01-01 00:00 +0100 . When you now output the date with -[NSDate description] , it will give you the equivalent point in time in GMT, which is 144-12-31 23:00 +0000 .

Just came across this problem myself. @OleBergmann's answer to the second part of your question is correct, but although @bosmac's answer to the main part of your question is technically right, it's not very helpful.

Here's what I did...

func laxDate(str: String) -> Date? {
    let strictDF = DateFormatter()
    strictDF.dateFormat = "yyyy GG"
    let laxDF = DateFormatter()
    laxDF.dateFormat = "yyyy"

    if let d = strictDF.date(from: str) {
        return d
    } else if let d = laxDF.date(from: str) {
        return d
    } else {
        return nil
    }
}

print(String(describing: laxDate(str: "1901"))) // "Optional("1901-01-01 00:00:00 +0000")\n"
print(String(describing: laxDate(str: "10 BC"))) // "Optional("-0009-01-01 00:01:15 +0000")\n"

Or, more tersely...

func laxDate(str: String) -> Date? {
    func df(_ f: String) -> Date? {
        let df = DateFormatter()
        df.dateFormat = f
        return df.date(from: str)
    }

    return df("yyyy GG") ?? df("yyyy")
}

You'll get nil from the formatter if you don't include an era suffix, as is the case for '145'. Make it '145 AD', and I think you'll find it works. The date format components aren't optional — you have to match the whole pattern.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM