NSString
NSDate
iOS Development
Date Conversion
Swift Programming

Converting NSString to NSDate and back again

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Converting between NSString and NSDate is really a formatting problem, not a type-casting problem. You need a formatter that knows exactly what date string shape you expect, along with the right locale and time-zone rules, or parsing will fail in subtle ways.

Use NSDateFormatter for Custom Formats

The standard Objective-C tool is NSDateFormatter. To parse a string, configure the formatter and ask it for a date:

objective-c
1#import <Foundation/Foundation.h>
2
3int main(void) {
4    @autoreleasepool {
5        NSString *text = @"2025-09-23 14:30:00";
6
7        NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
8        formatter.dateFormat = @"yyyy-MM-dd HH:mm:ss";
9        formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
10        formatter.timeZone = [NSTimeZone timeZoneWithName:@"UTC"];
11
12        NSDate *date = [formatter dateFromString:text];
13        NSLog(@"%@", date);
14    }
15    return 0;
16}

The en_US_POSIX locale is especially important for fixed machine-readable formats. It prevents user locale settings from changing how the parser interprets the string.

Convert NSDate Back to NSString

Formatting the date back into text uses the same formatter concept in the other direction:

objective-c
1#import <Foundation/Foundation.h>
2
3int main(void) {
4    @autoreleasepool {
5        NSDate *date = [NSDate dateWithTimeIntervalSince1970:0];
6
7        NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
8        formatter.dateFormat = @"yyyy-MM-dd HH:mm:ss";
9        formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
10        formatter.timeZone = [NSTimeZone timeZoneWithName:@"UTC"];
11
12        NSString *text = [formatter stringFromDate:date];
13        NSLog(@"%@", text);
14    }
15    return 0;
16}

Using the same format, locale, and timezone for both directions gives you predictable round-tripping.

Why Locale Matters

If the string is meant for humans, the user locale may be appropriate. If the string is meant for machines, APIs, or storage, user locale is usually the wrong choice.

For example, a date pattern such as:

text
MM/dd/yyyy

can mean different things to people in different regions. A fixed locale plus a fixed format prevents those ambiguities.

That is why machine-oriented parsing often uses:

  • an explicit format string,
  • 'en_US_POSIX,'
  • and an explicit timezone.

Why Time Zone Matters

NSDate represents an absolute point in time. The string may or may not specify a timezone explicitly.

If the string has no timezone information and you do not set one on the formatter, parsing may silently use the current default timezone. That can make the exact same input string mean different moments on different devices.

If the date text is supposed to be UTC, say so:

objective-c
formatter.timeZone = [NSTimeZone timeZoneWithName:@"UTC"];

If it is local user time, configure accordingly.

ISO 8601 Deserves Special Treatment

If your strings are ISO 8601 timestamps such as:

text
2025-09-23T14:30:00Z

then NSISO8601DateFormatter is often better than a hand-written pattern:

objective-c
1#import <Foundation/Foundation.h>
2
3int main(void) {
4    @autoreleasepool {
5        NSISO8601DateFormatter *formatter = [[NSISO8601DateFormatter alloc] init];
6        NSDate *date = [formatter dateFromString:@"2025-09-23T14:30:00Z"];
7        NSString *text = [formatter stringFromDate:date];
8        NSLog(@"%@", text);
9    }
10    return 0;
11}

For ISO 8601 data from APIs, this is usually more robust than manually maintaining date-format patterns.

Reuse Formatters Carefully

NSDateFormatter creation is relatively expensive. If you do many conversions, reuse a formatter when it is safe to do so rather than recreating one in tight loops.

At the same time, remember that date formatters are not generally thread-safe in the old Objective-C sense of random shared mutation. Reuse is good, but uncontrolled sharing across threads is not.

A Round-Trip Example

Putting it together:

objective-c
1NSString *original = @"2025-09-23 14:30:00";
2
3NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
4formatter.dateFormat = @"yyyy-MM-dd HH:mm:ss";
5formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
6formatter.timeZone = [NSTimeZone timeZoneWithName:@"UTC"];
7
8NSDate *date = [formatter dateFromString:original];
9NSString *formatted = [formatter stringFromDate:date];
10
11NSLog(@"%@", formatted);

If parsing and formatting rules match, formatted will reproduce the same timestamp representation.

Common Pitfalls

The biggest pitfall is using NSDateFormatter without setting a stable locale for machine-readable formats. User locale can change parsing behavior in ways that are hard to debug.

Another mistake is ignoring timezone assumptions. A string without timezone information is not automatically universal.

Developers also often use a custom format for ISO 8601 strings when NSISO8601DateFormatter would be simpler and less error-prone.

Finally, do not think of this as "casting" between NSString and NSDate. It is parsing and formatting, and that means the format rules have to match exactly.

Summary

  • Use NSDateFormatter to parse and format custom date strings.
  • Set en_US_POSIX for stable machine-readable formats.
  • Set the timezone explicitly when the meaning of the string depends on it.
  • Prefer NSISO8601DateFormatter for ISO 8601 timestamps.
  • Treat the conversion as parsing and formatting, not as a direct type conversion.

Course illustration
Course illustration

All Rights Reserved.