Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS RestKit Date parsing

In an old iOS project I had to parse dates that come in the format dd/MM/yyyy so I put these lines in a static method of my AppDelegate and it worked as expected

// Set the Dateformatter for the Dates returned by Knowledge tt/mm/yyyy
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"dd/MM/yyyy"];
[[RKValueTransformer defaultValueTransformer] insertValueTransformer:dateFormatter atIndex:0];

However in the actual projects my dates come in a slightly different format dd.MM.yyyy, so I used the same lines of code, just switched the Date format, but the date is not parsed.

For this date "ExamDate":"20.06.2014" I get (NSDate *) _examDate = 0x08f7dcd0 2014-01-01 01:00:00 CET after parsing and I can't understand why.

Update: I made a small test with this code:

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"dd.MM.yyyy"];
NSDate *date = [dateFormatter dateFromString:@"20.06.2014"];
DLog(@"Date: %@", date);

and got in the log: Date: 2014-06-19 22:00:00 +0000

like image 654
Hons Avatar asked Mar 20 '23 05:03

Hons


1 Answers

It looks like your in a timezone with a GMT offset of -2:00. Set your timezone to 0 GMT to have it printed correctly. What we usually do is just use unix time when passing around dates so we can avoid this sort of issue.

dateFormatter.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];

Since your problem appears to be in RestKit's parsing you'll need to use your own date parser. You can do this by installing what RestKit calls a Value Transformer which is what it uses when mapping data.

Here's one that you can work with to achieve what you want:

[RKObjectMapping alloc]; // This ensures you will actually insert at index 0!

[RKValueTransformer.defaultValueTransformer
 insertValueTransformer:
 [RKBlockValueTransformer
  valueTransformerWithValidationBlock:^BOOL(__unsafe_unretained Class inputValueClass, __unsafe_unretained Class outputValueClass) {
      return (([inputValueClass isSubclassOfClass:[NSDate class]] && [outputValueClass isSubclassOfClass:[NSString class]]) ||
              ([inputValueClass isSubclassOfClass:[NSString class]] && [outputValueClass isSubclassOfClass:[NSDate class]]));
  }
  transformationBlock:^BOOL(id inputValue, __autoreleasing id *outputValue, __unsafe_unretained Class outputClass, NSError *__autoreleasing *error) {
      RKValueTransformerTestInputValueIsKindOfClass(inputValue, (@[ [NSString class], [NSDate class] ]), error);
      RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputClass, (@[ [NSString class], [NSDate class] ]), error);
      if ([inputValue isKindOfClass:[NSString class]]) {
          // We're mapping from a string to a date.
          // You can add your formatter here.
          // Below is mine for mapping from Unix Time to an NSDate.
          NSString* input = inputValue;
          *outputValue = [NSDate dateWithTimeIntervalSince1970:input.integerValue];
      } else if ([inputValue isKindOfClass:[NSDate class]]) {
          // We're mapping from a date to a string.
          // You can add your formatter here (if needed).
          // Below is mine for mapping from an NSDate to Unix Time.
          NSDate* input = inputValue;
          *outputValue = @([input timeIntervalSince1970]);
      }
      return YES;
  }]
 atIndex:0]; // Insert at index 0 so your formatter is always used over the default one.

Alternatively, it looks like RestKit has it's own NSDateFormatter category which adds support for adding it as an RKValueTransformer. You should be able to try something like this:

[RKObjectMapping alloc]; // This ensures you will actually insert at index 0!
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"dd.MM.yyyy"];
dateFormatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"];
[RKDefaultValueTransformer insertValueTransformer:dateFormatter atIndex:0];
like image 196
Sandy Chapman Avatar answered Mar 27 '23 14:03

Sandy Chapman