Setting an NSDate to specific date, time and timezone - iphone

I need to set a NSDate to a specific date, time and timezone for an iPhone App.
The example code below works fine on iOS 4 as the setTimeZone was introduced with iOS 4. How could I easily set a NSDate to a date, time and timezone without using setTimeZone so it can be used on iOS 3.0 devices?
NSDateComponents *comps = [[NSDateComponents alloc] init];
[comps setYear:2010];
[comps setMonth:8];
[comps setDay:24];
[comps setHour:17];
[comps setMinute:5];
[comps setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"UTC"] ];
NSCalendar *cal = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDate *referenceTime = [cal dateFromComponents:comps];
Guess this should be simple, but somehow NSDate, components and calendars and I are not good friends...

I wonder if you could set the time zone on the NSCalendar object that you use to create the NSDate from the NSDateComponents. I haven't tried this and don't know if it'll work, but it's probably worth a try.

NDates have no concept of time zones in and of themselves. They're basically seconds since a certain arbitrary date at GMT. As such, you can't give them a time zone. If time zone is important, you'll need to track both the time and the time zone.

Related

Find continuous days the app is used

I am developing one ios app now. I have feature in which i have to display a continuous days the app is used.
Means if i use app for 3 days constantly i have to display 3.
And if i have not used it for one day. The counter should reset.
I am using this function to calculate days.
- (int)daysBetween:(NSDate *)dt1 and:(NSDate *)dt2 {
NSUInteger unitFlags = NSDayCalendarUnit;
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [calendar components:unitFlags fromDate:dt1 toDate:dt2 options:0];
return [components day];
}
I am saving last used date. and pass two parameter last used date and current date in it.
But by this function if i used app at 11.30 PM and again used it at 1.00 AM it will not increment day.
You get this because you are not considering the time part of the dates, you need to use rangeOfUnit:.
I suggest to use the #Brain functions mentioned in this SO question:
Number of days between two NSDates

Struggling with NSDate, formats and timezones

