سؤال

تحيات،

واجهت مؤخرًا مشكلة كبيرة (كما يبدو لي) مع فئة NSCALENDAR.

في مهمتي ، أحتاج إلى العمل مع فترات زمنية كبيرة تبدأ من 4000BC إلى 2000AD (التقويم الغريغوري). في مكان ما ، اضطررت إلى زيادة بعض الفاصل الزمني لـ 100 عام. عند زيادة السنوات في الجدول الزمني الإعلاني (0-> ...) كل شيء يعمل بشكل جيد ، ولكن عندما جربت نفس الشيء مع BC كنت في حيرة من أمري.

المشكلة هي أنه عندما تحاول إضافة 100 عام إلى 3000BC [تم تحريرها] ، تحصل على 3100BC [تم تحريرها] بغض النظر عن ... شخصياً وجدت أنه غريب وغير منطقي. يجب أن تكون النتيجة الصحيحة 2900BC.

فيما يلي عينة الكود لكي ترى هذا السلوك "غير الصحيح":

NSCalendar *gregorian = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];

// initing
NSDateComponents *comps = [[[NSDateComponents alloc] init] autorelease];
[comps setYear:-1000];
NSDate *date = [gregorian dateFromComponents:comps];

// math
NSDateComponents *deltaComps = [[[NSDateComponents alloc] init] autorelease];
[deltaComps setYear:100];

date = [gregorian dateByAddingComponents:deltaComps toDate:date options:0];

// output
NSString *dateFormat = @"yyyy GG";

NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:dateFormat];
NSLog(@"%@", [formatter stringFromDate:date]);

ماذا يمكنك أن تقول عن هذا السلوك؟ هل هذا كيف ينبغي أن يعمل أم أن هذا خطأ؟ أنا مرتبك: ق.

راجع للشغل: الطريقة [مكونات NSCALENDAR: FROMDATE: TODATE: الخيارات:] لا تسمح لنا بحساب الفرق بين السنوات في عصر BC ... إضافي "لماذا؟" في صندوق باندورا هذا.

ملاحظة: كنت أتجول في الوثائق الرسمية وغيرها من الموارد ، لكنني لم أجد شيئًا فيما يتعلق بهذه المشكلة (أو ربما تهدف إلى العمل ، وأنا أحمق؟).

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

المحلول

لقد وجدت حلًا بسيطًا لهذا الخطأ. ها هو:

@interface NSCalendar (EraFixes)

- (NSDate *)dateByAddingComponentsRegardingEra:(NSDateComponents *)comps toDate:(NSDate *)date options:(NSUInteger)opts;

@end

@implementation NSCalendar (EraFixes)

- (NSDate *)dateByAddingComponentsRegardingEra:(NSDateComponents *)comps toDate:(NSDate *)date options:(NSUInteger)opts
{
    NSDateComponents *toDateComps = [self components:NSEraCalendarUnit fromDate:date];
    NSDateComponents *compsCopy = [[comps copy] autorelease];

    if ([toDateComps era] == 0) //B.C. era
    {
        if ([comps year] != NSUndefinedDateComponent) [compsCopy setYear:-[comps year]];
    }

    return [self dateByAddingComponents:compsCopy toDate:date options:opts];
}

@end

إذا كنت تتساءل عن سبب عكس سنوات فقط ، فإن الإجابة بسيطة ، كل مكون آخر باستثناء السنوات يتزايد وتناقص بالطريقة الصحيحة (لم أختبرها جميعًا ، لكن يبدو أن الأشهر والأيام تعمل بشكل جيد).

تعديل: تمت إزالته عن طريق الخطأ المتمثل في Autorelease ، شكرًا جون.

نصائح أخرى

إنها خطأ أو ميزة. لم يقل مستند Apple أبدًا ما يعنيه إضافة مكونات إلى تاريخ التقويم. إنه مجاني تمامًا بالنسبة لهم لتحديد "إضافة مكون" إلى تاريخ BCE باعتباره مجرد إضافة إلى مكون السنة.

نعم أنا أتفق معك على أنه غير بديهي وأعتقد أنه خطأ.

تحتاج إلى تحويل الخاص بك NSDate إما ل

  • الثاني من عصر UNIX (1.1.1970) باستخدام -timeIntervalSince1970
  • الثاني من OS X Epoch (1.1.2001) باستخدام -timeIntervalSinceReferenceDate

يمكنك بعد ذلك إجراء الحساب ، وتحويله إلى NSDate. أعتقد أنها فكرة سيئة أن تعمل في التقويم الغريغوري طوال الوقت ... سيكون من الأفضل تحويل التقويم الغريغوري قبل إظهاره على واجهة المستخدم الرسومية.

تخيل أن لديك تاريخ مع اللحظة الأولى من عصرنا - AD 0001-01-01 00:00:00. ماذا كانت اللحظة السابقة؟ BC 0001-01-01 00:00:01. إذا استخدم مطورو الكاكاو الحساب الأساسي لهذه المهمة ، فستحصل على AD 0000-12-31 23:59:59. هل هذا معقول للتقويم الغريغوري؟ لا أعتقد. لذلك ، يبدو لي أن الطريقة الأكثر ملاءمة لتنفيذ التقويم هي استخدام علم الحقبة والتغيير "اتجاه الوقت"عند التعامل مع BC ERA للحصول على تواريخ قابلة للقراءة البشرية في كل حالة.

بالمناسبة.: [NSCalendar dateByAddingComponents:toDate:options:] يتصرف حقًا غريبًا وغير قادر على حساب الفاصل الزمني بين تواريخ BC ، لقد راجعت أيضًا. لذلك ، بالنسبة لتواريخ BC ، يمكنك استخدام الحل البديل ، على سبيل المثال عن طريق ترجمة التواريخ إلى م ، ثم العثور على Diff.

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