NSDateComponents - 返回错误日期的日方法

时间:2011-07-30 20:49:43

标签: iphone nsdatecomponent

我似乎无法弄清楚为什么当我到了2011年11月6日这一天没有改变。我所做的一切都在迭代。任何帮助,将不胜感激。这是我的代码:

NSCalendar* calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents* comp = [[NSDateComponents alloc] init];

[comp setDay:2];
[comp setMonth:11];
[comp setYear:2011];

NSDate* date = [calendar dateFromComponents:comp];

for (int i = 0; i < 7; i++) {
    NSDate* d = [date dateByAddingTimeInterval:((3600 * 24) * i)];
    NSDateComponents* dComponents = [calendar components:(NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit) fromDate:d];

    int day = [dComponents day];
    NSLog(@"\nDate: %@\nDay: %i", [d description], day);
}

这是我的输出:

Date: 2011-11-02 06:00:00 +0000
Day: 2

Date: 2011-11-03 06:00:00 +0000
Day: 3

Date: 2011-11-04 06:00:00 +0000
Day: 4

Date: 2011-11-05 06:00:00 +0000
Day: 5

Date: 2011-11-06 06:00:00 +0000
Day: 6

Date: 2011-11-07 06:00:00 +0000
Day: 6

Date: 2011-11-08 06:00:00 +0000
Day: 7

谢谢!

2 个答案:

答案 0 :(得分:34)

欢迎来到精彩的日期计算世界!

@Vladimir是对的。 11月6日恰好有大约90,000秒,因为那时(在阳历中的美国),夏令时生效。接受他的回答;这是正确的。

这个是为了教育你一点,因为这是一个难题

NSDate表示绝对时间点。这一点是不可改变的。无论人类及其时间测量是否存在,它都将存在。

“天”是相对值。这与许多事情有关,例如:

  1. 地球。火星日和地球日不一样
  2. 进行计算的人的日历。并非所有日历都以相同的方式衡量时间。
  3. 因此,不可能获取相对值并将其添加到绝对值而无需更多上下文。您不知道相对值的相对值是多少。您假设每个人都使用与您相同的参考点,并且该假设错误。例如:

    • 当年是2011年。但是呢? “2011”与格里高利历有关。如果您没有使用公历,该怎么办?
    • 当前年份为23.但这只是在您使用日历并特别使用日本时代的名字时。
    • 当年是5771.但这只是在你使用希伯来日历的时候。而下一年的营业额(5772)与下一个格里高利年的营业额并不相同。
    • 当前年份(可能)是1432年。如果你是穆斯林。
    • 如果你是韩国人,那么今年是4344。

    依旧等等。

    作为一般规则,大多数日历都是基于太阳的,这意味着围绕太阳的一个轨道相当于该日历中的一个“年”。但是这使事情变得非常复杂,因为地球围绕太阳旋转的旋转次数(“天”)不是一个整体(整数)。这就像365.24轮换。输入闰日!但只在某些日历中!在其他日历中,我们有整个闰月!或者闰秒。或者闰小时。或者你想要的任何时间单位跳跃。甚至不让我开始时区。

    那么,你怎么处理这个?

    答案简单:你不。人们比你聪明得多,或者我已经编写了代码来处理所有这些问题。

    看哪:

    NSCalendar封装了根据该测量系统计算时间(地球上)的所有规则和规定。 NSDateComponents封装了测量时间的相对性

    所以你有一个绝对的时间点(NSDate),你想知道它对应的星期几。这是你做的:

    • 获取相应的日历对象。对于你将要做的几乎所有事情,这可能是[NSCalendar currentCalendar]
    • 使用日历,你会说“我希望从这个绝对时间点出现这样的'日期组件'”

    日历将会流失并烧毁并返回NSDateComponents,表示您正在寻找的任何信息。

    或者假设你有一个绝对的时间点,你想知道“一周之后的绝对时间点是多少?”。谁知道一周有多长?我不。它通常 7天,但它不一定是。这就是我熟悉的。但我确信那里有基于非7天周的日历。所以你制作一个NSDateComponents对象,抨击它意味着“1周”,并说“日历:我有这个日期和这个相对数量。添加它们并告诉我新的日期”,它就是这样做的。< / p>

    &LT;更新&GT;

    但是,将日期组件添加到日期也可能会有问题。例如,如果你想找到今年每个月的最后一天怎么办? (我们将在这里假设格里高利历)所以你从1月31日恰好落在NSDate开始,然后加上“1个月”。你得到了什么? 2月28日!那么你将一个月添加到那个。你得到了什么? 3月28日!那不是本月底了!

    修复 的方法是始终从原始日期开始计算新日期。因此,不是每个连续日期添加1个月,而是在原始日期添加“n”个月。这将正常工作。

    &LT; /更新&GT;

    您可以看到这是一个难题。如果你没有,这是最后一个提示:

    这是一个难以理解的主题

    你越早学会正确地做事,你和你的代码就越快乐。 :)

答案 1 :(得分:20)

11月6日是由于节约时间而改变时间的一天,因此这一天实际上持续25小时并且可能来自那个不正确的结果(通常由于日历不规则和行为而增加日期的时间间隔是不可靠的可能取决于许多参数:当前日历,时区,区域设置等)。

迭代几天的更正确的方法(每个wwdc11视频"Performing Calendar Calculations"(iTunes链接))是在每次迭代的开始日期添加适当数量的日期组件:

...
NSDateComponents *addComponents = [[NSDateComponents alloc] init];
for (int i = 0; i < 7; i++) {
    [addComponents setDay: i];
    NSDate* d = [calendar dateByAddingComponents:addComponents toDate:date options:0];        
     NSDateComponents* dComponents = [calendar components:(NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit) fromDate:d];

     int day = [dComponents day];
     NSLog(@"\nDate: %@\nDay: %i", [d description], day);
}