The deal is I want a NSDate representation of the date 18th of June 1978.
I have tried to init NSDate like
dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
self.dateFormatter.timeStyle = NSDateFormatterNoStyle;
self.startDate = [dateFormatter dateFromString:#"19/06/78"];
NSLog(#"%#", self.startDate);
This produces the right date when the iPhone is set to Danish in the International settings.
It does not work with a iPhone set to i.e. english/american settings.
Notice the extra day (19) because denmark is in GMT +1 and i think the NSDate defaults to time 23:00:00. That indicates that something i not working as intended.
I want the above date (18/06/1978) represented a an NSDate object regardless of the timezone, locale and International settings on the device.
How to achieve that?
Edit:
So Ole Begemann's answer seemed to resolve my issue. His solution did create the correct date both on a device in USA International settings and en European international settings.
But when Apple should review the app the date created was 17th of June 1978. This makes sence since I'm setting timezone to GMT +0000. And Cupertino is like GMT -0007 or so.
So this would give a day earlier.
So to correct my question: I want the 18-06-1978 no matter what locale, timezone the device is physically or settings wise in.
What I'm trying to do is setting a start date 18. june 1978 and later in my app render the date as a string formatted like "780618" (yyMMdd) regardless of the timezone or place of the device. It allways has to be "780618" as this is a key start date for my app.
So I might be attending the problem wrong. Instead of trying to force same date everywhere I maybe should accept the timezone stuff and try to configure the NSDateFormatter to output the right date.
So basically: What I want is THE NSDate instance that formats to "780618" everywhere - in any timezone with any international device settings.
How to achieve this?
I want the above date (18/06/1978) represented a an NSDate object regardless of the timezone, locale and International settings on the device.
This makes no sense to NSDate. An NSDate always represents a single point in time, so by definition it includes a time and the time zone this time is in (or to be more exact, it stores the time in GMT; the time is only converted to another time zone for display purposes). If you just want the date, you have to make your own definition regarding the time, e.g. to store these dates with a time of midnight GMT.
When setting a date programmatically, you must always set a time zone and, if you use a date formatter, set the formatter's locale and calendar. This ensures that your code is independent of the user's/device's locale settings.
I would do it like this:
NSDateComponents *dateComponents = [[NSDateComponents alloc] init];
[dateComponents setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
[dateComponents setYear:1978];
[dateComponents setMonth:6];
[dateComponents setDay:18];
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDate *date = [calendar dateFromComponents:dateComponents];
NSLog(#"%#", date);
You can do like this:
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
// Set the locale to en_US_POSIX. This makes the date formatter respect
// the format string regardless of the user's locale.
NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"];
[formatter setLocale:locale];
[locale release];
// We want the date in the user's current time zone.
[formatter setTimeZone:[NSTimeZone localTimeZone]];
[formatter setDateFormat:#"dd/MM/yy"];
NSDate *date = [formatter dateFromString:#"18/06/78"];
[formatter release];
NSLog(#"%#", date);
That the date is shown like this 1978-06-17 23:00:00 +0000 is because NSDate's description returns the date in GMT. 17th of June 1978 at 23:00 is 18th of June 1978 00:00 in GMT+1.

How to Convert a Double value into Date value in Objective-C

I have to convert a Double value into a Date value in Objective-C
I tried many ways but im not getting it.
date=var1/24;
Here var1 is a double value which should be divided by 24 and stored as a Date into the variable date. How can I do this using Objective-C?
I created the date variable like this:
NSDate *date=[[NSDate alloc]init];
date=(nsdate)var1/24;
How can I do this?
Its a Double Variable.. which will be containing values upto 24 it will be representing HOURS from TODAY..
OK, so you have a relative value that you want to add to an absolute value. Additional work is required.
First, you must decide "What is today?". Is it 12:01am? If it is, in which time zone? GMT? Something else? You have to know this, because 12:01am GMT is not the same thing as 12:01am EDT. So: what is today?
Once you've decided where you're going to be measuring time from, you have to construct an NSDate representing that point in time.
For example:
NSDate *rightNow = [NSDate date];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [calendar components:NSUIntegerMax fromDate:rightNow];
This will give you an NSDateComponents object, which is an object that represents a point in time relative to a calendar. In this case, we're using the "current calendar" (probably the Gregorian calendar, but not necessarily), and the default time zone is your current time zone. If you need to have it be relative to a different time zone, you can create a new NSTimeZone object and use -[NSCalendar setTimeZone:] to set the calendar's time zone (before asking for the date components).
Now that you've got the date components, we can "reset" things to the appropriate time:
[components setHour:0];
[components setMinute:0];
[components setSecond:0];
Then we can turn it back into an NSDate to make it an absolute point in time:
NSDate *startingPoint = [calendar dateFromComponents:components];
NOW we have our starting point, and can deal with the "hours from today". First, we'll create a date components object to represent however many hours the difference is:
NSInteger hourDelta = var1 / 24;
NSDateComponents *delta = [[NSDateComponents alloc] init];
[delta setHour:hourDelta];
Now, we'll add this relative difference to our absolute starting date:
NSDate *finalDate = [calendar dateByAddingComponents:delta toDate:startingPoint options:0];
And because we're good citizens, we'll clean up our memory (unless you're using Garbage Collection or compiling with ARC):
[delta release];
Some important notes:
All of the manipulations are done via the NSCalendar object, because the NSCalendar is what defines what a "day" means and what an "hour" is. You think "there are 24 hours in a day and 60 minutes in an hour...", but that's not necessarily true. I can create my own calendar that has 10 hours in a day, and 10 minutes in an hour. If I want, I can define a "day" as something other than "one full rotation of the Earth". The NSCalendar define all these rules. Thus, all relative manipulations of dates (adding "hours" and "days" or whatever) must be done via the calendar.
There are methods on NSDate like -dateByAddingTimeInterval:, but this is for when you're dealing with absolute intervals and not relative amounts.
It depends of what you want to do exactly, but a direct cast as (nsdate)var1/24 will definitely NOT work!!!
Anway, what does your variable var1 represent exactly? Minutes ? Seconds ? Hours ? From which reference date? Today? The UNIX Epoch? Is it a UNIX timestamp (seconds since 01/01/1970)? Just asking to "convert a number to a date" means nothing on its own ;-)
Depending on the answer to those questions, you may use either NSDateComponents to produce a date giving the different date components (month, day, hours, minutes, seconds, …), or create a NSDate from a UNIX timestamp using dateWithTimeIntervalSince1970... or use any other method from NSDate or NSDateComponents depending on your needs.
Whatever your problem is, do read* the Date and TIme Programming Guide!! Everything is explained here about date manipulation; it will contain everything you need to answer your question.

Does NSTimeZone in iPhone adjust automatically for DST

I have a fairly simple question. I have a set of dates in UTC. I want to represent these to the user in the correct local time adjusted (or not, if DST is not currently in effect) for DST.
So, if I do something such as the following, will timeStamp be set correctly to the local time in New York taking DST into account when in effect
NSDate *date = initialise with a UTC time
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:#"America/New_York"];
[formatter setTimeZone:timeZone];
[formatter setDateFormat:#"yyyy-MM-dd HH:mm:ss"];
NSString *timeStamp = [formatter stringFromDate:date];
Or so I need to do something else? Do I check NSTimeZone.isDaylightSavingTime/NSTimeZone.daylightSavingTimeOffset and adjust my date accordingly or anything like that?
Thanks in advance?
Twibbles.
Yes, NSDateFormatter will automatically adjust for DST if you create the timeZone with [NSTimeZone timeZoneWithName]. NSTimeZone knows the DST rules for each time zone and can look into the future and the past and will do the right thing for the NSDate passed to stringForDate. However, if you create the NSTimeZone with [NSTimeZone timeZoneForSecondsFromGMT] DST adjustments are not made. It should also be noted that DST rules are subject to change, which means NSTimeZone is not guaranteed to always do the right thing for all time zones.
You do not need to use NSTimeZone.isDaylightSavingTime or NSTimeZone.daylightSavingTimeOffset to format an NSDate as DST correct local time. Both of those methods operate on the current time. If you want to know if an NSDate falls within DST in a timezone you can use the NSTimeZone.isDaylightSavingTimeForDate method and if you want to know what the DST offset is for an NSDate you can use the NSTimeZone.daylightSavingTimeOffsetForDate method.

In Cocoa, how do I use NSTimeZone to get the system time zone offset as a string?

For PDT, I would want "-0700".
I'm getting a date in the past to determine how long ago something happened.
NSDate *then = [NSDate dateWithString:#"1976-04-01 12:34:56 -0700"]; // Note the hard-coded time zone at the end
I'll be constructing the date string elsewhere but I don't know how to access the local time zone.
I read the Apple Dates and Times Programming Topics for Cocoa as well as the NSTimeZone and NSDate Class References but it's just too hard for me to put the information together. I could really use a few lines of code just to show how it's used.
Update: While struggling with this, I was writing code using a Command Line template so I could try things quickly. I just tried my previous code on iPhone and I'm getting NSDate may not respond to '+dateWithString:' Sorry if that added to the confusion, who knew Apple would change up such a basic class.
Use NSDateFormatter to build NSDate from a string:
NSDateFormatter *inputFormatter = [[NSDateFormatter alloc] init];
[inputFormatter setDateFormat:#"yyyy-MM-dd HH:mm:ss Z"];
NSDate *formatterDate;
formatterDate = [inputFormatter dateFromString:#"1976-04-01 12:34:56 -0700"];
NSString *dateString = [inputFormatter stringFromDate:formatterDate];
NSLog(#"date:%#", dateString);
This way you get the local time from string, for example the date specified by the string:
"1976-04-01 12:34:56 -0700"
is in time zone -0700, (I'm in time zone GMT +1000) so I get:
2009-11-17 22:13:46.480
cmdline[10593:903] date:1976-04-02
05:34:56 +1000
The time zone offset is dependent on the date in much of the world—those parts of it that use Daylight-Saving Time/Summer Time.
The only correct way is to generate the entire string from date and time-zone together. Use NSDateFormatter for this.
The best way is to probably use a simple calendar formatter
NSCalendarDate * date = [NSCalendarDate calendarDate];
[date setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"PDT"]];
NSLog([date descriptionWithCalendarFormat:#"%z"]);
which will output '-0700'
or leave out the second line if you want the current time zone of the system (not sure which you were asking for)