Date Formatting/Error handling trouble in iOS - ios

I have an iOS app that receives data via webservice calls. Everything was working then, without warning, the app began to crash. I have traced it down to a line that formats date-time values. The webservice originally returned date values as:
yyyy-MM-dd'T'HH:mm:ss.sssz
then, without warning the date format changed to:
yyyy-MM-dd'T'HH:mm:ss
and an exception resulted. I have corrected the problem, however, the web service provides data from thousands of stations around the nation that report time sensitive data. Therefore, I can't guarantee that the old date format isn't still returned from some web service calls.
Coming from a C# and Java background, my normal approach to this issue would be a try/catch block. However, Objective-C is a different animal when it comes to exception handling. I'm not sure how to handle the different date formats. Here is my current code to do the date-time formatting
-(NSString*)stringDateFormatter:(NSString*)dateToFormat{
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss"];
//[df setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss.sssz"];
[df setTimeZone:[NSTimeZone localTimeZone]];
NSDate *newDateValue = [df dateFromString:dateToFormat];
[df setDateFormat:#"HH:mm"];
NSString *retValue = [df stringFromDate:newDateValue];
return retValue;
}
What might be a best practice in hadling the two different date-time formats? Thanks! V

If you might get a date string in one of two different formats then try one first. If you get a nil result, try the other format.
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss"];
NSDate *newDateValue = [df dateFromString:dateToFormat];
if (!newDateValue) {
[df setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss.sssz"];
newDateValue = [df dateFromString:dateToFormat];
}
BTW - there is no need to set the timezone to the local timezone. That is already the default.

Related

Lossless conversion of NSDate to NSString and vice versa

I have an NSDate:
2015-07-13 16:04:01 +0000
and I want to convert it to an NSString to be able to store it on a server and then read it back from server and convert back to NSDate without losing any details.
I've been looking at other posts that have suggested doing it as follows:
NSDateFormatter *dateFormatter = [NSDateFormatter new];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
NSString *dateString = [dateFormatter stringFromDate:date];
and vice-versa:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"dd-MM-yyyy"];
NSDate *dateFromString = [dateFormatter dateFromString:message[#"date"]];
but this leads to the loss and compromise of the format:
Jul 13, 2015
How do I convert NSDate to NSString and back, eventually getting back the exact original NSDate?
You're only formatting the original NSDate with a date (not time) style that reflects the user's preferences and you're only formatting the retrieved NSDate with day, month, and year, i.e. "dd-MM-yyyy". You should be consistent your NSDateFormatters in order to maintain the original format.
Change both
[dateFormatter setDateFormat:#"dd-MM-yyyy"];
and
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
to
[dateFormatter setDateFormat:#"yyyy-MM-dd HH:mm:ss Z"];
to get and keep the entire date and time format.
An NSDate stores the number of seconds since a reference date. If you are using only iOS applications. then you call a method returning that number of seconds as an NSTimeInterval which is a number, and then you store the number. This means there is absolutely no loss of information. Your data will come back with better than microsecond precision.
If the data has to be read by different devices not running iOS then there is another method returning the number of seconds since Jan 1st, 1970. This is a very standard format that any OS should be able to handle.
Storing a number instead of a string seems to be much better.

Convert a date to English format form Bengali

I have a date picker in my app. The phone is set to Bangladesh local settings. When I select a date from datepicker is always returns the date in Bengali. It return a date in local format.
Like, it returns ০৬/১১/২০১৪
but I want it to be 06/11/2014.
I've tried converting it by date formatter. This is what I tried:
NSDateFormatter* formatter = [[NSDateFormatter alloc] init];
[formatter setLocale:[NSLocale currentLocale]];
NSDate* date = [formatter dateFromString: self.birthDate.text];
NSDateFormatter *formater = [[NSDateFormatter alloc] init];
[formater setLocale:[NSLocale localeWithLocaleIdentifier:#"en_US"]];
[formater setDateFormat:#"dd/MM/yyyy"];
NSLog(#"%#",[formater stringFromDate:date]);
The output is null.
You are incorrect in your assumption when you say...
When I select a date from datepicker is always returns the date in Bengali. It return a date in local format.
UIDatePicker returns an NSDate object. NSDate has no formatting at all. It has no language, it is purely a point in time.
When you do this...
NSLog(#"%#", someDate);
The system will render that point in time into a string and then print it. It is the rendering into a string that contains the format.
I'm guessing what you are doing is this...
Get a date from a UIDatePicker.
Render that date into a UITextField in Bengali. (or label, or text view or something)
Trying to read the text and store it into a date.
Trying to then "convert" the date to an English string.
What you should be doing is just saving the date that comes from the date picker.
Put it into a property or something.
In your above code I think the bit that is failing is actually the first bit...
NSDateFormatter* formatter = [[NSDateFormatter alloc] init];
[formatter setLocale:[NSLocale currentLocale]];
NSDate* date = [formatter dateFromString: self.birthDate.text];
Because you're not giving it a format it will fail. But this is the wrong way to go about it anyway.
You should have something like this...
- (void)datePickerChoseADate
{
self.date = self.datePicker.date;
}

how to convert Javascript Date to iOS date format

I am new in iOS development. Actually I am trying to show some information which I get from a web service in a table view.
I have successfully retrieved the response as JSON in my code, but in my table view there is a label to show date.
But in my response the date is something like this
/Date(1391068800000)/
How can I convert this to show in my table view? I think this is Javascript date.
But I'm not sure how to convert it.
NSDate *date = [NSDate dateWithTimeIntervalSince1970:[your timestamp doublevalue]/1000];
divide value by 1000 cause of milliseconds (13 digit)
The date in your response is a timestamp. You can create a date object by:
NSDate *date = [NSDate dateWithTimeIntervalSince1970:1391068800000];
After that you can convert this date to a string in an appropriate format by using the NSDateFormatter class. For example:
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterMediumStyle];
NSString *dateString = [formatter stringFromDate:date];
For more information about formatting dates see: https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/DataFormatting/Articles/dfDateFormatting10_4.html

iOS - Converting time and date to user time zone

I am sending some requests on a webserver that replies me time and date like this:
"at 18:58 of 05/08/2012"
I can figure out how to get the time and the date in 2 NSStrings(18:58, 05/08/2012).
Note that the server's time zone is +00:00. What I want to accomplish is to present this time based on user's location. So for example if the reply from server is 23:30 at 05/08/2012 and the user's time zone is +2:00 I want to present him 1:30 at 06/08/2012.
Any ideas?
You should do it the following way:
1) First, create an NSDateFormatter to get the NSDate sent from the server:
NSDateFormatter *serverFormatter = [[NSDateFormatter alloc] init];
[serverFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"GMT"]];
[serverFormatter setDateFormat:#"'at 'HH:mm' of 'dd/MM/yyyy"];
From Apple docs: note with the Unicode format string format, you should enclose literal text in the format string between apostrophes ('').
2) Convert the string (consider it is defined as theString) to a NSDate:
NSDate *theDate = [serverFormatter dateFromString:theString];
3) Create an NSDateFormatter to convert theDate to the user:
NSDateFormatter *userFormatter = [[NSDateFormatter alloc] init];
[userFormatter setDateFormat:#"HH:mm dd/MM/yyyy"];
[userFormatter setTimeZone:[NSTimeZone localTimeZone]];
3) Get the string from the userFormatter:
NSString *dateConverted = [userFormatter stringFromDate:theDate];
instead of getting absolute time from server get timestamp from server and convert that in to date at the client side, for this you didn't have to change the timezone also.

Ensure AM / PM (Period) does not appear in NSDateFormat stringFromDate

The Unicode Date Format Patterns guide (here) state that appending an 'a' to the format will get the period (AM or PM for instance), e.g.,
[formatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss a"];
However I wish to ensure that the period information does not appear but I cannot find a format string to do that. The format string I am using is as follows:
[formatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss"];
unfortunately, when I use stringFromDate I get the following:
2013-01-09T11:11:00 AM
I dont wish to simply strip AM or PM from the resultant string because the period syntax may be different in differing Calendars etc, I just want to stop the period information appearing.
----8<------
Consider the following code
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setLocale:[NSLocale currentLocale]];
[formatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"UTC"]];
[formatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss"];
NSString *stringDate = [formatter stringFromDate:[NSDate date]];
self.labelOutput.text = stringDate;
[formatter release];
This code will produce a string in the format I want - however I cannot use it for memory management reasons. The app I am working on is plagued by NSDateFormatter memory leaks. So we use a singleton class to provide a set number NSDateFormatters to the app which are never released and therefore we minimise how much memory is being leaked. Unfortunately these static NSDateFormatters are appending AM / PM even when I apply a date format string thus:
NSDateFormatter *formatter = [MyDateFormatter dateFormat:kFormatDateMediumStyleTimeShortStyle];
[formatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"UTC"]];
[formatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss"];
According to date formatter different output on different devices running same iOS version, set the local of your NSDateFormatter to en_US_POSIX will fix this.
Additional to set Local you may wish avoid problems with time zone setting it like:
[formatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"UTC"]];
It actually depends on user's settings.
Please see Fixed Formats part of Data Formatting Guide. Note this sentence:
In iOS, the user can override the default AM/PM versus 24-hour time
setting. This may cause NSDateFormatter to rewrite the format string
you set.
And at the end of the paragraph:
The representation of the time may be 13:00. In iOS, however, if the
user has switched 24-Hour Time to Off, the time may be 1:00 pm.
You need to use POSIX here a sample code
NSDateFormatter *rfc3339DateFormatter = [[NSDateFormatter alloc] init];
NSLocale *enUSPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"];
[rfc3339DateFormatter setLocale:enUSPOSIXLocale];
[rfc3339DateFormatter setDateFormat:#"yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"];
[rfc3339DateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
// Convert the RFC 3339 date time string to an NSDate.
NSDate *date = [rfc3339DateFormatter dateFromString:rfc3339DateTimeString];
One option is to create your own NSFormatter. I did that on my code when I couldn't get the formatter in Xcode's Interface Builder to do what I wanted. Granted, I was only looking for hours, minutes, and seconds and not the full date.
As for the memory leaks: if you can, use ARC. If you can't, use Xcode's Static Analyzer to try and track down improper retain counts.
Here is the answer I have settled on. It's a bit simplistic but it does the job.
#interface NSDateFormatter (Utils)
- (NSString *)stringWithNoPeriodInformationFromDate:(NSDate*)date;
#end
#implementation NSDateFormatter (Utils)
- (NSString *)stringWithNoPeriodInformationFromDate:(NSDate*)date
{
NSString *stringWithPotentialPeriodInformation = [self stringFromDate:date];
NSString *stringWithNoAMInformation = [stringWithPotentialPeriodInformation stringByReplacingOccurrencesOfString:[self AMSymbol] withString:#""];
NSString *stringWithNoPeriodInformation = [stringWithNoAMInformation stringByReplacingOccurrencesOfString:[self PMSymbol] withString:#""];
return stringWithNoPeriodInformation;
}
#end

Resources