Cannot convert to NSDate from this specific date (1994-04-01) String - ios

Something strange happen to me.
I'm not able to convert this specific date (1994-04-01) String.
Can anyone check this and let me know if it reproduce in your code?
Steps to Reproduce:
Swift:-
let dateString = "1994-04-01"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let dateFromString = dateFormatter.date(from: dateString)
Obj c:-
NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
[formatter setDateFormat:#"yyyy-MM-dd"];
NSString *birthdayStr = #"1994-04-01";
NSDate *birthday = [formatter dateFromString:birthdayStr];
Expected Results:
birthday = 1994-03-31 21:00:00 +0000
In UTC
Actual Results:
birthday = nil
Version:
Xcode ver :- Version 8.1 (8B62)
OS X ver :- 10.12.1 (16B2555)
you can try any different date then (1994-04-01) and it will work fine.

Test code:
import Foundation
for timeZoneId in TimeZone.knownTimeZoneIdentifiers {
let dateString = "1994-04-01"
let dateFormatter = DateFormatter()
dateFormatter.timeZone = TimeZone(identifier: timeZoneId)
dateFormatter.dateFormat = "yyyy-MM-dd"
if dateFormatter.date(from: dateString) == nil {
print(timeZoneId)
}
}
Output:
Asia/Amman
Asia/Damascus
Asia/Gaza
Asia/Hebron
Asia/Jerusalem
I conclude your system time zone is set to one of the ones printed. If I type “jerusalem time zone 1994” into Google, the first result tells me that Daylight Saving Time started at midnight on April 1 in 1994. This means there was no midnight. The first instant of April 1, 1994 was in fact 1 AM in that time zone.
A DateFormatter uses a time of day of midnight by default when not parsing a time of day from the string. This makes it fail when midnight doesn't exist on the date in the string.
The solution is to not use midnight as your default time of day. Noon is a much safer default time. So, one solution is to include the time of day in the input and parse it in the format:
let dateString = "1994-04-01 12:00:00"
let dateFormatter = DateFormatter()
dateFormatter.timeZone = TimeZone(identifier: timeZoneId)
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
Another solution is to give the date formatter a default date that is noon of some day:
// Reference date was 00:00:00 UTC on 1 January 2001. This is noon of the same day in UTC.
dateFormatter.defaultDate = Date(timeIntervalSinceReferenceDate: 12*60*60)
If you are going to do any date parsing or manipulation on iOS or macOS, it would be a very good idea to watch WWDC 2013 Session 227: Solutions to Common Date and Time Challenges.

Related

why Date will return nil when using correct format in swift 4?

so here is the string Date that I want to Convert
2019-03-22T00:00:00
and here is the problem
Remember that I used "yyyy-MM-dd'T'HH:mm:ss" or "yyyy-MM-ddTHH:mm:ss" or "yyyy-MM-dd HH:mm:ss" or yyyy-MM-dd'T'HH:mm:ssZ and some other similar formats
You have to set a time zone and locale when parsing internet dates:
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
// necessary to avoid daylight saving (and other time shift) problems
dateFormatter.timeZone = TimeZone(secondsFromGMT: TimeZone.current.secondsFromGMT())
// necessary to avoid problems with 12h vs 24h time formatting
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
print(dateFormatter.date(from: "2019-03-22T00:00:00"))
The default time zone contains information about daylight saving time and some specific times does not exist there. Instead, we have to use a generic time zone.
See https://developer.apple.com/library/archive/qa/qa1480/_index.html
22 March 2019 around midnight is the day & time when daylight saving change in Iran makes an hour non-existent.
The same can be achieved using ISO8601DateFormatter:
let dateFormatter = ISO8601DateFormatter()
dateFormatter.formatOptions = ISO8601DateFormatter.Options.withInternetDateTime.subtracting(.withTimeZone)
print(dateFormatter.date(from: "2019-03-22T00:00:00"))
Try this function might help
public func dateFormatter(strDate: String) -> String{
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "fa_IR")
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
let date = dateFormatter.date(from: strDate)
let dateString = dateFormatter.string(from: date!)
return dateString
}
dateFormatter.isLenient = true
Ignores missing hours during daylight saving time offset

Convert 12 hour date format into 24 hour format & vice versa in swift?

