NSDate date method returns wrong result - objective-c

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

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.

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.

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.

Related

Calculating actual day's midnight date [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Getting date from [NSDate date] off by a few hours
I want to calculate the actual day's midnight time using the actual day's date here is the code:
NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
[formatter setDateFormat:#"dd/MM/yyyy"];
NSDate *today = [NSDate date];
NSString *todayStr = [NSString stringWithFormat:#"%# 12:59 PM",[formatter stringFromDate:today]];
NSLog(#"%#",todayStr);
[formatter setDateFormat:#"dd/MM/yyyy hh:mm a"];
NSDate *midNight = [formatter dateFromString:todayStr];
NSLog(#"%#",midNight);
But the log I get is :
23/01/2013 12:59 PM
2013-01-23 10:59:00 +0000
Why does midNight isn't the actual midnight and why does it have a different format from formatter?
The midnight you calculated with date formatter takes the localization into account.
So, you are living in a UTC+2 timezone.
You can add a 'Z' for UTC.
See more at http://www.w3.org/TR/NOTE-datetime
This calculates midnight for your local timezone.
NSDate *d = [NSDate date];
NSCalendar *cal = [NSCalendar currentCalendar];
NSDateComponents *comps = [cal components:NSEraCalendarUnit|NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit fromDate:d];
d = [cal dateFromComponents:comps];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"dd/MM/yyyy hh:mm a"];
NSString *dateStr = [formatter stringFromDate:d];
NSLog(#"%#", dateStr);
prints 23/01/2013 12:00 AM

Get the time and date of selected time zone?

I tried below snippet I'm getting current date and time of system instead of the selected time zone code.
NSDate *now = [NSDate date];
NSCalendar *gregorian=[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
[gregorian setTimeZone:[NSTimeZone timeZoneWithName:selectedzone]];
NSDateComponents* timeZoneComps = [gregorian components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit|NSHourCalendarUnit|NSMinuteCalendarUnit|NSSecondCalendarUnit|NSTimeZoneCalendarUnit fromDate:now];
NSDate *selectedDate=[gregorian dateFromComponents:timeZoneComps];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterFullStyle];
[formatter setDateFormat:#"dd-MM-yyyy HH:mm:ss "];
NSString *strSelectedDate= [formatter stringFromDate:selectedDate];
setZone.text = strSelectedDate;`
Any ideas?
[NSDate date]returns a date object representing the current date and time, no matter where you are. NSDates are not subject to places or time zones. There is just one NSDate that represents now or any other moment for that matter, not different date objects for every time timezone. Therefore, you should not attempt to convert a date between time zones.
NSDate objects represent an absolute instant in time. Consider the following example of how two date representations in different time zones (9/9/11 3:54 PM in Paris and 9/9/11 11:54 PM in Sydney) are actually the same date.
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterShortStyle];
[formatter setTimeStyle:NSDateFormatterShortStyle];
[formatter setTimeZone:[NSTimeZone timeZoneWithName:#"Europe/Paris"]];
NSDate *aDate = [formatter dateFromString:#"9/9/11 3:54 PM"];
[formatter setTimeZone:[NSTimeZone timeZoneWithName:#"Australia/Sydney"]];
NSDate *anotherDate = [formatter dateFromString:#"9/9/11 11:54 PM"];
NSLog(#"%#",anotherDate);
if ([aDate isEqualToDate:anotherDate]) {
NSLog(#"How about that?");
}
When it comes to output a date, bear in mind that NSDate's description method returns time in GMT and you need to use a NSDateFormatter to create a date string representing the local time in Paris, Sydney, etc. from a date:
NSDate *now = [NSDate date];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterShortStyle];
[formatter setTimeStyle:NSDateFormatterShortStyle];
[formatter setTimeZone:[NSTimeZone timeZoneWithName:#"Australia/Sydney"]];
NSLog(#"%#",[formatter stringFromDate:now]); //--> 9/9/11 11:54 PM
[formatter setTimeZone:[NSTimeZone timeZoneWithName:#"Europe/Paris"]];
NSLog(#"%#",[formatter stringFromDate:now]); //--> 9/9/11 3:54 PM
[dateFormatter setDateFormat:#"EEE, d MMM yyyy HH:mm:ss z"];
Remove the trailing 'z' character from the format string if you don't want to display the time zone.
EDIT
On the other hand, if you just want to display the timezone name, just make the 'z' uppercase.
EDIT
Lowercase 'z' works fine for all the other timezones, but unfortunately GMT is a special case. So the easiest thing to do is to just omit the 'z' and append " GMT" to the formatted date.

how to display time and date in a label of selected zone xcode

Can any 1 help me to get this problem done I'm trying to display date and time of selected time zone n a label or text field I tried below code but its Displaying current time of system for all selected zone :( thanks in advance
NSDate *now = [NSDate date];
NSCalendar *gregorian=[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
[gregorian setTimeZone:[NSTimeZone timeZoneWithName:selectedzone]];
NSDateComponents* timeZoneComps = [gregorian components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit|NSHourCalendarUnit|NSMinuteCalendarUnit|NSSecondCalendarUnit|NSTimeZoneCalendarUnit fromDate:now];
NSDate *selectedDate=[gregorian dateFromComponents:timeZoneComps];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterFullStyle];
[formatter setDateFormat:#"dd-MM-yyyy HH:mm:ss "];
NSString *strSelectedDate= [formatter stringFromDate:selectedDate];
zone.text = strSelectedDate;
[NSDate date]returns a date object representing the current date and time, no matter where you are. NSDates are not subject to places or time zones. There is just one NSDate that represents now or any other moment for that matter, not different date objects for every time timezone. Therefore, you should not attempt to convert a date between time zones.
NSDate *now = [NSDate date];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterShortStyle];
[formatter setTimeStyle:NSDateFormatterShortStyle];
[formatter setTimeZone:[NSTimeZone timeZoneWithName:#"Australia/Sydney"]];
NSLog(#"%#",[formatter stringFromDate:now]); //--> 9/9/11 11:54 PM
[formatter setTimeZone:[NSTimeZone timeZoneWithName:#"Europe/Paris"]];
NSLog(#"%#",[formatter stringFromDate:now]);

How to convert to next day when currents date format is "MMM dd, yyyy hh:mm:ss a"?

I have a date in my application which has this format :
"MMM dd, yyyy hh:mm:ss a"
The user chooses a day from a picker and the date is always converted to this format. From this format how can i get the date after exactly 24 hours?
For example if the date is Mon 24 , 2012 17:44:33 i need the code to transform it to Tue 25 , 2012 17:44:33.
Read the Date and Time Programming Guide.
Use a date formatter to generate a date from the string.
Add one day to the date.
Use a date formatter to generate a string from your new date.
Use the following code to create a NSDate from your string:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setTimeZone:[NSTimeZone localTimeZone]];
[dateFormatter setCalendar:[NSCalendar currentCalendar]];
[dateFormatter setDateFormat:<FORMAT_OF_DATE_STRING>];
NSDate *date = [dateFormatter dateFromString:<DATE_STRING>];
[dateFormatter release];
Use the following code to add days to a NSDate:
NSDate *today =<YOUR_DATE>
NSCalendar *gregorian = [[NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar];
/*
Create a date components to represent the number of days to add to the current date.
The weekday value for Sunday in the Gregorian calendar is 1, so add 1 from the number of days to subtract from the date in question. (If today is Sunday, add 0 days.)
*/
NSDateComponents *componentsToAdd = [[NSDateComponents alloc] init];
if(day<7)
{
[componentsToAdd setDay: day];
}
NSDate *calculateDay = [gregorian dateByAddingComponents:componentsToAdd
toDate:today options:0];
Happy coding!
Here is the code you need to set up the date formatter:
NSString *dateString = #"Tue 24 , 2012 17:44:33";
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"EEE dd , yyyy HH:mm:ss"];
NSDate *theDate = [dateFormat dateFromString:dateString];
theDate = [NSDate dateWithTimeInterval:(60*60*24) sinceDate:theDate];
NSString *newDate = [dateFormat stringFromDate:theDate];
NSLog(#"%#",newDate);
The console returns:
2012-07-18 09:26:28.395 TesterProject[71645:f803] Wed 25 , 2012 17:44:33
You really should include a month though, because it will just take the current month if you do not, and that can throw off your day of the week.
I used the actual format of the dates you entered, not the incorrect format that you typed in your question. For information on date formatting here is the unicode standards.
For information on NSDateFormatter here is the Apple documentation: NSDateFormatter.
EDIT: Here is an alternate implementation:
NSString *dateString = #"Tue 24 , 2012 17:44:33";
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"EEE dd , yyyy HH:mm:ss"];
NSDate *theDate = [dateFormat dateFromString:dateString];
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *offsetComponents = [[NSDateComponents alloc] init];
[offsetComponents setDay:1];
theDate = [gregorian dateByAddingComponents:offsetComponents toDate:theDate options:0];
NSString *newDate = [dateFormat stringFromDate:theDate];
NSLog(#"%#",newDate);
It returns the exact same thing.

unexpected result of dateFromComponents:

the following code
NSCalendar *cal = [NSCalendar currentCalendar];
[cal setFirstWeekday:2];
[cal setMinimumDaysInFirstWeek:4];
NSDateComponents *comp = [[NSDateComponents alloc] init];
[comp setYear: 2012];
[comp setMonth:3];
[comp setDay: 12];
NSDate *date = [cal dateFromComponents:comp];
NSLog(#"date:%#",date);
logs:
date:2012-03-11 23:00:00 +0000
Any Idea, why this happen and how to avoid
Tnx
I assume you are using the CET time zone locally. This is what the [NSCalendar currentCalendar] will use as a time zone then.
When you dump a NSDate with NSLog, you will get the date in its raw UTC form. To print the date using a local format, look into the NSDateFormatter class, which has a timeZone property:
....
NSDate *date = [cal dateFromComponents:comp];
NSDateFormatter* fmt = [[NSDateFormatter alloc] init];
fmt.timeZone = [NSTimeZone defaultTimeZone]; // Probably not required
NSLog(#"date:%#", [fmt stringFromDate:date]);
set timezone
NSCalendar *cal = [NSCalendar currentCalendar];
[cal setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"GMT"]];
When you call dateFromComponents: you lose all of the timezone and calendar information and are left an NSDate object that contains the moment in time your date components represent, but nothing else. When you use NSLog on your NSDate object, that moment in time is converted to a time in UTC and rendered as a human readable string.
You need to provide more info about what you're trying to achieve to be able to answer your second question of how to avoid this.