توزيع RFC3339 يرجع مع NSDateFormatter في iOS 4.x و MacOS X 10.6: مستحيل؟

StackOverflow https://stackoverflow.com/questions/4330137

سؤال

يبدو أن تحليل تاريخ RFC3339 مع NSDateFormatter مستحيل ، في الحالة العامة. هل أنا مخطئ؟ [تحرير بعد عامين: هناك الآن طريقة! انظر أدناه والحاشية.

تعمل خدمة الويب غير القابلة للارتداد على وجه الخصوص على إطعام مواعيد مثل:

2009-12-31T00:00:00-06:00

RFC3339 متوافق ، الإخراج الافتراضي لمكتبة JaxB التي يستخدمونها. لاحظ القولون ، الذي RFC3339 يستوجب عندما لا يكون الإزاحة "Z" حرفيًا:

time-numoffset  = ("+" / "-") time-hour ":" time-minute
time-offset     = "Z" / time-numoffset

أريد تحليلها في nsdates.

NSDateFormatter يريد أنماط في بناء الجملة المحدد بواسطة يونيكود, ، الذي يوفر رموز حقل التاريخ للمناطق الزمنية مثل "PDT" ، "-0800" ، "GMT-08: 00" ولكن ليس "-08: 00".

غوغلينغ ، وغيرها من الأسئلة المتشابهة ، تنتج تنسيقات تاريخ فقط مثل

[myDateParser setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ssZ"];
/* or: */ [myDateParser setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"];

هذا الأخير يتطلب "Z" الحرفي ، ويصر الأول إما على غياب القولون أو وجود "GMT". ومع ذلك ، بدا أنهم يعملون قبل iOS 4.x (ربما عن طريق التخلص من إزاحة TZ تمامًا ؛ بياناتاتي ليست واضحة.)

خياراتي في هذه المرحلة هي الكثير آسف:

  • اكتشف بعض المواصفات غير الموثقة ، أو بعض الوضع الغريب لوضع NSDateFormatter ، والتي ستقبل القولون الضال: Longshot ، على الأرجح غير موجود. [هامش
  • إقناع ناشر الخدمة الخاص بي بتحويل جميع التواريخ إلى وقت Zulu وتحديد "Z": تحدي سياسي.
  • اكتب بلدي الفئة الفرعية nsformatter أو بحث جيد قديم strptime_l: الشغل. قون
  • تقوم السلسلة بإلغاء مدخلاتي وتجريد القولون الأخير: هش وقبيح ، ولكن المسار المحتمل لأقل مقاومة.

هل فهمت الموقف بدقة ، أن NSDateFormatter الحالي يتبع Unicode بدقة دون امتدادات ؛ وتنسيقات Unicode غير كافية لوصف تاريخ RFC3339 بالكامل؟

هامش لقد عدت إلى هذا بعد ثلاث سنوات لأخذ إضافة صغيرة: أضافت Unicode و Apple هذه الميزة إلى سلاسل التنسيق ، اعتبارًا من iOS6/OSX10.8. قارن آخر مراجعة حتى كتابة هذه السطور مع سلفها المباشر, ، ولاحظ إضافة 5 "Z" S ، التي تعطي تنسيق المنطقة مثل "-08: 00". لذلك إذا تمكنت من التخلص من الدعم للتخلي عن 5.x/10.7 ، فهناك طريقة صحيحة جديدة للقيام بذلك. سأترك موقف الإجابة السابق ، لأنه لا يزال أفضل طريقة عندما يلزم التوافق المتخلف.

هل كانت مفيدة؟

المحلول

يمكن أن يكون تحليل سلسلة التاريخ في الكاكاو ألمًا ، خاصة إذا كان عليك التعامل مع التواريخ التي تم إنشاؤها بواسطة خدمات الويب المستندة إلى .NET.

أقترح النظر في فئة NSDATE+InternetDateTime التي لدى Michael Waterfall على NSDATE كجزء من مشروع MWFeedParser الخاص به على Github. لقد عملت بشكل جيد بالنسبة لي لتحليل شكل التاريخ الذي تصفه بالضبط.

https://github.com/mwaterfall/mwfeedparser/

نصائح أخرى

- getObjectValue: forstring: المدى: خطأ: يمكن بالفعل تحليل RFC3339 بشكل صحيح. ليس لدي أي فكرة لماذا - DateWithString: لا يمكن:

// RFC3339 date formatting
NSString *dateString = @"2012-04-11T18:34:19+00:00";
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ssZ";

NSDate *date;
NSError *error;
[formatter getObjectValue:&date forString:dateString range:nil error:&error];

يتم توثيق أحرف تنسيق السلسلة في أي مكان في وثائق Apple. بدلاً من ذلك ، هناك رابط مخفي بعمق في بعض المستندات التي تشير إلى معيار Unicode في

http://www.unicode.org/reports/tr35/tr35-31/tr35-dates.html#date_format_patterns

استخدام المعلومات في هذا الرابط أمر بسيط للغاية:

- (NSDate*)dateFromRFC3339String:(NSString*)aString
{
    static NSDateFormatter* sRFC3339DateFormatter = nil;
    static NSDateFormatter* sRFC3339DateFormatterSubSeconds = nil;
    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{
        NSLocale *enUSPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];

        sRFC3339DateFormatter = [[NSDateFormatter alloc] init];
        [sRFC3339DateFormatter setLocale:enUSPOSIXLocale];
        [sRFC3339DateFormatter setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ssXXXXX"];
        [sRFC3339DateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];

        sRFC3339DateFormatterSubSeconds = [[NSDateFormatter alloc] init];
        [sRFC3339DateFormatterSubSeconds setLocale:enUSPOSIXLocale];
        [sRFC3339DateFormatterSubSeconds setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ss.SSSSSSXXXXX"];
        [sRFC3339DateFormatterSubSeconds setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
    });

    NSDate* date = [sRFC3339DateFormatter dateFromString:aString];
    if (date == nil)
        date = [sRFC3339DateFormatterSubSeconds dateFromString:aString];

    return date;
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top