I have a date from a UIControl. I get date as string such as 06-12-2016 01:25 PM. Now I want to convert it into a format as 2016-12-06 13:25:00 I have tried below code t do so but it just gives me wrong date for ex. 2016-12-06 18:55:00. I have used below code for this:
func converStingToDate(str_date:String)->String
{
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd-MM-yyyy H:mm a"
let date = dateFormatter.date(from: str_date)
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
return dateFormatter.string(from: date!)
}
Please suggest me a better code. Also if you guys can help me to understand all this date formatting concept how it is done ?
The code is correct and the date is correct (although you should use h for 12-hour hour).
Your time zone is UTC+0530 and print() displays the date in UTC.
If you need to print the correct local time set the time zone of the formatter to UTC:
dateFormatter.timeZone = TimeZone(abbreviation: "UTC")`

Converting time from GMT in iOS behaving oddly (Reverse)

So I am trying to convert some times I receive in UTC/GMT to the local time zone using the following code:
let gmtFormatter: NSDateFormatter = NSDateFormatter()
gmtFormatter.timeZone = NSTimeZone(name: "GMT")
gmtFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let gmtDate: NSDate = gmtFormatter.dateFromString(dateString)!
print("GMT \(gmtDate)")
let localFormatter: NSDateFormatter = NSDateFormatter()
localFormatter.timeZone = NSTimeZone.localTimeZone()
localFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let localDate: NSDate = localFormatter.dateFromString(gmtFormatter.stringFromDate(gmtDate))!
print("Local \(localDate)")
However, I find that the conversion is working in revers. PST is UTC-8 and the outputs are 8 hours ahead instead of 8 hours behind. So I tested with a London Time Zone (CET) which is UTC+1 and should be 1 hour ahead of GMT. The results was a time that was 1 hour behind.
This was the string I am testing with: "2016-02-24 00:05:54"
For PST this should convert to 2016-02-23 04:05:54, but instead converts to 2016-02-24 08:05:54 (notice the way it should be is on the 23rd and not the 24th)
For CET this should convert to 2016-02-24 01:05:54, but instead converts to 2016-02-23 23:05:54 (notice the way it should be is on the 24th and not the 23rd)
Am I missing something glaring?
The problem is that in the second part of your code...
let localDate: NSDate =
localFormatter.dateFromString(gmtFormatter.stringFromDate(gmtDate))!
... you're doing the opposite of what you want. An NSDate is absolute. Its string representation is what is volatile, as it were. So having turned a string into a date with your first formatter, what you now want to do is turn that date into a string with your second formatter.
For example, I'm in California. Now, watch this:
let dateString = "2016-02-24 10:09:08"
let gmtFormatter: NSDateFormatter = NSDateFormatter()
gmtFormatter.timeZone = NSTimeZone(name: "GMT")
gmtFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let gmtDate: NSDate = gmtFormatter.dateFromString(dateString)!
print("GMT \(gmtDate)")
let localFormatter: NSDateFormatter = NSDateFormatter()
localFormatter.timeZone = NSTimeZone.localTimeZone()
localFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let localDateString = localFormatter.stringFromDate(gmtDate) // <-- !!!
print("Local \(localDateString)")
Result:
GMT 2016-02-24 10:09:08 +0000
Local 2016-02-24 02:09:08
That's correct. When it's 10 AM in London, it's 2 AM here.
To put it another way, if you think what you're doing is converting a date from one time zone to another, you have not understood what a date is. It is a date-time and a time zone. There is nothing to convert: it is completely determined, and it is correct no matter where you are, because it says what time zone it is.
Perhaps it would be a bit clearer to you if I changed the next-to-last line format to this:
localFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
The final output is then:
Local 2016-02-24 02:09:08 -0800
which is obviously correct.

Convert NSDate to String with a specific timezone in SWIFT

In my coredatabase I have an "news" entity with a NSDate attribute. My app is worldwide.
News was published 2015-09-04 22:15:54 +0000 French hour (GMT +2)
To save the date, I convert it, in UTC format.
let mydateFormatter = NSDateFormatter()
mydateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss+00:00"
mydateFormatter.timeZone = NSTimeZone(abbreviation: "UTC")
var dateToSaved : NSDate! = mydateFormatter.dateFromString(date)
The news is recorded with the date : 2015-09-04 20:15:54 +0000 (UTC)
Later in the app, I need to convert this NSDate saved in String:
let mydateFormatter = NSDateFormatter()
mydateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss+00:00"
var dateInString:String = mydateFormatter.stringFromDate(date)
Everything works perfectly if I launch the app in the same timezone when I published the news i.e GMT+2.
If I change the timezone of my device, for example UTC-4, then convert my NSDate in String, the date is not the same. I got : 2015-09-04 16:15:54 +0000
How to obtain the same UTC date as in my database for any timezone?
I'm not very comfortable with timezone, but I think my issue comes from the "+0000" in the NSDate. In all my dates, there is always +0000, it should be the right timezone, I think. But I don't know how to do.
Xcode 8 beta • Swift 3.0
Your ISO8601 date format is basic hms without Z. You need to use "xxxx" for "+0000".
"+0000" means UTC time.
let dateString = "2015-09-04 22:15:54 +0000"
let dateFormatter = DateFormatter()
dateFormatter.calendar = Calendar(calendarIdentifier: .ISO8601)
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss xxxx"
dateFormatter.locale = Locale(localeIdentifier: "en_US_POSIX")
if let dateToBeSaved = dateFormatter.date(from: dateString) {
print(dateToBeSaved) // "2015-09-04 22:15:54 +0000"
}
If you need some reference to create your date format you can use this:

Getting back a date from a string

im dealing with dates, and i'm having problems getting my date back from a string, i simplified my problem here:
let date = NSDate()
let formatter = NSDateFormatter()
formatter.dateFormat = "dd-MM-YYYY"
formatter.stringFromDate(date)
formatter.dateFromString(formatter.stringFromDate(date))
And the output is:
"25-05-2015" (Which is fine)
"Dec 21, 2014, 12:00 AM" (???)
The problem there is that Y is for weekOfYear. You have to use "dd-MM-yyyy". Btw don't forget to set your date formatter locale to "en_US_POSIX" .
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).
You should use yyyy for the year, not YYYY (which has a different meaning)
let date = NSDate()
let formatter = NSDateFormatter()
formatter.dateFormat = "dd-MM-yyyy"
let s = formatter.stringFromDate(date) // "25-05-2015"
let d = formatter.dateFromString(s) // "2015-05-24 22:00:00 UTC" (*)
(*) it's 22:00 because I'm in the +0200 timezone, so this result is effectively 2015-05-25 00:00:00 in my timezone
You should change your dateFormat to make it work , YYYY is not correct.
import Foundation
let date = NSDate()
let formatter = NSDateFormatter()
formatter.dateFormat = "dd-MM-YYYY"
var firstDate = formatter.stringFromDate(date)
formatter.dateFormat = "yyyy-MM-dd hh:mm:ss.SSSSxxx"
var secondDate = formatter.dateFromString(formatter.stringFromDate(date))
println("\(firstDate)")
println("\(secondDate)")

Resources