I've searched and haven't found an exact question like mine, so here goes nothing:
I have a NSString containing a key that I pull from an XML feed. The key is a time in 24-hour format (e.g. 13:30 or 15:00.) I'd like to convert the NSString to an NSDate and have it converted to the appropriate timezone based on the device's set timezone. The key is Unicode HH:mm (24:00), so I'm curious why this does not work as it should.
I've already gotten a basic outline that should work, but alas does not. The 2nd NSLog (Got NS Date) returns null and the final log returns a strange number (1969-12--2147483629 -596:-31:-23 +0000 to be precise.) What am I doing wrong here?
Thanks in advance,
NSString *dateString = [dict objectForKey:#"24hrdate"];
NSLog(#"NSString Date: %#", dateString);
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"HH:mm"];
NSDate *sourceDate = [formatter dateFromString:dateString];
NSLog(#"Got NS Date: %#", sourceDate);
NSTimeZone *sourceTimeZone = [NSTimeZone timeZoneWithAbbreviation:#"GMT"];
NSTimeZone *destinationTimeZone = [NSTimeZone systemTimeZone];
NSInteger sourceGMTOffset = [sourceTimeZone secondsFromGMTForDate:sourceDate];
NSInteger destinationGMTOffset = [destinationTimeZone secondsFromGMTForDate:sourceDate];
NSTimeInterval interval = destinationGMTOffset - sourceGMTOffset;
NSDate* destinationDate = [[[NSDate alloc] initWithTimeInterval:interval sinceDate:sourceDate] autorelease];
NSLog(#"Final Date: %#", destinationDate);
First of all understand that the date component will be 01-01-1970 because it isn't provided. I am assuming that you want the time to be 04:00 GMT if the input string is #"04:00". That you can achieve by setting the time zone of the formatter.
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setTimeZone:[NSTimeZone timeZoneWithName:#"GMT"]];
[formatter setDateFormat:#"HH:mm"];
NSDate *sourceDate = [formatter dateFromString:dateString];
NSDate is used to represent a date and time. While you can represent just a date by sticking with midnight, you can't really represent just a time of day with it. You can sort of fake this on the Mac (it defaults to some reasonable day), but on iOS you'll get wildly inaccurate times instead. (At least, you do on certain versions. This may have been fixed.)
There's two approaches here:
You can build a NSDateComponents from your time of day and using dateByAddingComponents to add that to midnight on the date you want the time to appear on. This will fail to return the time you expect on a day where daylight savings begins or ends.
You can build a date/time string using the date you want (NSDate) and the time (likely, as a NSString).
- (NSDate *)timeInHours: (NSInteger)hours
minutes: (NSInteger)minutes
seconds: (NSInteger)seconds
onDate: (NSDate *)inDate;
{
id timeStr = [[NSMutableString alloc] initWithFormat: #"%02d:%02d:%02d", hours, minutes, seconds];
id dateStr = [dateWithoutTimeFormatter stringFromDate: inDate];
id dateTimeStr = [[NSString alloc] initWithFormat: #"%# %#", dateStr, timeStr];
[timeStr release];
id dateTime = [dateWithTimeFormatter dateFromString: dateTimeStr];
[dateTimeStr release];
return dateTime;
}
If you really want just the time of day, just keep it around as a string.
Just wanted to post back that I did manage to achieve what I initially set out to do without any issues. Basically, I had to convert the string to NSDate, run that NSDate through a NSDateFormatter (set to the time's original timezone--NSDateFormatter's setTimeZone was helpful), pull an NSDate out of that, and then run that through another NSDateFormatter for the device's timezone. I then converted the resulting NSDate back to NSString, and stuck it on a UILabel.
This solution seems to have worked quite well, as I've set my devices to various timezones, and the timezone change is still correct.
EDIT: this was important to included, too:
NSString *date…….
date = [date stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
Related
Sometimes my code is returning an a.m. or p.m. but not always. Most of the time it just returns what I expect, which is something like: 20110815170852164
But other times it's returning: 20100412010241 a.m.450
NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
[dateFormatter setDateFormat:#"yyyyMMddHHmmssSSS"];
NSString *dateString = [dateFormatter stringFromDate:[NSDate date]];
What could be causing this? Specific date/time country settings on users iPhones? I have this out to thousands of people, and most aren't returning the a.m. (which is expected) but others are. WHY?
The problem you are describing is a known bug. Check out some discussion on the problem on stackoverflow, and you can find some possible work-arounds there.
Here's an excerpt of huyz's explaination of the bug:
The problem comes from NSDateFormatter somehow “getting stuck” in the 12 or 24-hour time mode that the user has manually selected. So if a French user manually selects 12-hour mode, and the application requested NSDateFormatter to output time with the 24-hour format “HHmm”, it would actually receive time in a 12-hour format, e.g. “01:00 PM”, as if the application had instead requested “hhmm aa”. The reverse would happen if a US user manually selected 24-hour mode: outputting time with the 12-hour format “hhmm aa” would actually get you time in the 24-hour format instead, e.g. “17:00″.
Right. The solution is to explicitly set the locale of the date formatter, ideally to en_US_POSIX. See the final answer to this question.
I was working on a data-share function of a project which was highly depending on the values/results entered in advance when I bumped into the same problem. I implemented a nasty little workaround for saving the right datetime in 24h format to the database.
The solution is very simple
First, I get the local date from the device:
NSDate* now = [NSDate date];
Second step is to create a NSDateFormatter with US locale regardless of system's locale to make sure that "PM" is going to be "PM":
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:#"en_US"]];
Then, I get the date (year, month, day) into a string:
[formatter setDateFormat:#"yyyy-MM-dd"];
NSString *date = [formatter stringFromDate:now];
For the next part, I get the hours, minutes and seconds:
[formatter setDateFormat:#"hh"];
NSString *hours = [formatter stringFromDate:now];
[formatter setDateFormat:#"mm"];
NSString *minutes = [formatter stringFromDate:now];
[formatter setDateFormat:#"ss"];
NSString *seconds = [formatter stringFromDate:now];
Next, I get the part of the day:
[formatter setDateFormat:#"a"];
NSString *partOfDay = [formatter stringFromDate:now];
Then comes the logic: if the part of the day is PM but the hours are less then 12, we just have to correct that. In code:
if([partOfDay isEqualToString:#"PM"] && [hours intValue] < 12) {
hours = [[NSString alloc] initWithFormat:#"%i", ([hours intValue] + 12)];
}
After this modification, we are ready to put the string together in order to have a datetime ready to be saved into SQL:
NSString *sqlDateTime = [[NSString alloc] initWithFormat:#"%# %#:%#:%#", date, hours, minutes, seconds];
That's all there is to it. And from now we can only hope that Apple is going to fix this bug to make it work as it should be.
I hope this helps.
i am not able to get proper time from a given time.
My code is as follows
NSArray * array_TimeSlotWith_StartDate = [ #"01/05/2010 10:15:33" componentsSeparatedByString:#" "];
NSArray * array_TimeSlotWith_EndDate = [ #"01/05/2010 10:45:43" componentsSeparatedByString:#" "];
NSLog(#" array_TimeSlotWith_StartDate === %#",array_TimeSlotWith_StartDate);
NSLog(#"array_TimeSlotWith_EndDate == %#",array_TimeSlotWith_EndDate);
NSArray * Array_StartTime = [[array_TimeSlotWith_StartDate objectAtIndex:1] componentsSeparatedByString:#":"];
NSLog(#"Array_StartTime == %#",Array_StartTime);
NSDateFormatter *df = [[[NSDateFormatter alloc] init] autorelease];
[df setDateFormat:#"HH:mm:ss"];
NSDate *date1 = [df dateFromString:[array_TimeSlotWith_StartDate objectAtIndex:1]];
NSDate *date2 = [df dateFromString:[array_TimeSlotWith_EndDate objectAtIndex:1]];
NSTimeInterval interval = [date2 timeIntervalSinceDate:date1];
NSLog(#"date 1%#",date1);
NSLog(#"date 2%#",date2);
It gives me value of date 1 as 1970-01-01 04:45:33 +0000 instead of this what i need is just the time an that should be 10:15:33.
And same for the end date also it gives log as 1970-01-01 05:15:43 +0000 instead of this it should output as only the time component with value 10:45:43 .
Time doesn't exist without a date. If you don't specify any date, the date formatter will default to "1970-01-01"(Unix epoch). I hope this SO link will help you.
Though the date1 and date2 don't contain the value you've expected, I feel that, interval should contain the correct result you need. I suggest you to just ignore the dates in this context.
you neither specifying the date and timezone that's the reason NSDate object pick the default one for its use.
I have a NSString (ex. "2011-04-12 19:23:39"), and what I did to format it to a NSDate was the following:
[inputFormatter setDateFormat:#"yyyy-MM-dd HH:mm:ss"];
NSDate *date = [inputFormatter dateFromString:newDateString];
but what it outputs when I nslog the date is this:
2011-04-12 23:23:39 +0000
which is about 4 hours off. Is there something I missed? Possibly a time zone problem?
The answer in short, is the Date is being returned GMT unless specified otherwise. You can set your timezone to get the correct date. If you plan on using the date in the app to set anything ( like localNotification time or Event ) you will need to do something special with the date because if you set the date in the iPhone it will be set as GMT time and will be off by a few hours. ( in your case 4 hours ). I do this exact thing I just described in one of my apps.
I made a mess of trying to get this to work correctly without having the hours be off. It was a huge PITA to figure out but its working now. I have copied, pasted, and edited my code to share. Again, its messy but it works! The pickerChanged is getting its info from a UIDatePicker
Using the code below. To answer your question, you can stop at "destinationDate". That will return to you the corrected time for your current time zone. I just provided the extra incase you were trying to use the date in the Phone somewhere.
NOTE: for a quick example i put the Event reminder in the same function as the datepicker, you will NOT want to do that otherwise you will have alot of reminders set everytime the wheel scrolls in the datepicker.
The code is below.
- (void)pickerChanged:(id)sender
{
NSLog(#"value: %#",[sender date]);
NSDate* date= [sender date];
NSDateFormatter *formatter=[[[NSDateFormatter alloc]init]autorelease];
[formatter setDateFormat:#"MM/dd/yyyy hh:mm:ss a"];
[formatter setTimeZone:[NSTimeZone systemTimeZone]];
[formatter setTimeStyle:NSDateFormatterLongStyle];
NSString *dateSelected =[formatter stringFromDate:date];
NSString *timeZone = [dateSelected substringFromIndex:12];
NSTimeZone* destinationTimeZone = [NSTimeZone systemTimeZone];
//here we have to get the time difference between GMT and the current users Date (its in seconds)
NSInteger destinationGMTOffset = [destinationTimeZone secondsFromGMTForDate:date];
//need to reverse offset so its correct when we put it in the calendar
correctedTimeForCalendarEvent = destinationGMTOffset + (2*(-1*destinationGMTOffset));
//date to enter into calendar (we will use the correctedTimeForCalendarEvent to correct the time otherwise it will be off by a few hours )
NSDate * destinationDate = [[[NSDate alloc] initWithTimeInterval:destinationGMTOffset sinceDate:date] autorelease];
NSDate * dateForReminder = destinationDate;
// return destinationDate;
NSLog(#"value: %# - %#",destinationDate,dateForReminder);
//DO NOT put this code in this same function this is for a quick example only on StackOverflow
//otherwise you will have reminders set everytime the users scrolled to a different time
//set event reminder
//make sure to import EventKit framework
EKEventStore *eventDB = [[[EKEventStore alloc] init]autorelease];
EKEvent *myEvent = [EKEvent eventWithEventStore:eventDB];
NSString * eventTitle = [NSString stringWithFormat:#"%# - %#",app.dealerBusinessName,serviceOrComments.text];
myEvent.title = eventTitle;
//double check date one more time
NSLog(#"value: %#",destinationDate);
//set event time frame (1 hour) the "initWithTimeInterval" is where we account for the users timezone by adding the correctedTime from GMT to the calendar time ( so its not off by hours when entering into calendar)
myEvent.startDate = [[[NSDate alloc] initWithTimeInterval:correctedTimeForCalendarEvent sinceDate:destinationDate ]autorelease];
myEvent.endDate = [[[NSDate alloc] initWithTimeInterval:3600 sinceDate:myEvent.startDate]autorelease];
myEvent.allDay = NO;
//set event reminders 1 day and 1 hour before
myAlarmsArray = [[[NSMutableArray alloc] init] autorelease];
EKAlarm *alarm1 = [EKAlarm alarmWithRelativeOffset:-3600]; // 1 Hour
EKAlarm *alarm2 = [EKAlarm alarmWithRelativeOffset:-86400]; // 1 Day
[myAlarmsArray addObject:alarm1];
[myAlarmsArray addObject:alarm2];
myEvent.alarms = myAlarmsArray;
[myEvent setCalendar:[eventDB defaultCalendarForNewEvents]];
NSError *err;
[eventDB saveEvent:myEvent span:EKSpanThisEvent error:&err];
if (err == noErr) {
//no error, but do not show alert because we do that below.
}
}
NSDateFormatter use the current device timezone when it created the NSDate object. NSDate stores the date/time in GMT. Therefore by default NSLog will output the date/time in GMT+0. So, there's nothing wrong with your code. Now if you want to output the NSDate to your current timezone, your will have to use a NSDateFormatter object.
Your data and date formatter omit the TimeZone specifier. So something like this:
[inputFormatter setDateFormat:#"yyyy-MM-dd HH:mm:ssZ"];
Would work - the Z is the timezone specifier and will parse both numeric offsets and timezone codes. Although in your case as your input date has no TimeZone information it won't work.
Your correct Time string should be like "2011-04-12 19:23:39 -0400" or "2011-04-12 19:23:39 EST "
Depending on where you get your date from, you should fix that to produce a fully qualified date if you can't do that, you will have to agree timezone offsets with the server or simply 'hard code' a timezone offset and add that number of seconds to your NSDate.
The date is being logged as a UTC date can be seen by the +0000 at the end. The date format you are using to parse the string assumes your local time zone which is presumably 4 hours behind UTC with daylight savings and the standard -5 hours.
Use -[NSDateFormatter setTimeZone:] to provide the date formatter with timezone information. You can use the local time zone, or if you have a fixed time zone associated with the date information, I recommend creating the timezone with the name (such as "America/East") rather than the abbreviation (such as "EST" or "EDT"), since the name does not force daylight savings into effect, but uses the correct daylight savings offset for that date in that timezone.
How can I compare the dates only, not the time. I am using
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"dd-MM-yyyy"];
NSString *tempDate = #"2-2-2012"; //Dynamic Date
NSDate *dateString = [dateFormatter dateFromString:tempDate];
NSLog(#"%#",dateString);
It logs this: 2012-02-01 18:30:00 +0000
NSDate *now = [NSDate date];//Current Date
NSLog(#"%#",now);
It logs this: 2011-04-04 14:49:45 +0000
I want to compare Dynamic date and current date, I don't need time. I may not using the correct NSDateFormatter. Can anyone of you tell me how to do this? If I am not clear, please let me know.
Suppose I have to strings
date1 = 3-2-2011;
date2 = 4-5-2020;
I want to convert them in date, only after that I can compare them. Its not happening from my date Formatter. Please have a look.
Thanks!
Simplest way is to compare date by converting it into string.
Sample Code is as shown below:
//Current Date
NSDate *date = [NSDate date];
NSDateFormatter *formatter = nil;
formatter=[[NSDateFormatter alloc] init];
[formatter setDateFormat:#"yyyy-MM-dd"];
NSString *dateString = [formatter stringFromDate:date];
[formatter release];
//Other Date say date2 is of type NSDate again
NSString *date2String = [formatter stringFromDate:date2];
//Comparison of Two dates by its conversion into string as below
if([date2String isEqualToString:dateString])
{
//Your logic if dates are Equal
}
else if(![date2String isEqualToString:dateString])
{
//Your Logic if dates are Different
}
EDIT:
Checkout this link.
Comparing dates
http://www.iphonedevsdk.com/forum/iphone-sdk-development/64625-how-compare-2-dates.html
Hope This Helps You. :)
Use NSCalendar and NSDateComponents to get a date components object. Then you can look at only those parts of the date that you care about.
If you're just trying to determine whether two dates are the same, regardless of time, one way to go is to use NSDate's -timeIntervalSinceDate: method. If the time interval returned is less than 86,400 seconds (i.e. 24 hours * 60 minutes * 60 seconds) then you can feel fairly sure that it's the same day. Changes related to such things as daylight savings time and leap seconds introduce some possibility of error... if that's a problem, go with NSDateComponents.
NSDate *date = [NSDate date];
NSDateFormatter *formatter = nil;
formatter=[[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterMediumStyle];
[formatter setTimeStyle:NSDateFormatterNoStyle];
[formatter setLocale:[NSLocale autoupdatingCurrentLocale]];
NSString *dateString = [formatter stringFromDate:date];
[formatter release];
I'm diving into iOS development and the Objective C language and am building an alarm clock app to become familiar with the SDK and language. I have an NSString object that represents a time, with the range "1:00 am" to "12:59 am". I need to convert this NSString into two NSInteger's that contain the hour value and minute value. As I'm doing this, I'm finding the NSString manipulation that I'm doing to be extremely laborious and it just feels like sloppy code.
Is there a simple way to extract the hour and minute characters from a NSString representation of a time value and store their numerical values in two NSInteger's?
Thanks in advance for all your help! I'm gonna get back to it...
NSScanner* timeScanner=[NSScanner scannerWithString:...the time string...];
int hours,minutes;
[timeScanner scanInt:&hours];
[timeScanner scanString:#":" intoString:nil]; //jump over :
[timeScanner scanInt:&minutes];
NSLog(#"hours:%d minutes:%d",hours,minutes);
Use an NSDateFormatter to convert your string into an NSDate.
Use the [NSCalendar currentCalendar] to extract various date components (like the hour, minute, etc).
In other words:
NSDateFormatter* formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"h:m a"];
NSDate *date = [formatter dateFromString:#"12:59 pm"];
[formatter release];
NSDateComponents * components = [[NSCalendar currentCalendar] components:(NSHourCalendarUnit | NSMinuteCalendarUnit) fromDate:date];
NSLog(#"hour: %d", [components hour]);
NSLog(#"minute: %d", [components minute]);
This is the official way, as I know it. It's not pretty:
NSDateFormatter* dateFormatter = [[[NSDateFormatter alloc]init] autorelease];
[dateFormatter setDateFormat:#"h:m a"];
NSDate *date = [dateFormatter dateFromString:#"12:34 am"];
[dateFormatter setDateFormat:#"h"];
NSString *hours = [dateFormatter stringFromDate:date];
[dateFormatter setDateFormat:#"m"];
NSString *minutes = [dateFormatter stringFromDate:date];
BUT the string fiddling way of doing it (look for :, look for space, ...), may give you more headaches on the long term.
NSString *time = #"1:00 am";
NSString *removeam = [time stringByReplacingOccurencesOfString:#" am" withString:#""];
SString *removepm = [removeam stringByReplacingOccurencesOfString:#" pm" withString:#""];
NSArray *timeArray = [removepm componentsSeparatedByString:#":"];
NSInteger *hour = [[timeArray objectAtIndex:0] intValue];
NSInteger *mins = [[timeArray objectAtIndex:1] intValue];
If you're building an alarm clock app, you probably will want to look into the NSDate and NSDateFormatter classes, instead of trying to pull all those strings apart into integer types. Also, your time range is a bit weird (maybe a typo?) - don't you want all 24 hours to be available?
get the time interval and write it as
duration.text = [NSString stringWithFormat:#"%d:%02d", (int)audioPlayer.duration / 60, (int)audioPlayer.duration % 60, nil];