NSDate date method returns wrong result

10,512

Solution 1

NSDates are always stored in UTC, actually the dates itselfs dont know anything about timezones or weeks, month, years. They are just a point in time.

To see the correct time for your position on the earth surface, you need to take the NSCalendar, that represents your time model in account. You could use it directly and mess around with your dates, or create a NSDateFormatter that will leave the dates untouched but adjust their appearence to your needs.

NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterFullStyle];
[formatter setTimeStyle:NSDateFormatterFullStyle];

NSLog(@"%@", [formatter stringFromDate: date1]);

results in

Thursday, July 12, 2012, 4:36:07 PM Central European Summer Time 

in response to the comment:

try this code as test

NSDate *now = [NSDate date];
NSDate *startOfToday = nil;
NSDate *startOfThisWeek = nil;
NSDate *startOfThisMonth = nil;
NSDate *startOfThisYear = nil;
[[NSCalendar currentCalendar] rangeOfUnit:NSDayCalendarUnit startDate:&startOfToday interval:NULL forDate:now];
[[NSCalendar currentCalendar] rangeOfUnit:NSWeekCalendarUnit startDate:&startOfThisWeek interval:NULL forDate:now];
[[NSCalendar currentCalendar] rangeOfUnit:NSMonthCalendarUnit startDate:&startOfThisMonth interval:NULL forDate:now];
[[NSCalendar currentCalendar] rangeOfUnit:NSYearCalendarUnit startDate:&startOfThisYear interval:NULL forDate:now];

NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterFullStyle];
[formatter setTimeStyle:NSDateFormatterFullStyle];

NSLog(@"%@", now);
NSLog(@"%@", [formatter stringFromDate:now]);

NSLog(@"%@", startOfToday);
NSLog(@"%@", [formatter stringFromDate:startOfToday]);

NSLog(@"%@", startOfThisWeek);
NSLog(@"%@", [formatter stringFromDate:startOfThisWeek]);

NSLog(@"%@", startOfThisMonth);
NSLog(@"%@", [formatter stringFromDate:startOfThisMonth]);

NSLog(@"%@", startOfThisYear);
NSLog(@"%@", [formatter stringFromDate:startOfThisYear]);

you will realize, that the start of the day, week, month and year will be adjusted to your local time, as the first of each NSLog-pair will give you the date in UTC and the second in your local time zone.


on the chat you posted this code

NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init]; 
[dateFormat setDateFormat:@"yyyy-MM-dd HH:mm"]; 
[dateFormat setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]]; 
NSDate *date = [dateFormat dateFromString:dateString]; 
[dateFormat release]; 

so the problem is, that the datestring is actually not from GMT, but EET (Eastern European Time)

try

[dateFormat setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"EET"]]; 

but the by far most elegant solution would be to get the datestring with the offset to UTC, similar to 2012-07-12 12:23:00 +0300if some how possible.
In such an case you could parse it with
[dateFormat setDateFormat:@"yyyy-mm-dd HH:mm:ss Z"]; and don't need further time zone handling, as the formatter knows the offset via the Z-specifier.
Also note, that if you don't set any timezone, the device's current should be used. If the user is always in the same timezone as the time from the date string, this should work, too. But if the user leaves that zone, or you inted to have it working world wide, you should use one of the solutions I gave you. With the second (specifying the timezone with-in the datestring) as the preferred one.

Solution 2

The date probably has the correct value; perhaps you think it's incorrect because it looks wrong when you log it? This is because when you log it, it shows the date in UTC. You can get the string in your local timezone by using an NSDateFormatter.

Solution 3

The answer is correct if the second date is in UTC. The Ukraine is currently 3 hours ahead of UTC so midnight UTC is at 21:00 in the Ukraine. 21:00 - 18:00 is 3 hours. So check how you are obtaining the second date. The wrong time zone is probably being specified for it.

If the first date really was created at 18:00 Ukraine time via

nowDate = [NSDate date];

then the second date really is 21:00 Ukraine time which corresponds to midnight UTC. Since you claim it is midnight, you must have used UTC to create it from a string - either implicitly or explicitly. Show us how you created it.

** EDIT **

The code you gave me on chat is this:

NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init]; 
[dateFormat setDateFormat:@"yyyy-MM-dd HH:mm"]; 
[dateFormat setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]]; 
NSDate *date = [dateFormat dateFromString:dateString]; 
[dateFormat release]; 

The third line sets the time zone to GMT which is identical to UTC for all intents and purposes. Your date formatter is probably initialised to the correct locale for the device and so probably you can just leave that line out.

Share:
10,512
Timur Mustafaev
Author by

Timur Mustafaev

Updated on June 17, 2022

Comments

  • Timur Mustafaev
    Timur Mustafaev almost 2 years

    I know there is a lot of questions of this type, but I did't find solution for my case; I need to get current and correct NSDate object, not NSString! This code returns wrong time (+3 hours), because I'm from Ukraine.

    NSDate *currentDate = [NSDate date];
    

    How to get current NSDate object from NSDateFormatter? I know only how to get NSString, but I don't need it.

    EDIT: I'm using this code to compare 2 NSDates using NSCalendar object, here is code:

    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSUInteger unitFlags = NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;
    NSDateComponents *components = [calendar components:unitFlags fromDate:nowDate toDate:endDate options:0];
    

    and components.hour shows me +3 hours difference