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);
Related
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
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.
My country is located in GMT+0. We are +1 hour now, because we are in daylight saving.
When I do
[NSDate date];
it was supposed to return the current date and time, but when I do that, I receive the GMT time not considering the daylight saving.
This is what the docs say about the date command
Creates and returns a new date set to the current date and time.
Why Apple does that to us? Why everything is so complex? Is this a bug? Is there a way to get the current real time the device is on? the same time that is displayed on the device's clock?
My app depends on dates and times and having a wrong date for an user located in a different timezone around the world that is on summertime or wintertime will be a disaster.
Thanks.
EDIT
After several answers, I have tried this code:
NSDate *wrongToday = [NSDate date];
NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
[dateFormatter setTimeStyle:NSDateFormatterMediumStyle];
[dateFormatter setTimeZone:[NSTimeZone localTimeZone]];
NSString *currentTime = [dateFormatter wrongToday];
NSDate *today = [dateFormatter dateFromString:currentTime];
guess what, today = wrongToday...
in other words, no change, I continue to have the wrong date without daylight saving.
what is more amazing is that currentTime shows in NSString the date with daylight saving...
any clues? thanks again.
albertamg, MRAB and Joe Osborn are all correct. They're all trying to explain to you that NSDate is a "number", "an absolute moment in time".
This value is INDEPENDENT of whether you're in London, in Los Angeles or in Singapore. It's independent of whether your county respects daylight savings time.
To INTERPRET NSDate in terms of something recognizable (like "Th July 28, 4:28pm"), you need an NSDateFormatter. You also need to make sure your locale is defined correctly: including timezone, whether daylight savings is honored, and various time/date formatting conventions.
'Hope that helps ..
Hard coding:
BOOL isDayLightSavingTime = [sysTimezone isDaylightSavingTimeForDate:currentDate];
if (isDayLightSavingTime) {
NSTimeInterval timeInterval = [sysTimezone daylightSavingTimeOffsetForDate:currentDate];
currentDate = [currentDate dateByAddingTimeInterval:timeInterval];
}
the current date is now daylight saving time.
Hope help.
My suggestion!
NSString *dateToTest = #"16-10-2016"; // <-- daylight saving
NSDateFormatter *dateformatter = [[NSDateFormatter alloc] init];
[dateformatter setDateFormat:#"dd-MM-yyyy"];
NSDate *data = [dateformatter dateFromString:dateToTest];
NSLog(#"data before --> %#:", data);
if (data == nil && [[NSTimeZone systemTimeZone] isDaylightSavingTimeForDate:data]) {
NSTimeZone *timeZone = [[NSTimeZone alloc] initWithName:[NSTimeZone localTimeZone].name];
[dateformatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:[timeZone secondsFromGMT]]];
data = [dateformatter dateFromString:dateToTest];
NSLog(#"data after --> %#:", data);
}
There are a couple of good answers on the site already here and here and here. An NSDate is an interval since the (UTC) reference date, but you can use NSTimeZone as detailed in those answers.
It will keep counting down and updating the current time. Anyone has any idea how to approach this problem? I don't see how the NStimer will recognize the date format like this:
20110803 23:59:59
Look up NSDateFormatter. You can specify a format string (-[setDateFormat:])that lets you convert to AND from NSDate and NSString.
When converting back to your countdown view, you may want to use NSDateComponents and NSCalendar to get the pieces you need for your countdown label (instead of NSDateFormatter). You could do something like:
NSDateComponents *countdown = [[NSCalendar currentCalendar]
components:(NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit)
fromDate:[NSDate date]
toDate:expiration
options:0];
This will calculate all the unit differences for you (with respect to the device's currently configured calendar settings).
You can get the components back with a call like [countdown day] or [countdown hour].
You can get the date easily by using NSDateFormatter like this to get a NSDate object from your string.
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyyMMdd' 'HH:mm:ss"];
[dateFormatter setTimeZone:[NSTimeZone localTimeZone]];
NSDate *date = [dateFormatter dateFromString:your_date_string];
You could convert the date from NSString to NSDate by using the NSDateformatter class.
NSString *dateString = #"20110803 23:59:59";
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"yyyyMMdd HH:mm:ss"];
NSDate *date = [dateFormat dateFromString:dateStr];
Now, in order to count down, you use the NSTimer class to fire every one second, then you can get the difference in seconds between the current date and your datevariable by simply use timeIntervalSinceDate.
NSTimeInterval distanceBetweenDates = [currentDate timeIntervalSinceDate:yourDate];
Now that you have the difference in seconds, you convert it to whatever format you wish to display.
I didn't drill down into this problem deeply, therefore sorry, if my answer is a bit unappropriate.
In this case I would use NSDate. Using NSDateFormatter I would convert text data of xml to NSDate. Changing the value of NSDate, when every tick of NSTimer, properly.
And a bit of code, 'cause the symbols of NSDateFormatter sometimes create mess:
NSString *xmlDateFormat = #"yyyyMMdd HH:mm:ss";
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:xmlDateFormat];
NSDate *yourDate = [dateFormatter dateFromString:timeStringFromXml];
This is for reading from xml. For changing value of NSDate when tick you can see the doc of NSDate. And for display the value in label I would arithmetically calculate every value and show it with the help of casual NSString:
[NSString stringWithFormat:#"%dday %dh %dm %ds", days, hours, minutes, seconds];
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.