Date formatter for a certain format of date - ios

I might missing something, but I can't compose proper date formatter string for the date:
2016-01-14T10:24:26+0000
What is 'T' here? and how to include timezone?
My string does not work: #"yyyy-MM-dd'T'hh:mm:ss Z"

You have to use 'T' in single quotes like below format to retrive string ftom date:
yyyy-MM-dd'T'hh:mm:ssZ
Let me know.

NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = #"yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'";
NSDate *yourDate = [dateFormatter dateFromString:myString];

Related

NSDateFormatter doesn't support long-form day periods ('b' or 'B')

NSDateFormatter doesn't seem able to use the 'B' or 'b' format specifiers. 'B' is a little like 'a' (am/pm), but it outputs things like "at night" or "in the morning".
For example, this code:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
NSLocale* locale = [[NSLocale alloc] initWithLocaleIdentifier:#"en-US"];
NSString *dateTemplate = [NSDateFormatter dateFormatFromTemplate:#"h:mmB"
options:0
locale:locale];
[dateFormatter setDateFormat:dateTemplate];
[dateFormatter setLocale:locale];
NSString* now = [dateFormatter stringFromDate:[NSDate date]];
NSLog(#"String:\t%#\ndateTemplate:\t%#",
now,
dateFormatter.dateFormat);
...prints this:
String: 10:23 PM // Should be "10:23 at night"
dateTemplate: h:mm a // Note that 'B' turned into 'a' (am/pm)
Skipping dateFormatFromTemplate and putting the format directly into the formatter has the same effect.
The docs say that iOS 7 and later use tr35-31. It's unclear whether that spec supports 'B'. The formatting table for version 31 mentions 'a', but does not mention 'B'. On the other hand, the spec for all of tr35 does indeed mention 'B'.
If you download the actual CLDR data for version 31, you can find dayPeriod entries for "in the evening" etc.
The data exists; is there another formatting string I can use to get longer "day period" strings?
You are correct that B is used for a "natural language" description of the day period. However, the problem you're experiencing is arising from using it in a date format template.
It would seem that the CLDR does not recognize that it should keep B in a date format string when you ask it to localize a template format. Thus, it's substituting a back in to the final format string.
Incidentally, if you run through +[NSLocale availableLocaleIdentifiers], you'll see that there isn't any locale that support B in a template string.
However, if you use B in a date format string directly, then it works as expected:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = #"h:mm B";
NSLog(#"%#", [dateFormatter stringFromDate:[NSDate date]]);
Outputs:
12:57 in the afternoon
I'm able to get it to work in a iOS playground in Xcode 9. Sorry, the code below is in Swift, but it does seem to be working for me.
let loc = Locale(identifier: "en-US")
let testDF = DateFormatter()
testDF.dateFormat = "MM-dd-yyyy HH:mm"
testDF.locale = loc
let df = DateFormatter()
df.dateFormat = "h:mm B"
df.locale = loc
df.string(from: testDF.date(from: "09-21-2018 17:22")!) // "5:22 in the afternoon"
df.string(from: testDF.date(from: "09-21-2018 19:22")!) // "7:22 in the evening"
df.string(from: testDF.date(from: "09-21-2018 22:22")!) // "10:22 at night"
df.dateFormat // "h:mm B"

how to convert date according to time zones

So in my project a user from USA set some time say it was 10:30 am
and now when a person some another country see that time then it should be according to their timezone .
For Example in USA it is 5:30 am now
and in india it is 6:30 pm , so if after 5 hours a person in india sees that then that person should see 6:30 pm for that post
Use php function gmdate()
string gmdate(string $format[,int $timestamp= time()] )
Identical to the date()function except that the time returned is Greenwich Mean Time (GMT).
Parameters format The format of the outputted date string. See the formatting options for the date() function. timestamp The optional timestamp parameter is an integer Unix timestamp that defaults to the current local time if a timestamp is not given. In other words, it defaults to the value of time().Return Values Returns a formatted date string. If a non-numeric value is used for timestamp, FALSE is returned and an E_WARNING level error is emitted.
in timestamp add the interval to.
Ex if GMT zone is 5 say then add timestamp+5*60*60
Use below function:
class func getDateWithFormat(format: String) -> NSDate {
var dateFormatter: NSDateFormatter = NSDateFormatter()
dateFormatter.timeZone = NSTimeZone.localTimeZone()
dateFormatter.dateFormat = format
var newDate: NSDate = dateFormatter.dateFromString(dateFormatter.stringFromDate(NSDate()))
return newDate
}
Eg: var todaysDate: NSDate = NSDate.getDateWithFormat("dd:mm:yyyy hh:mm:ss a")
I created the below function to solve this problem.
How it works: suppose this was your local time converted to GMT zero - 2016-04-14 21:00:00 +0000
and when I convert it using following function, I'm here in New Delhi India, which has GMT+05:30, then I will get time 2:30 of morning.
+(NSString*)getLocalTimeFromGMTzero : (NSString*)GMTzerioTimeString {
NSDateFormatter *df = [NSDateFormatter new];
[df setDateFormat:#"yyyy-MM-dd HH:mm"];
//Create the date assuming the given string is in GMT
df.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
NSDate *date = [df dateFromString:GMTzerioTimeString];
//Create a date string in the local timezone
df.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:[NSTimeZone localTimeZone].secondsFromGMT];
NSString *localDateString = [df stringFromDate:date];
NSLog(#"date = %#", localDateString);
return localDateString;
}

NSDateFormatter setDateFormat is not returning value correctly

In my app, I have below code:
if ([fieldValue isKindOfClass:[NSString class]]) {
NSDateFormatter *formatter = [NSDateFormatter new];
[formatter setDateFormat:#"MM/dd/yyyy"];
resultValue = [formatter dateFromString:fieldValue];
}
fieldValue is set from a datePicker and let's say the value I got is "2016-03-12 01:13:36 +0000"
In my code, I initialized new NSDateFormatter and called setDateFormat function to set the resultValue in form of "MM/dd/yyyy". For example, 01/13/2016.
However, the value I'm getting for resultValue is also 2016-03-12 01:13:36 +0000.
I'm not sure why this formatter is not working correctly.
You could get the right result as #RyanR described above.
In case you still prefer string as input, you need to tell your formatter the format of the input, and then convert string to NSDate first
let string = "2016-03-12 01:13:36 +0000"
let formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd hh:mm:ss +zzzz"
let date = formatter.dateFromString(string)
Once you have NSDate value, you can convert it to whatever format you like. In your case, if you want to have MM/dd/yyyy, then:
formatter.dateFormat = "MM/dd/yyyy"
let resultValue = formatter.stringFromDate(date!)
This code above give you exactly what you expected
About date format pattern, you could take a look at this link
Well, UIDatePicker has a property named date that you can get the selected NSDate value straight out of.
NSDate *selectedDate = datePicker.date;
Your code example is using a string as the source value, that doesn't make sense within the context of the details that you have provided. Are you sure you aren't trying to format an NSDate object into 'MM/dd/yyyy'? It's very unclear what you are trying to accomplish, but if that is the case you'll want to call -stringFromDate: and pass it your NSDate instance, like so:
NSString *formattedDateString = [formatter stringFromDate:datePicker.date];
You are calling dateFromString. That takes a date STRING the specified format and converts it to an NSDate (an object) An NSDate object does not have an internal format. It is a moment in time, recorded internally as a time in UTF.
Any time you log an NSDate using NSLog (or the debugger "po" or "expression" commands) you will see the date as a string in UTF format, as you show.
If you want the output to be a string, you need to use a date formatter's stringFromDate to convert the date to a string
If you want to convert a date string in one format to another format, you have to convert the date string to an NSDate using one date formatter's dateFromString method, then convert the resulting date to another string using a different date formatter's stringFromDate method

Converting NSString into NSDAte once again

i have a label which is :
_labelCell.text = [2014-06-22 20:27:48 +0000];
What i want to do is to convert this string into NSDate so i can format it into something like : EEEE dd MM yyyy
i try :
// convert to date
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"YYYY-MM-dd'T'HH:mm:ss'+0000'"];
NSDate *dte = [dateFormat dateFromString:str];
NSLog(#"Date: %#", dte);
but it always give me a NULL NSDate
Can someone help me on this little thing ?
Thank you very much.
Your date format needs to resemble the format of the date. See http://www.unicode.org/reports/tr35/tr35-31/tr35-dates.html#Date_Format_Patterns for the format patterns. For your date 2014-06-22 20:27:48 +0000 you need to use "yyyy-MM-dd HH:mm:ss ZZZ". Note that it must be "yyyy", not "YYYY", and the zone field should be parsed rather than treated as a literal. There is no "T" separating date and time.
Your date formatter is expecting a T in between the date and time. It returns null because there the string has a space instead of a T.
You're also missing a space before the timezone.
Fix those two issues, and it should work:
dateFormat.dateFormat = #"YYYY-MM-dd HH:mm:ss '+0000'";
Beware this might give you the wrong date, because of time zone issues. Test that out, and if it doesn't work adjust accordingly with dateFormat.timeZone = ...

How do I get an ISO 8601 date on iOS?

It's easy enough to get the ISO 8601 date string (for example, 2004-02-12T15:19:21+00:00) in PHP via date('c'), but how does one get it in Objective-C (iPhone)? Is there a similarly short way to do it?
Here's the long way I found to do it:
NSDateFormatter* dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
dateFormatter.dateFormat = #"yyyy-MM-dd'T'HH:mm:ssZ";
NSDate *now = [NSDate date];
NSString *formattedDateString = [dateFormatter stringFromDate:now];
NSLog(#"ISO-8601 date: %#", formattedDateString);
// Output: ISO-8601 date: 2013-04-27T13:27:50-0700
It seems an awful lot of rigmarole for something so central.
Use NSDateFormatter:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
NSLocale *enUSPOSIXLocale = [NSLocale localeWithLocaleIdentifier:#"en_US_POSIX"];
[dateFormatter setLocale:enUSPOSIXLocale];
[dateFormatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ssZZZZZ"];
[dateFormatter setCalendar:[NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian]];
NSDate *now = [NSDate date];
NSString *iso8601String = [dateFormatter stringFromDate:now];
And in Swift:
let dateFormatter = DateFormatter()
let enUSPosixLocale = Locale(identifier: "en_US_POSIX")
dateFormatter.locale = enUSPosixLocale
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
dateFormatter.calendar = Calendar(identifier: .gregorian)
let iso8601String = dateFormatter.string(from: Date())
iOS 10 introduces a new NSISO8601DateFormatter class to handle just this. If you're using Swift 3, your code would be something like this:
let formatter = ISO8601DateFormatter()
let date = formatter.date(from: "2016-08-26T12:39:00Z")
let string = formatter.string(from: Date())
As a complement to maddy's answer, the time zone format should be "ZZZZZ" (5 times Z) for ISO 8601 instead of a single "Z" (which is for RFC 822 format).
At least on iOS 6.
(see http://www.unicode.org/reports/tr35/tr35-25.html#Date_Format_Patterns)
An often overlooked issue is that strings in ISO 8601 format might have milliseconds and might not.
In other words, both "2016-12-31T23:59:59.9999999" and "2016-12-01T00:00:00" are legit, but if you are using static-typed date formatter, one of them won't be parsed.
Starting from iOS 10 you should use ISO8601DateFormatter that handles all variations of ISO 8601 date strings. See example below:
let date = Date()
var string: String
let formatter = ISO8601DateFormatter()
string = formatter.string(from: date)
let GMT = TimeZone(abbreviation: "GMT")
let options: ISO8601DateFormatOptions = [.withInternetDateTime, .withDashSeparatorInDate, .withColonSeparatorInTime, .withTimeZone]
string = ISO8601DateFormatter.string(from: date, timeZone: GMT, formatOptions: options)
For iOS 9 and below use the following approach with multiple data formatters.
I haven't found an answer that covers both cases and abstracts away this subtle difference. Here is the solution that addresses it:
extension DateFormatter {
static let iso8601DateFormatter: DateFormatter = {
let enUSPOSIXLocale = Locale(identifier: "en_US_POSIX")
let iso8601DateFormatter = DateFormatter()
iso8601DateFormatter.locale = enUSPOSIXLocale
iso8601DateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
iso8601DateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
return iso8601DateFormatter
}()
static let iso8601WithoutMillisecondsDateFormatter: DateFormatter = {
let enUSPOSIXLocale = Locale(identifier: "en_US_POSIX")
let iso8601DateFormatter = DateFormatter()
iso8601DateFormatter.locale = enUSPOSIXLocale
iso8601DateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss'Z'"
iso8601DateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
return iso8601DateFormatter
}()
static func date(fromISO8601String string: String) -> Date? {
if let dateWithMilliseconds = iso8601DateFormatter.date(from: string) {
return dateWithMilliseconds
}
if let dateWithoutMilliseconds = iso8601WithoutMillisecondsDateFormatter.date(from: string) {
return dateWithoutMilliseconds
}
return nil
}
}
Usage:
let dateToString = "2016-12-31T23:59:59.9999999"
let dateTo = DateFormatter.date(fromISO8601String: dateToString)
// dateTo: 2016-12-31 23:59:59 +0000
let dateFromString = "2016-12-01T00:00:00"
let dateFrom = DateFormatter.date(fromISO8601String: dateFromString)
// dateFrom: 2016-12-01 00:00:00 +0000
I also recommend checking Apple article about date formatters.
So use Sam Soffee's category on NSDate found here. With that code added to your project, you can from then on use a single method on NSDate:
- (NSString *)sam_ISO8601String
Not only is it one line, its much faster than the NSDateFormatter approach, since its written in pure C.
Just use NSISO8601DateFormatter from Foundation framework.
let isoDateFormatter = ISO8601DateFormatter()
print("ISO8601 string: \(isoDateFormatter.string(from: Date()))")
// ISO8601 string: 2018-03-21T19:11:46Z
https://developer.apple.com/documentation/foundation/nsiso8601dateformatter?language=objc
Update
From iOS 10, you can just use NSISO8601DateFormatter from Foundation
Original answer
From IS8601, the problems are the representation and time zone
ISO 8601 = year-month-day time timezone
For date and time, there are basic (YYYYMMDD, hhmmss, ...) and extended format (YYYY-MM-DD, hh:mm:ss, ...)
Time zone can be Zulu, offset or GMT
Separator for date and time can be space, or T
There are week format for date, but it is rarely used
Timezone can be a lot of spaces after
Second is optional
Here are some valid strings
2016-04-08T10:25:30Z
2016-04-08 11:25:30+0100
2016-04-08 202530GMT+1000
20160408 08:25:30-02:00
2016-04-08 11:25:30 +0100
Solutions
Parse step by step, like soffes ISO8601
Convert to basic format, like onmyway133 ISO8601
NSDateFormatter
So here is the format that I'm using in onmyway133 ISO8601
let formatter = NSDateFormatter()
formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
formatter.dateFormat = "yyyyMMdd HHmmssZ"
About the Z identifier Date Field Symbol Table
Z: The ISO8601 basic format with hours, minutes and optional seconds fields. The format is equivalent to RFC 822 zone format (when optional seconds field is absent)
About locale Formatting Data Using the Locale Settings
Locales represent the formatting choices for a particular user, not the user’s preferred language. These are often the same but can be different. For example, a native English speaker who lives in Germany might select English as the language and Germany as the region
About en_US_POSIX Technical Q&A QA1480 NSDateFormatter and Internet Dates
On the other hand, if you're working with fixed-format dates, you should first set the locale of the date formatter to something appropriate for your fixed format. In most cases the best locale to choose is "en_US_POSIX", a locale that's specifically designed to yield US English results regardless of both user and system preferences. "en_US_POSIX" is also invariant in time (if the US, at some point in the future, changes the way it formats dates, "en_US" will change to reflect the new behaviour, but "en_US_POSIX" will not), and between machines ("en_US_POSIX" works the same on iOS as it does on OS X, and as it it does on other platforms).
Interesting related quetions
Converting an ISO 8601 timestamp into an NSDate: How does one deal with the UTC time offset?
Why NSDateFormatter can not parse date from ISO 8601 format
Milliseconds NSDateFormatter to parse ISO8601 with and without milliseconds
Based on this gist: https://github.com/justinmakaila/NSDate-ISO-8601/blob/master/NSDateISO8601.swift, the following method can be used to convert NSDate to ISO 8601 date string in the format of yyyy-MM-dd'T'HH:mm:ss.SSSZ
-(NSString *)getISO8601String
{
static NSDateFormatter *formatter = nil;
if (!formatter)
{
formatter = [[NSDateFormatter alloc] init];
[formatter setLocale: [NSLocale localeWithLocaleIdentifier:#"en_US_POSIX"]];
formatter.timeZone = [NSTimeZone timeZoneWithAbbreviation: #"UTC"];
[formatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss.SSS"];
}
NSString *iso8601String = [formatter stringFromDate: self];
return [iso8601String stringByAppendingString: #"Z"];
}
With iOS 15 you get ISO860 as follows:
let iso8601String = Date.now.ISO8601Format()
If you are here because of a search result of the opposite way, here's the easiest solution:
let date = ISO8601DateFormatter().date(from: dateString)
This is a little bit simpler and puts the date into UTC.
extension NSDate
{
func iso8601() -> String
{
let dateFormatter = NSDateFormatter()
dateFormatter.timeZone = NSTimeZone(name: "UTC")
let iso8601String = dateFormatter.stringFromDate(NSDate())
return iso8601String
}
}
let date = NSDate().iso8601()
Using Swift 3.0 and iOS 9.0
extension Date {
private static let jsonDateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(identifier: "UTC")!
return formatter
}()
var IOS8601String: String {
get {
return Date.jsonDateFormatter.string(from: self)
}
}
init?(fromIOS8601 dateString: String) {
if let d = Date.jsonDateFormatter.date(from: dateString) {
self.init(timeInterval: 0, since:d)
} else {
return nil
}
}
}

Resources