I am running the following code :
if let messagedate = curr_comment["timestamp"] as? String {
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let date = dateFormatter.dateFromString(messagedate)
}
and here is the debugger output :
This started happening randomly today, I'm not sure why the date changes by 500 years through such a simple operation.
EDIT: This happens on a device that is using the Buddhist calendar.
It is because the device in question is not set for Gregorian calendar. It is using the Buddhist calendar. See Apple Technical Q&A 1480 which discusses the proper handling of date strings to gracefully handle international calendars.
If this yyyy-MM-dd HH:mm:ss format is for internal purposes (storing in database, communicating with web service, etc.), you should consider setting the locale of the formatter to en_US_POSIX. In Swift 3:
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
in Swift 2:
dateFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
Frankly, this also begs the question as to what timezone the string representation of the date is using. You generally would want to make sure that date/time strings are consistently stored in UTC/GMT. In Swift 3:
dateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
Or, in Swift 2:
dateFormatter.timeZone = NSTimeZone(forSecondsFromGMT: 0)
If you do that consistently throughout the app, you'll avoid weird timezone issues (e.g. if someone in NY posts something right now, I don't want it to tell me in CA that it happened three hours ago).
Related
One day, the app worked. The next day I updated to Xcode 11 and now the app crashes with "unexpectedly found nil" on line 27 (when executing line 15) in the picture.
I asked my co-worker who doesn't yet have Xcode 11, and his doesn't crash. we are on the same branch/commit...everything.
Any advice? any way around this?
My code:
// ticket.timeOrdered == "2019-10-03 22:54:57 +0000"
let ticketDate = ticket.timeOrdered.asCrazyDate.timeIntervalSince1970
extension String {
var asCrazyDate: Date {
let dateFormatterGet = DateFormatter()
dateFormatterGet.dateFormat = "yyyy-MM-dd HH:mm:ss +zzzz"
dateFormatterGet.timeZone = .current
return dateFormatterGet.date(from: self)!
}
}
The date format string is incorrect. The +zzzz is not an acceptable format. See the timezone related sections of the table in Date Format Patterns. The + shouldn’t be there. And zzzz is for long descriptions of the time zone (e.g. “Pacific Daylight Time”). You can verify this by using the same formatter to build a string from Date() and you’ll see that it’s not resulting in the +0000 like you might have expected.
The latest SDK’s date formatter is no longer as forgiving regarding these sorts of format string errors as the previous versions were. But rather than reverting your Xcode version, you really should just fix that date format string. For example, you could use Z instead of +zzzz, which will correctly interpret the +0000 (or whatever) as the time zone portion of the string.
A few other suggestions, if you don’t mind:
You don’t need asCrazyDate in this example. There’s no point in getting a date, using string interpolation to build the string representation, and then using a formatter to convert the string back to a date (which you originally started with). You can just use the Date directly:
func getDate() -> TimeInterval {
return Date().timeIntervalSince1970
}
Date formatters are notoriously computationally intensive to create, and if you’re using this computed property a lot, that can really affect performance. It’s better to instantiate date formatters once, if possible.
If you’re trying to build some invariant date string for some reason, it’s better to use something like ISO8601DateFormatter. So don’t build your date strings using string interpolation, and don’t build your own formatter.
let formatter = ISO8601DateFormatter()
let now = Date()
let string = formatter.string(from: now) // not "\(now)"
let date = formatter.date(from: string)
print(now, string, date)
If you’re stuck with this date format (perhaps you’ve already stored dates using this string format), you can use the custom dateFormat string, if you must. But as Technical Q&A 1480 suggests, you might want to set the locale (and I’d suggest setting the timeZone, too, so your date strings are comparable).
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(secondsFromGMT: 0)
This question already has an answer here:
DateFormatter doesn't return date for "HH:mm:ss"
(1 answer)
Closed 5 years ago.
Within our iphone app we parse a date gotten from an api call. The date returns correctly and is a valid date. Now only on some devices does it crash with the error of unexpectedly found nil while unwrapping an Optional value. Here is the code in question:
//formatDate(date: date, format: FullDateFormat)
class func formatDate(date: String, format: String)->String{
if date.characters.count == 0 {return "" }
let formatter = DateFormatter()
formatter.dateFormat = Constants.FullDateFormat
let nsDate = formatter.date(from: date)
formatter.dateFormat = format
return formatter.string(from: nsDate!)
}
nsDate is not being formatted as it is nil.
The Constants.FullDateFormat is a static string defined as "M/d/yyyy h:mm:ss a" as the date will always come in this format
The call to the class function will look like this
let newDate = Helpers.formatDate(date: "9/27/2017 9:26:51 AM", format: "h:mm a")
Some devices crash while majority don't. If we don't use the class function the app works correctly. I don't see any cause for it so if anyone sees why this may be happening and a possible solution, please let me know.
This may be a duplicate but didn't show up in any of the searches I performed. Thanks to community they pointed to another similar questions with answers already at stackoverflow. My apologies if this is a duplicate.
It is a matter of locales. DateFormatter is dependent on the device's current location settings, including date and time.
You can ensure that the formatter's locale is always static by setting its locale to en_US_POSIX:
formatter.locale = Locale(identifier: "en_US_POSIX")
See Apple's link for more details:
https://developer.apple.com/documentation/foundation/nsdateformatter
how can i return a NSDate in a predefined time zone from a string
let responseString = "2015-8-17 GMT+05:30"
var dFormatter = NSDateFormatter()
dFormatter.dateFormat = "yyyy-M-dd ZZZZ"
var serverTime = dFormatter.dateFromString(responseString)
println("NSDate : \(serverTime!)")
the above code returns the time as
2015-08-16 18:30:00 +0000
The date format has to be assigned to the dateFormat property of the date formatter instead.
let date = NSDate.date()
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let str = dateFormatter.stringFromDate(date)
println(str)
This prints the date using the default time zone on the device. Only if you want the output according to a different time zone then you would add for example
Swift 3.*
dateFormatter.timeZone = NSTimeZone(name: "UTC")
Swift 4.*
dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
also refer link http://www.brianjcoleman.com/tutorial-nsdate-in-swift/
how can i return a NSDate in a predefined time zone?
You can't.
An instance of NSDate does not carry any information about timezone or calendar. It just simply identifies one point in universal time.
You can interpret this NSDate object in whatever calendar you want. Swift's string interpolation (the last line of your example code) uses an NSDateFormatter that uses UTC (that's the "+0000" in the output).
If you want the NSDate's value as a string in the current user's calendar you have to explicitly set up a date formatter for that.
Swift 4.0
dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
If you always have the same time zone for the input string, you can create two date formatters to output the local time zone (or a specified one):
let timeFormatterGet = DateFormatter()
timeFormatterGet.dateFormat = "h:mm a"
timeFormatterGet.timeZone = TimeZone(abbreviation: "PST")
let timeFormatterPrint = DateFormatter()
timeFormatterPrint.dateFormat = "h:mm a"
// timeFormatterPrint.timeZone = TimeZone(abbreviation: "EST") // if you want to specify timezone for output, otherwise leave this line blank and it will default to devices timezone
if let date = timeFormatterGet.date(from: "3:30 PM") {
print(timeFormatterPrint.string(from: date)). // "6:30 PM" if device in EST
} else {
print("There was an error decoding the string")
}
The number 1 means 1 regardless of language. Yet in English it's spelled as one, in Spanish it's una, in Arabic it wahid, etc.
Similarly 123982373 seconds pass 1970 is going to reflect differently in different timezones or calendar formats, but's all still 123982373 seconds passed 1970
The difference between 3 seconds and 7 seconds is 4 seconds. That doesn't require a calendar. Neither you need a calendar/timezone to know the difference in time between these two Epoch times 1585420200 and 1584729000
Dates are just a timeInterval from January 1, 1970 (midnight UTC/GMT). Dates also happen to have a string representation.
Repeating Nikolia's answer, Swift's default string interpolation (2015-08-16 18:30:00 +0000) uses a DateFormatter that uses UTC (that's the "+0000" in the output).
Calendars with the use of timezones give us a contextual representation that is just easier to understand than trying to calculate the difference between two gigantic numbers.
Meaning a single date (think of a single timeInterval since 1970) will have a different string interpretations per calendar. On top of that a calendar will itself vary based on time zones
I highly recommend that you go and play around with this Epoch converter site and see how selecting a different timezone will cause the string representations for the same moment/date/timeInterval to change
I also recommend to see this answer. Mainly this part:
Timezone is just an amendment to the timestamp string, it's not considered by the date formatter.
To consider the time zone you have to set the timeZone of the formatter
dateFormatter.timeZone = TimeZone(secondsFromGMT: -14400)
I found something that could solve my problem in Obj-c, but I'm not able to translate the code, so I'm asking for a Swift solution.
I'm parsing some data from a JSON file and I get an issue retrieving the date; here is the code :
println(data) // "Fri, 16 Jan 2015 11:49:00 +0100"
var dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "EEE, dd LLL yyyy HH:mm:ss ZZZ"
let formattedDate = dateFormatter.dateFromString(data)
println(formattedDate) // returns 'Optional(2015-01-16 11:49:00 +0100)' if running on an iOs Simulator
// returns 'nil' if runnig on an iPhone
Like I write in the code comments, I get correctly the optional type of the date if I run it on an iOs Simulator or in the playground, but I get nil if it is running on an iPhone.
Can anyone help?
For the others who get here and don't read the comments of the initial post ;)
As #rintaro pointed out - and what was my problem too - you have to add a locale when you use fixed-format dates:
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
https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/DataFormatting/Articles/dfDateFormatting10_4.html#//apple_ref/doc/uid/TP40002369-SW7
So in Swift 3 you would have to add
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
I am reading the tutorial provided by Raywenderlich, Chapter 29 What’s New with Testing, and run into a strange problem.
Following is the code in the tutorial converting a string into date:
// Convert date string to date.
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss zzz"
var date: NSDate? = dateFormatter.dateFromString(dateString)
The dateString is of the form
2014-06-21 14:56:00 EST
However, the date variable is always nil.
NOTE: when playing this code in the playground, it works properly, as the image shows:
I am working in iOS SDK 8.0. Is it a bug of the SDK?
Updated
I am testing using a latest iPod Touch with iOS 8.
When you set a dateFormat string you must also set the locale property to something that is compatible with the format provided. Otherwise the locale will be based on the device settings which may not be compatible.
The date format you provided here will work with the "en" locale but it will not work with many others, such as "eu". Here's an example:
let dateString = "2014-06-21 14:56:00 EST"
let localeStr = "eu" // this will give nil
let localeStr = "us" // this will succeed
let dateFormatter = NSDateFormatter()
dateFormatter.locale = NSLocale(localeIdentifier: localeStr)
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss zzz"
var date: NSDate? = dateFormatter.dateFromString(dateString)
The problem here is "EST" which only exists in the north america. In all other locales it is an invalid timezone. If you change your date string to this:
"2014-06-21 14:56:00 UTC-5"
Then it the date will correctly format no matter what value locale is set to.
NSDateFormatter's behaviors are heavily depends on it's locale.
By default, it uses device locale.
If you want consistent result from it, You should manually specify the locale. In most cases, en_US_POSIX is the best.
The document says:
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 behavior, but en_US_POSIX will not), and between platforms (en_US_POSIX works the same on iPhone OS as it does on OS X, and as it does on other platforms).
Like this:
let dateString = "2014-06-21 14:56:00 EST"
let dateFormatter = NSDateFormatter()
dateFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss zzz"
var date: NSDate? = dateFormatter.dateFromString(dateString)