Objective c 从核心数据检索NSDate时出现时区问题

Objective c 从核心数据检索NSDate时出现时区问题,objective-c,ios,ios5,nsdate,nsdatecomponents,Objective C,Ios,Ios5,Nsdate,Nsdatecomponents,我使用这种方法将一个月和一年转换为一个日期,该日期等于给定月份的最后一天 + (NSDate*)endOfMonthDateForMonth:(int)month year:(int)year { NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; NSDateComponents *comps = [[NSDateComponents alloc]

我使用这种方法将一个月和一年转换为一个日期,该日期等于给定月份的最后一天

+ (NSDate*)endOfMonthDateForMonth:(int)month year:(int)year
{
    NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
    NSDateComponents *comps = [[NSDateComponents alloc] init];
    comps.year = year;
    comps.month = month;

    NSDate *monthYearDate = [calendar dateFromComponents:comps];

    // daysRange.length will contain the number of the last day of the endMonth:
    NSRange daysRange = [calendar rangeOfUnit:NSDayCalendarUnit inUnit:NSMonthCalendarUnit forDate:monthYearDate];
    comps.day = daysRange.length;
    comps.hour = 0;
    comps.minute = 0;
    comps.second = 0;
    [comps setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
    [calendar setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
    [calendar setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]];
    NSDate *endDate = [calendar dateFromComponents:comps];
    return endDate;
}
我希望日期的时间成分为00:00:00,这就是为什么我将时区设置为GMT 0,将分钟、小时和秒的日期成分设置为0。方法返回的日期是正确的,并且具有00:00:00的时间成分

以下是我将日期保存到核心数据的方式:

NSDate *endDate = [IBEstPeriod endOfMonthDateForMonth:endMonth year:endCalYear];
[annualPeriod setEndDate:endDate];
在检索数据并将其记录到调试器控制台之后,我得到了日期,比如带有时间组件的
2008-12-30 23:00:00+0000
0.

为什么现在组件发生了变化? 它不应该停留在00:00吗

我这里的代码错了什么

谢谢

要看两件事:

  • 在设置时间组件之前,请尝试为
    comps
    设置时区。我还没有测试过,但可能是在设置时区时,NSDateComponents会调整小时以保持与GMT相同的时间

  • 当您从核心数据存储中读回日期时,看看您是如何解释日期的

  • 要看两件事:

  • 在设置时间组件之前,请尝试为
    comps
    设置时区。我还没有测试过,但可能是在设置时区时,NSDateComponents会调整小时以保持与GMT相同的时间

  • 当您从核心数据存储中读回日期时,看看您是如何解释日期的


  • 创建日历后,只需设置日历时区

    将此添加为函数的第二行:

    calendar.timeZone = [NSTimeZone timeZoneWithName:@"UTC"];
    
    但是,一种更简单的方法是:

    - (NSDate*)endOfMonthDateForMonth:(int)month year:(int)year
    {
        NSCalendar *calendar    = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
        calendar.timeZone       = [NSTimeZone timeZoneWithName:@"UTC"];
    
        NSDateComponents *comps = [[NSDateComponents alloc] init];
        comps.year              = year;
        comps.month             = month+1;
        comps.day               = 0;
    
        NSDate *monthYearDate   = [calendar dateFromComponents:comps];
        return monthYearDate;
    }
    
    结果:

    NSLog(@"%@",[self endOfMonthDateForMonth:12 year:2010]);
    // Output: 2012-07-10 12:30:05.999 Testing App[16310:fb03] 2010-12-31 00:00:00 +0000
    

    这是通过将日期设置为下个月的“0”天来实现的,该天与本月的最后一天相同。(这与从下个月的第一天减去一天是一样的。)请注意,这是有效的,因为comp允许“溢出”(或者在本例中是“下溢”)和
    dateFromComponents:
    自动进行计算。

    创建日历后,只需设置日历时区

    将此添加为函数的第二行:

    calendar.timeZone = [NSTimeZone timeZoneWithName:@"UTC"];
    
    但是,一种更简单的方法是:

    - (NSDate*)endOfMonthDateForMonth:(int)month year:(int)year
    {
        NSCalendar *calendar    = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
        calendar.timeZone       = [NSTimeZone timeZoneWithName:@"UTC"];
    
        NSDateComponents *comps = [[NSDateComponents alloc] init];
        comps.year              = year;
        comps.month             = month+1;
        comps.day               = 0;
    
        NSDate *monthYearDate   = [calendar dateFromComponents:comps];
        return monthYearDate;
    }
    
    结果:

    NSLog(@"%@",[self endOfMonthDateForMonth:12 year:2010]);
    // Output: 2012-07-10 12:30:05.999 Testing App[16310:fb03] 2010-12-31 00:00:00 +0000
    

    这是通过将日期设置为下个月的“0”天来实现的,该天与本月的最后一天相同。(这与从下个月的第一天减去一天是一样的。)注意,这是有效的,因为comp允许“溢出”(或者在本例中是“下溢”)和
    dateFromComponents:
    自动进行计算。

    谢谢你的帮助,Caleb!!我尝试了你的建议,可惜没有成功。关于2:我只记录日期,根本没有转换。在读取时,核心数据中存储的日期似乎正在我当前的时区中转换(我基于GMT+2:00)。我怎样才能避免这种转换,它实际上改变了一天?我不关心时间成分,我只需要日期,它必须在所有时区保持不变。NSDate存储日期信息,不受时区的影响。要理解NSDate,您应该使用日期格式化程序来显示日期,以便自己指定时区。我怀疑当您记录日期时,NSDate的
    -description
    方法可能使用当前时区,但日期本身不会更改(日期是不可变的)。因此,如果您想以GMT显示日期,请再次使用日期格式化程序。我不确定NSDate的-description方法是否真的使用了当前时区,因为我使用类似的代码生成NSDate:
    NSDateFormatter*dateFormatter=[[NSDateFormatter alloc]init];[dateFormatter setLocale:[NSLocale alloc]initWithLocaleIdentifier:@“en_US_POSIX”];[日期格式化程序setDateFormat:@“yyy MM dd”];[dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];NSDate*date=[dateFormatter dateFromString:[csvLineItems对象索引:0]]从字符串中解析。。。。在这种情况下,我总是得到正确的值,如2002-04-03 00:00:00+0000。我尝试了相同的方法(字符串解析)而不是上面显示的代码,但仍然存在相同的问题。正如Caleb所说,NSDate始终存储在GMT中,但日历/日期格式化程序操作将在创建或格式化它们时转换为/转换为它们设置的时区。感谢您的帮助,Caleb!!我尝试了你的建议,可惜没有成功。关于2:我只记录日期,根本没有转换。在读取时,核心数据中存储的日期似乎正在我当前的时区中转换(我基于GMT+2:00)。我怎样才能避免这种转换,它实际上改变了一天?我不关心时间成分,我只需要日期,它必须在所有时区保持不变。NSDate存储日期信息,不受时区的影响。要理解NSDate,您应该使用日期格式化程序来显示日期,以便自己指定时区。我怀疑当您记录日期时,NSDate的
    -description
    方法可能使用当前时区,但日期本身不会更改(日期是不可变的)。因此,如果您想以GMT显示日期,请再次使用日期格式化程序。我不确定NSDate的-description方法是否真的使用了当前时区,因为我使用类似的代码生成NSDate:
    NSDateFormatter*dateFormatter=[[NSDateFormatter alloc]init];[dateFormatter setLocale:[NSLocale alloc]initWithLocaleIdentifier:@“en_US_POSIX”];[日期格式化程序setDateFormat:@“yyy MM dd”];[dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];NSDate*date=[dateFormatter dateFromString:[csvLineItems对象索引:0]]从字符串中解析。。。。在这种情况下,我总是得到正确的值,如2002-04-03 00:00:00+0000。我在instea中尝试了相同的方法(字符串解析)