I frequently use the NSDate compare method - but I want to consider two dates similar if they are equal in year, month, day. I have made a procesure called "cleanDate" to remove the hour part before I compare.
-(NSDate*)cleanDate:(NSDate*)date {
NSCalendarUnit unitflags;
NSDateComponents *component;
NSCalendar *calendar;
calendar=[[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]autorelease];
unitflags=NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit;
component=[calendar components:unitflags fromDate:date];
return [calendar dateFromComponents:component]; //Dato uten klokke
}
But my dates come out as:
2011-10-28 22:00:00
and some dates as:
2011-10-28 23:00:00
I want the hour part to be similar, e.g. 00:00.
Whats wrong? Does it have something to do with daylight saving time? Other? Thanks.
-(NSDate*)cleanDate:(NSDate*)date {
NSDateComponents *comps = [[NSCalendar currentCalendar]
components:NSDayCalendarUnit | NSYearCalendarUnit | NSMonthCalendarUnit
fromDate:date];
[comps setHour:0];
[comps setMinute:0];
[comps setSecond:[[NSTimeZone systemTimeZone] secondsFromGMT]];
return [[NSCalendar currentCalendar] dateFromComponents:comps];
}
Seems like this is a Time Zone issue...
I thought NSLog would default to the local time zone - but it seems to default to GMT...
Date with GMT time zone is: Sat, 29 Oct 2011 22:00:00 GMT+00:00
Date with system time zone is: Sun, 30 Oct 2011 00:00:00 GMT+02:00
NSlog shows 2011-10-29 22:00:00 +0000
When using NSLog(#"NSlog shows %#",finalDate); it seems to print the GMT time...
When using this code - I will get the local date in my time zone:
NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
[dateFormatter setDateFormat:#"EEE, d MMM yyyy HH:mm:ss z"];
[dateFormatter setTimeZone:[NSTimeZone systemTimeZone]];
NSString *dateString = [dateFormatter stringFromDate:myDate];
NSLog(#"Date with system time zone is: %#",dateString);
... so my original cleanDate actually seems to do what I want after all...
Related
I am trying to create the NSDate object with date "1 oct 2013 8:00:00". I used the following code
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [[NSDateComponents alloc] init];
[components setYear:2013];
[components setMonth:10];
[components setDay:1];
[components setHour: 8];
[components setMinute: 00];
[components setSecond: 00];
NSDate *date = [calendar dateFromComponents:components];
But when i print the date it gives wrong time "2013-10-01 02:30:00 +0000"
This happens because of time zone: you are in the Indian Standard Time (IST) zone, which lags 5 hours and 30 minutes behind GMT. When you set NSDate to 8:00 from the components, it uses your time zone, so the result gets adjusted to 02:30 so that NSDate has the correct GMT time. If you would like to set the time to 08:00 GMT, set your components' timeZone to GMT:
[components setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"GMT"]];
I'm searching the correct way to get the actual date and time for a given place / timezone, and being able to compare it to a given date/time for that same place.
Let's say, for the example, Paris, that is GMT +1. As we now, Paris can also be GMT+2 because of daylight saving, but it's part of an exception as far as I know so it must be taken in account into the answer, but not taken as a general param. The important words here are "given place".
So, if I want to know what date and time it is at Sidney Australia, or Paris France, and get that date into an NSDate for being able to compare it with another NSDate that would represent another date/time in the same place, how may I do ?
I've read pages and pages of questions and answers with comments, even on accepted answer, that says from experienced users : not a good answer -1, wrong, not the correct way of doing this, absolutely wrong, ...
So, do you know the correct real way to do that ?
In a perfect world, that date/time would be absolute even if the user's phone is not at the good time and/or date and/or timezone, or anything that can be near that perfection without needing for that to connect to a date/time server.
I'm searching the correct way to get the actual date and time for a given place / timezone.
[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?");
}
It logs that last message because 9/9/11 3:54 PM in Paris and 9/9/11 11:54 PM in Sydney are actually the same instant in time. When it is 9/9/11 3:54 PM in Paris, it is 9/9/11 11:54 PM in Sydney.
both gives in the debugger and NSLog 2011-09-09 14:26:02, but it's now 16:26 so I guess it should return 16:26:02 +0200
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
ok, but if I want to know if that time is after 15:00, how may I test that ?
Create an NSDate object that represents today at 15:00 (local time) and compare it to "now":
NSDate *now = [NSDate date];
NSCalendar* myCalendar = [NSCalendar currentCalendar];
NSDateComponents* components = [myCalendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit
fromDate:[NSDate date]];
[components setHour: 15];
[components setMinute: 0];
[components setSecond: 0];
NSDate *todayAt15 = [myCalendar dateFromComponents:components];
if ([now compare:todayAt15] == NSOrderedDescending) {
NSLog(#"After 15:00 local time");
}
It turns out #Oliver needed to check if it is after 15:00 in Paris so he needed to create a date that represents today at 15:00 Paris time (not local time). For an example on how to do that, see #Oliver's answer. Just to be clear, my third snippet of code shows how to check if it is after 15:00 local time.
After a big headache and starting to understand what NSDate is, I imagined that kind of solution. What do you think about that way of doing ?
// Now, an absolute date and time that represent now all around the world, that is made to play with
NSDate *now = [NSDate date];
// A specific calendar for a specific place in the world
NSCalendar* parisCalendar = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
[parisCalendar setTimeZone:[NSTimeZone timeZoneWithName:#"Europe/Paris"]];
// Now components seen from Paris
NSDateComponents* componentsNowInParis = [parisCalendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit|NSHourCalendarUnit|NSMinuteCalendarUnit|NSSecondCalendarUnit|NSTimeZoneCalendarUnit fromDate:now];
// Tricking a copy of "Now components seen from Paris" to force 15:00:00, in Paris
NSDateComponents* componentsInParisAt15 = [[componentsNowInParis copy] autorelease];
[componentsInParisAt15 setHour:15];
[componentsInParisAt15 setMinute:0];
[componentsInParisAt15 setSecond:0];
// Getting an universal date reference that represent what could be 15:00:00 seen from paris, Or 19:00:00 from GMT+4
NSDate* dateAt15 = [parisCalendar dateFromComponents:componentsInParisAt15];
// We now have two universal dates that can be compared each other
// If "now" is 16:00:00, those date will show a 60 minutes difference all around the world
NSLog(#"%#", now);
NSLog(#"%#", dateAt15);
Some reference : http://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/DatesAndTimes/Articles/dtTimeZones.html#//apple_ref/doc/uid/20000185-SW4
But, as far as I know and tested, that day/time cannot be really absolute. It is based on the iPhone date/time/timezone, that can be wrong.
Use NSCalendar, and the setTimeZone method.
NSDate *newDate;
NSDateComponents *dateComponents = [[NSCalendar currentCalendar] components:~ NSTimeZoneCalendarUnit fromDate:[NSDate date]];
newDate = [[NSCalendar currentCalendar] dateFromComponents:dateComponents];
NSLog(#"newDate: %#", newDate);
NSLog(#"newDate: %.0f", [newDate timeIntervalSinceReferenceDate]);
newDate: 2011-09-09 15:02:09 +0000
newDate: 337273330
[dateComponents setTimeZone:[NSTimeZone timeZoneWithName:#"Australia/Sydney"]];
newDate = [[NSCalendar currentCalendar] dateFromComponents:dateComponents];
NSLog(#"newDate: %#", newDate);
NSLog(#"newDate: %.0f", [newDate timeIntervalSinceReferenceDate]);
newDate: 2011-09-09 00:52:03 +0000
newTimeInterval: 337222930
[dateComponents setTimeZone:[NSTimeZone timeZoneWithName:#"Europe/Paris"]];
newDate = [[NSCalendar currentCalendar] dateFromComponents:dateComponents];
NSLog(#"newDate: %#", newDate);
NSLog(#"newDate: %.0f", [newDate timeIntervalSinceReferenceDate]);
newDate: 2011-09-09 08:52:03 +0000
newTimeInterval: 337251730
This question follows on from a previous question...
How do I create the current date (or any date) as an NSDate without hours, minutes and seconds?
I would use this code as follows...
NSDate *todaysDate = [General makeAbsoluteNSDate:[NSDate date]];
My problem is that I have users in different countries and UTC isn't their timezone and the date produced by this function at certain times of the day won't be correct.
How do I get the current time zone to correct my function ?
Or should I be using a different approach ?
Heres the function I've been using...
+ (NSDate *)makeAbsoluteNSDate:(NSDate*)datSource {
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:
NSGregorianCalendar];
[calendar setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"UTC"]];
NSDateComponents *dateComponents = [calendar components:NSYearCalendarUnit |
NSMonthCalendarUnit | NSDayCalendarUnit
fromDate:datSource];
[dateComponents setHour:0];
[dateComponents setMinute:0];
[dateComponents setSecond:0];
NSDate *midnightUTC = [calendar dateFromComponents:dateComponents];
[calendar release];
return midnightUTC;
}
You get the timezone object from this call:
[NSTimeZone localTimeZone]
And you can use the secondsFromGMT method to figure out the difference and create a date with the timezone.
You can even build a Category for NSDate that includes a method to transform a date into the current timezone date, which would be even simpler.
I used NSDateComponents to find date for 4th, 2nd day of the week like this
NSDate *today = [NSDate date];
NSCalendar *gregorian = [[NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *weekdayComponents = [gregorian components:(NSDayCalendarUnit |
NSMonthCalendarUnit |
NSYearCalendarUnit |
NSWeekCalendarUnit |
NSWeekdayCalendarUnit)
fromDate:today];
[weekdayComponents setWeekday:4];
NSLog(#"Date at that day was %#",[gregorian dateFromComponents:weekdayComponents]);
but every time the output is
Date at that day was 2011-06-20 18:30:00 +0000
Can you help in this
Thanks in advance
[weekdayComponents setDay:weekdayComponents.day+ (4-weekdayComponents.weekday)];
As for the NSlog output: NSLog (#"%#", somedate) displays the time in GMT0, but actions with NSDateComponents made taking into account time zone, so 2011-06-20 18:30:00 +0000 is beginning оf 21.06.2011 in your time zone
Alright I've given up on this. Here's what I'm trying to do: I have a sunrise, sunset, and the current time in a certain timezone. I want to know if it's day or night by figuring out if the current time lies between the sunrise and the sunset times.
Here's what I have:
NSLog(#"%# - %# - %#",currTime,sunrise,sunset);
NSDateFormatter *formatter1 = [[NSDateFormatter alloc]init];
NSDateFormatter *formatter2 = [[NSDateFormatter alloc]init];
[formatter1 setDateFormat:#"hh:mm a"];
[formatter2 setDateFormat:#"EEE, dd MMM yyyy h:mm a z"];
NSDate *rise = [formatter1 dateFromString:sunrise];
NSDate *set = [formatter1 dateFromString:sunset];
NSDate *time = [formatter2 dateFromString:currTime];
[formatter1 release];
[formatter2 release];
unsigned int flags = NSHourCalendarUnit | NSMinuteCalendarUnit;
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components1 = [calendar components:flags fromDate:rise];
NSDateComponents *components2 = [calendar components:flags fromDate:set];
NSDateComponents *components3 = [calendar components:flags fromDate:time];
NSDate *Sunrise = [calendar dateFromComponents:components1];
NSDate *Sunset = [calendar dateFromComponents:components2];
NSDate *Time = [calendar dateFromComponents:components3];
NSLog(#"\nSunrise: %# \nSunset:%# \nTime:%#",rise,set,time);
NSLog(#"\nSunrise: %# \nSunset:%# \nTime:%#",Sunrise,Sunset,Time);
Here's the first output:
Fri, 10 Jun 2011 4:00 am SAST - 7:46 am - 5:41 pm
And here's the second (before making it only concerned about the time, not date)
Sunrise: 1969-12-31 22:46:00 +0000
Sunset: 1970-01-01 08:41:00 +0000
Time: 2011-06-10 02:00:00 +0000
And finally here is the last output (notice how the times are messed up?):
Sunrise: 0001-12-31 22:27:01 +0000
Sunset: 0001-01-01 08:22:01 +0000
Time: 0001-01-01 01:41:01 +0000
So I wanted to pop those resulting dates into my method that checks whether it's in between the dates:
+(BOOL)date:(NSDate*)date isBetweenDate:(NSDate*)beginDate andDate:(NSDate*)endDate {
return (([date compare:beginDate] != NSOrderedAscending) && ([date compare:endDate] != NSOrderedDescending));
}
However, until I get the date problem figured out that method won't work. :/ I need help! What am I doing wrong?
Ok, so I gave up on trying to get NSDates to work for me. The timezone issues just killed my brain for the weekend. Anyway, I decided to use BoopMeister suggestion, but it doesn't work quite like I expect. Here's an example:
Using the setup from above, I added these lines:
NSInteger riseHour = [components1 hour];
NSInteger setHour = [components2 hour];
NSInteger timeHour = [components3 hour];
NSLog(#"Rise: %i Set: %i Time: %i",riseHour,setHour,timeHour);
Now, when I plug in these variables:
Current time: Fri, 10 Jun 2011 9:07 am CDT
Sunrise: 6:33 am
Sunset: 8:32 pm
However, when I output the strings from the methods above here's what I get:
Rise: 6 Set: 20 Time: 23
What the?
I would use the components you already have and not make new dates.
Starting at this point in your code:
NSDateComponents *riseComponents = [calendar components:flags fromDate:rise];
NSDateComponents *setComponents = [calendar components:flags fromDate:set];
NSDateComponents *timeComponents = [calendar components:flags fromDate:time];
And then something like
NSInteger riseHour = [riseComponents hour];
NSInteger setHour = [setComponents hour];
NSInteger timeHour = [timeComponents hour];
// Do some checks here
// If necessary do the same for the minutes ([components minute])
Comparing dates has been a performance issue in my app and since you already have the dateComponents it would be faster to make your own check and use the NSIntegers.
Okay, so as can be seen in the question, it gives the numerical presentation of the hours. Same works for the minutes. Build your checks after that.
What probably is the problem with the current time, is the calendar you use. It automatically converts the time to the time in the timezone of the calendar you use. You can also create a calendar with a string representation of the timezone. It's in the API of NSCalendar I think. Then after you made that calendar, then use that one for the current time.
One of the key things about NSDate is that it is in GMT. Always. However when you log it, it prints according to the user's locale.
Now when you do,
NSDateFormatter *formatter1 = [[NSDateFormatter alloc]init];
[formatter1 setDateFormat:#"hh:mm a"];
NSDate *rise = [formatter1 dateFromString:sunrise];
NSDate *set = [formatter1 dateFromString:sunset];
[formatter1 release];
You are just providing information about hour, minute and whether it is AM/PM. How is it to know which day the time belongs to. It fills this lack of information by defaulting to 01/01/1970 and timezone based on the user's locale. You do provide the timezone information in the current time which might or might not be the same as the user's locale.
To fix this, you must generate a string that includes the date and timezone info for the sunset time and pass it to the date formatter with the correct format to get the date. I am assuming you must've this (or how else will you know that it is the sunset or sunrise time for that day?). Since you know the place you should be able to get the timezone info as well. Once you've the correct information to build the dates with, every comparison method that you've used will work.