I have a NSDate object. Let's say it represents "1-10-2011"
NSDate *date = [df dateFromString:#"2011-10-01 00:00:00"];
That date translates into "2011-09-30 22:00:00" because of my timezone.
Question: How do I get a new Date object representing "2011-10-01 00:00:00" in my local timezone?
NSDate only represents an absolute point in time. It has no concept of timezone or calendar. When you create a NSDate instance it is just a number of seconds since January 1st 2001 GMT! It does not matter if you are in New York, Tokyo, Barcelona or Jerusalem.
At your example, you instance the NSDate based on GMT, but [date description] (used in NSLog) translates it into your local time. There you have the mismatch.
So there are two parts to consider:
1. NSDate creation using NSCalendar and NSTimeZone
If you are creating a date manually you should specify the calendar (2012 in Gregorian, but 5772 in Hebrew) and time zone (22PM London time, but 7AM Sydney time).
// Use the user's current calendar and time zone
NSCalendar *calendar = [NSCalendar currentCalendar];
[calendar setTimeZone: [NSTimeZone systemTimeZone]];
// Specify the date components manually (year, month, day, hour, minutes, etc.)
NSDateComponents *timeZoneComps=[[NSDateComponents alloc] init];
[timeZoneComps setHour:22];
[timeZoneComps setMinute:0];
[timeZoneComps setSecond:0];
// ... year, month, ...
// transform the date compoments into a date, based on current calendar settings
NSDate *date = [calendar dateFromComponents:timeZoneComps];
At this point date stores the exact point in time (in seconds) representing the current calendar.
2. NSDate output using NSDateFormatter
For a controlled output of your NSDate you need NSDateFormatter, which is used to convert dates into strings.
Based on Apple NSDateFormatter Class Reference documentation
There are many attributes you can get and set on a style date
formatter, ...
You are encouraged, however, not to change individual settings. Instead you should accept the default settings established on initialization and specify the format using setDateStyle:, setTimeStyle:
This is specially important for the output, which is different for every locale. By default NSDateFormatter observes the current user’s locale settings. So the same NSDate could be 22.11.2011 18:33:19, or Nov 22, 2011 6:33:19 PM, or 2011-11-22 下午6:33:19 or even २२-११-२०११ ६:३३:१९ अपराह्, all for the same input and with the same code.
And the code:
// NSDate *date -> NSString *dateString
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
[dateFormatter setTimeStyle:NSDateFormatterShortStyle];
// Medium style date, short style time => "Nov 23, 1937 3:30pm"
NSString *dateString = [dateFormatter stringFromDate:date];
Or you could transform it using the class method localizedStringFromDate:dateStyle:timeStyle:
I hope this clarifies the problem.
[NSDate date] returns the date in GMT.
When you state:
That date translates into "2011-09-30 22:00:00" because of my
timezone.
Is that from NSLog or NSDateFormatter? Don't rely in [date description] which NSLog uses, it takes into account your local timezone, use NSDateFormatter. NSDateFormatter has a setTimeZone method.
From Apple docs on [date description]:
The representation is not guaranteed to remain constant across
different releases of the operating system. To format a date, you
should use a date formatter object instead
Related
This question already has answers here:
How do I add 1 day to an NSDate?
(30 answers)
Closed 10 years ago.
Here is the code from where I can get todays date as a string:
NSString *string;
NSDateFormatter *formatter;
string = [formatter stringFromDate: [NSDate date]];
formatter = [[[NSDateFormatter alloc] init] autorelease];
[formatter setDateFormat: #"yyyy-MM-dd "];
string = [formatter stringFromDate: [NSDate date]];
But now I want such that I will put this string as a parameter and a method will return the date of the day after 10 days of this date as a string. But I couldn't find any solution for it. Can anybody help me?
My answer will be a bit longer and probably slightly OT but I think it is better to provide you a knowledge of the concepts inside date management instead of a "copy and paste" answer.
Date management in fact even if intuitive is a quite complex task. In order to do this properly with Cocoa you must understand a few basic concepts.
The "date" concept itself is just a numerical representation of how many seconds elapsed from a reference date. This is an absolute measure and nothing can change it: if you say that now is time 0, in 10 seconds it will be time 10, and so on. It is represented by Cocoa with "NSDate".
Now to translate the "numerical date" to a "calendar date" you need to apply this numerical date to a "calendar" ("NSCalendar" Cocoa class). Clearly there are many types of calendars around so what you have to do is to pick the right calendar you want to use and then apply the numerical date to it: the effective result will be a "calendarized date". Note that the same "numerical date", which is common to all calendars as it is an absolute measure, will provide different results on different calendars. A calendar is all in all a complex algorithm or table that maps every single numerical date to a specific "calendar date".
The components that make a calendar date are called "date components" and are represented by the Cocoa class "NSDateComponents". As you may have understood, you cannot directly put in relation a "Date component" with a "Date" but you need to mediate them through the "Calendar". That's why all methods that put in relation the "Date" and "NSDateComponents" classes are defined in the "NSCalendar" class and this explains why a specific "NSDateComponents" instance is associated to a specific "NSCalendar" instance.
Finally your last step is to convert the "date component" to a "human readable format". To do this you use the "NSDateFormatter" object. While it would be more appropriate to link the date formatter to the date components, in order to facilitate the translation from a date to a string and vice versa NSDateFormatter methods play directly with NSDate objects instead of NSDateComponents. Obviously the NSDateFormatter class must be associated to a specific calendar (and be careful: it is initialized with a default calendar).
Now that you have this baggage of information you can easily understand how to proceed. Your task is to convert a date in "string format" to a date, in the same format, after 10 days.
So the tasks to be accomplished are (the code is below):
1. identify the Calendar you want to use
2. create a NSDateFormatter that accepts your input string and link the Calendar to it
3. use NSDateFormatter to import the string to a "NSDate"
4. use the NSCalendar to convert the date to a NSDateComponents object
5. add 10 days to the "day" component of NSDateComponents; don't take care of "end of month" or "end of year", because NSDateComponents + NSCalendar know how to do it!
6. use NSCalendar again to convert the new recalculated NSDateComponents instance to NSDate
7. use the NSDateFormatter you defined before to convert the new NSDate to a NSString.
You may ask: why I cannot just sum to my imported NSDate 10*24*60*60 seconds? while in most cases this solution will work, there are some cases where this operation will provide an incorrect result. E.g. in the daylight saving switch you revert the clock by 1 hour, that is 60*60 = 3600 seconds. This means that in your Calendar a 1 hr range of seconds will be mapped to two different date/times (1 hr before and 1 hr after the switch). This information is not known to NSDate but it is known by NSCalendar. You can visually see what's happening in this way: imagine an infinitely long line (the line of time) where every single "tick" in the line is 1 second. If you keep the "point in time" where you are now this tick will be associated to a specific date and time in your calendar and clock. Imagine now to identify the point in this timeline where you do the daylight saving switch and suppose you need at that time to revert your clock to 1 hour before. What you do is to cut the timeline in two pieces, then take the second half and overlap its first hour with the last hour of the first half. You will see then that the time is still going on but your calendar in this 1 hour overlap will be associated to two given range of times! this is an information known to your calendar + locale + time zone only, not to NSDate alone (by the way I intentionally skipped any discussion here about the "time zones" and "locale": they're relevant because time zone takes care of associating an absolute time to a effective time of day, while the locale can change some calendar rules, e.g. the daylight saving switch).
NSString *startDateStr = #"2013-02-25";
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.calendar=calendar;
[dateFormatter setDateFormat:#"yyyy-MM-dd"];
NSDate *startDate = [dateFormatter dateFromString:startDateStr];
NSDateComponents *startComponents = [calendar components:NSDayCalendarUnit|NSMonthCalendarUnit|NSYearCalendarUnit fromDate:startDate];
startComponents.day+=10;
NSDate *endDate = [calendar dateFromComponents:startComponents];
NSString *endDateStr = [dateFormatter stringFromDate:endDate];
NSLog(#"Date %# + 10 days gives %#",startDateStr,endDateStr);
Note that the above calculations could have been simplified using the NSCalendar's dateByAddingComponents:toDate:options: but I preferred the first method to give you a better picture of the interaction between the classes.
NSDate *now = [NSDate date];
NSDate *newDate1 = [now dateByAddingTimeInterval:60*60*24*10];
This will return date after 10 days.
Convert your fromDate string to a Date type and use the below function and pass the days parameter as 10:
NSString *fromDateString = #"Your_date_string";
// Convert string to date object
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"YOUR_DATE_FORMAT"];
NSDate *fromDate = [dateFormat dateFromString:dateStr];
[dateFormat release];
+ (NSDate *) getDate:(NSDate *)fromDate daysAhead:(NSUInteger)days
{
NSDateComponents *dateComponents = [[NSDateComponents alloc] init];
dateComponents.day = days;
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDate *previousDate = [calendar dateByAddingComponents:dateComponents
toDate:fromDate
options:0];
[dateComponents release];
return previousDate;
}
Code for 10 days after date ::
NSDateFormatter *entryDateFormat;
entryDateFormat = [[NSDateFormatter alloc]init];
[entryDateFormat setDateFormat:#"dd-MM-yyyy HH:mm:ss"];
NSString *s = [NSString stringWithFormat:#"%#", [entryDateFormat stringFromDate:[[NSDate date] dateByAddingTimeInterval:60*60*24*10]]];
NSLog(#" --> %#", s);
Any way to get timezone abbreviation(e.g UTC, EET) from NSDate? I'm getting NSDate from string, e.g 2012-08-26 02:54:50 +0200 and need to show timezone of this date.
Currently doing that:
NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease];
[formatter setDateFormat: #"yyyy-MM-dd HH:mm:ssZZZ"];
NSDate *isoDate = [formatter dateFromString: isoTime.value];
NSInteger offset = [[NSTimeZone defaultTimeZone] secondsFromGMTForDate: isoDate];
NSTimeZone *timeZone = [NSTimeZone timeZoneForSecondsFromGMT: offset];
But I'm getting GMT+03:00 for timeZone abbreviation, but it should be EET. Any way to get it?
An NSDate is time zone independent; it doesn't inherently have a time zone. You therefore can't get a time zone from it.
secondsFromGMTForDate: returns the offset of that time zone (the default one, in your case) from GMT at the specified date. It's returning information about the NSTimeZone which may depend on the date (eg, if your time zone honours daylight savings), not about the date.
I have an app that displays a timetable of certain ferry trips.
If I travel to a different timezone - say 4 hours behind, a 10am ferry trip now shows up as 6am?
I know this has got to do with how dates are treated based on their timezones, but I can't work out how to change that behaviour.
At the moment here's how I am getting the date and displaying it on a UILabel:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"HH:mm"];
[self.departureTime setText:[dateFormatter stringFromDate:[self.route objectForKey:#"departureTime"]]];
[self.arrivalTime setText:[dateFormatter stringFromDate:[self.route objectForKey:#"arrivalTime"]]];
[dateFormatter release];
Thanks in advance for your help.
You'll need to store the timezone that the ferry ride is taking place in and format it for that timezone.
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"HH:mm"];
NSDate *now = [NSDate date];
NSLog(#"now:%#", [dateFormatter stringFromDate:now]);
NSTimeZone *timeZone = [NSTimeZone timeZoneForSecondsFromGMT:(-8 * 3600)];
[dateFormatter setTimeZone:timeZone];
NSLog(#"adjusted for timezone: %#", [dateFormatter stringFromDate:now]);
Outputs:
2011-10-10 20:42:23.781 Craplet[2926:707] now:20:42
2011-10-10 20:42:23.782 Craplet[2926:707] adjusted for timezone: 16:42
You have seen NSDateFormatter's setTimeZone method, yes?
http://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSDateFormatter_Class/Reference/Reference.html#//apple_ref/occ/instm/NSDateFormatter/setTimeZone:
(b.t.w., I'd be amazed if there was a ferry that involved crossing four time zones; sounds like a cruise ship itinerary to me)
You can also use the NSDateComponents class as described by apple's reference:
If you need to create a date that is independent of timezone, you can store the date as an NSDateComponents object—as long as you store some reference to the corresponding calendar.
In iOS, NSDateComponents objects can contain a calendar, a timezone, and a date object. You can therefore store the calendar along with the components. If you use the date method of the NSDateComponents class to access the date, make sure that the associated timezone is up-to-date.
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/DatesAndTimes/Articles/dtTimeZones.html#//apple_ref/doc/uid/20000185-SW1
Don't confuse an NSDate value with a formatted output like NSLog. NSDate is GMT, Apple's docs:
The sole primitive method of NSDate, timeIntervalSinceReferenceDate,
provides the basis for all the other methods in the NSDate interface.
This method returns a time value relative to an absolute reference
date—the first instant of 1 January 2001, GMT.
NSTimeInterval referenceInterval = [[dateFormatter dateFromString:#"1 January 2001 GMT"] timeIntervalSinceReferenceDate];
NSLog(#"referenceInterval: %f", referenceInterval);
NSTimeInterval estInterval = [[dateFormatter dateFromString:#"1 January 2001 EST"] timeIntervalSinceReferenceDate];
NSLog(#"estInterval: %f", estInterval);
Output:
referenceInterval: 0.000000
estInterval: 18000.000000
NSDate *currentDateTime = datePicker.date;
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"EEE,MM-dd-yyyy HH:mm:ss"];
NSString *dateInStringFormated = [dateFormatter stringFromDate:currentDateTime];
NSLog(#"%#", dateInStringFormated);
Why would this code be giving me GMT? (I am in US Mountain Time)
NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
[dateFormatter setDateStyle:NSDateFormatterLongStyle];
[dateFormatter setTimeStyle:NSDateFormatterLongStyle];
[dateFormatter setLocale:[NSLocale currentLocale]];
NSDate *now = [NSDate date];
NSString *storeTime = [dateFormatter stringFromDate:now];
An NSDate represents a concrete point in time, regardless of the timezone. Put another way, an NSDate does not have a timezone. Timezones are only relevant when you want to display the date to the user. So 9:30pm in Mountain Time is 3:30am (+1 day) in GMT (assuming a 6 hour time difference).
NSDate, since it does not have a timezone, must pick one when producing a human-readable version to return as its -description. To make things simple, it always returns a date formatted in the GMT time zone. If you would like the date formatted to be in a different timezone, you can set the -timezone property of an NSDateFormatter, and then convert the date into a string using the -stringFromDate: method.
Yes, turns out this was a bug in Apple's Numbers on the Mac. Numbers was not interpreting the date string, or rather it was adding the time offset. The NSDate string, after formatting, was correct all along.
I want current date and time in PST. I used this code
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd HH:mm:ss zzz"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:#"PST"]];
NSString *timeStamp = [dateFormatter stringFromDate:[NSDate date]];
NSLog(#"String:%#",timeStamp);
It returns correct date and time in PST in string form but I want NSDate in PST. So when I change NSString to NSDate like this:
NSDate *currentPST = [dateFormatter dateFromString:timeStamp];
NSLog(#"currentPST Date:%#",currentPST);
It returns date in GMT. I have done R&D but all in vain.Output is:
String:2011-05-18 22:28:54 PDT
currentPST Date:2011-05-19 05:28:54 +0000
Can anyone suggest a solution please.
Thanks in advance
In Cocoa, NSDate is an abstract representation of a date with no time zone information applied.
Whenever you print a NSDate object, it will print the date value corresponds to the default timezone(your device timezone). Your device timezone is GMT thats why you get the value like that. If you look into that deeply, both the time where same, but the timezone varies.