Anibal Lamego
Anibal Lamego

Reputation: 241

Date from string not working with specific date

I have a very strange issue about one specific date 10-18-15 using xcode 7.01

Running code:

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    NSString *stringDate =@"10-18-15";
    NSDateFormatter *dateFormatter = [NSDateFormatter new];
    dateFormatter.dateStyle = NSDateFormatterShortStyle;
    dateFormatter.timeStyle = NSDateFormatterNoStyle;

    NSDate *myDate = [dateFormatter dateFromString:stringDate];

    NSLog(@"Mydate:%@ Text: %@",myDate,stringDate);
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

output:

2015-10-20 10:37:55.129 teste[3286:95083] Mydate:(null) Text: 10-18-15

If I change NSString *stringDate =@"10-17-15";

output:

2015-10-20 10:22:10.741 teste[3102:82782] Mydate:2015-10-17 03:00:00 +0000 Text: 10-17-15

It seems this date 10-18-2015 is corrupted in NSDate database

Any idea how to fix it?

Upvotes: 1

Views: 1035

Answers (3)

iOSX
iOSX

Reputation: 1300

Update: It's critical to set the calendar property of the date formatter!

Conversion from string to date may fail for specific dates because some dates simply do not exist in certain time zones (e.g. BRT) due to daylight saving time switch happening on midnight. So there is no midnight actually and 10-18-15 00:00 (BRT) (when no time is specified midnight is presumed) is just not a valid date.

However, when a calendar object is specified (only tested it with the Gregorian calendar) the date formatter seems to become "smarter" and falls back to the start of the day, which is 10-18-15 1:00 AM, instead of returning nil.

NSString *stringDate = @"10-18-15";
NSDateFormatter *dateFormatter = [NSDateFormatter new];
dateFormatter.calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
dateFormatter.dateFormat = @"MM-dd-yy";
NSDate *myDate = [dateFormatter dateFromString:stringDate];

Here is some code that shows the behaviour. I used a Xcode Playground, so it's in Swift...

import UIKit

func printDateForString(string: String, dateFormatter: NSDateFormatter, timeZone: NSTimeZone? = nil) {
    let date = dateFormatter.dateFromString(dateString)
    print("result: ", terminator: "")
    if let date = date {
        let outputDateFormatter = NSDateFormatter()
        outputDateFormatter.dateStyle = .ShortStyle
        outputDateFormatter.timeStyle = .ShortStyle
        outputDateFormatter.calendar = NSCalendar(identifier: NSCalendarIdentifierGregorian)!
        outputDateFormatter.timeZone = timeZone
        print(outputDateFormatter.stringFromDate(date))
    }
    else {
        print("nil")
    }
}

let dateString = "10-18-15"
let dateFormat = "MM-dd-yy"
let timeZone = NSTimeZone(name: "America/Sao_Paulo")!

print("configure date formatter without setting its calendar property")
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = dateFormat
dateFormatter.timeZone = timeZone
printDateForString(dateString, dateFormatter: dateFormatter, timeZone: timeZone)

print("after setting date formatter's calendar property to non-nil (Gregorian)")
dateFormatter.calendar = NSCalendar(identifier: NSCalendarIdentifierGregorian)
printDateForString(dateString, dateFormatter: dateFormatter, timeZone: timeZone)

print("resetting calender property of date formatter to nil")
dateFormatter.calendar = nil
printDateForString(dateString, dateFormatter: dateFormatter, timeZone: timeZone)

Output:

configure date formatter without setting its calendar property
result: nil
after setting date formatter's calendar property to non-nil (Gregorian)
result: 10/18/15, 1:00 AM
resetting calender property of date formatter to nil
result: nil

Original answer:

You should set the date format explicitly when converting from string to date:

NSString *stringDate = @"10-18-15";
NSDateFormatter *dateFormatter = [NSDateFormatter new];
dateFormatter.dateFormat = @"MM-dd-yy";
NSDate *myDate = [dateFormatter dateFromString:stringDate];

Upvotes: 1

Anibal Lamego
Anibal Lamego

Reputation: 241

I found same question: Bug in swift 2.0 NSDateFormatter?The behavior depends on which timeZone the formatter using. For example: America/Sao_Paulo In Sao Paulo, timeanddate.com/time/change/brazil/sao-paulo?year=2015 Sunday, 18 October 2015, 00:00:00 clocks are turned forward 1 hour to Sunday, 18 October 2015, 01:00:00 local daylight time instead That means, there is no 2015-10-18 00:00:00 in Sao Paulo. And as for NSDateFormatter, when it receives no time information from string, it assumes the time is 00:00:00 in its timezone. That's why it returns nil.

Upvotes: 2

Teja Nandamuri
Teja Nandamuri

Reputation: 11201

Try to give NSdate to this format which returns date which can be converted later either to NSDate/NSString in short format

For example:

    NSDate *stringDate=[NSDate dateWithTimeIntervalSinceNow:0];
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
    dateFormatter.dateStyle = NSDateFormatterShortStyle;
    dateFormatter.timeStyle = NSDateFormatterNoStyle;

    NSString *myDate = [dateFormatter stringFromDate:stringDate];

If you want to use NSString anyway, then convert it to NSdate and parse it to the formatter.

Upvotes: 0

Related Questions