Convert NSDate to String with a specific timezone in SWIFT - ios

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:

Related

I can't convert iso8601 to string swift

I have a string coming from API and its format will be like this
"2021-03-01T15:00:00+07:00"
so i try to convert this string to date using this code
// string to date
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
let date = dateFormatter.date(from: isoDate)!
print("date from date Formatter = \(date)")
// convert date back to string
dateFormatter.dateFormat = "EEEE HH:mm"
let dateString = dateFormatter.string(from: date)
print("date string \(dateString)")
return dateString
The result that I expect is -> "2021-03-01 08:00:00 +0000", "Monday 15:00"
When I try this on playground the result is what I want, but when I try this on my project the result is
-> "1478-03-01 08:00:00 +0000", "Sunday 14:42"
How can I change the result to the same as i expect? Thanks
It looks like you are using a different calendar than you expect in your project (buddhist maybe?) and I guess this is because you haven't set one explicitly so it's the one set in System Preferences.
So if you for some reason do not want to use the users current calendar (and locale and time zone) you need to set those properties on your date formatter instance
//Gregorian calendar
dateFormatter.calendar = Calendar.init(identifier: .gregorian)
//UTC time zone
dateFormatter.timeZone = TimeZone(identifier: "UTC")
//English locale
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
This will give you the expected output.
Note that the playground is a bit inconsequent in what it uses and it seems to be a mix of what we have set in our System preferences and hardcoded values.

Get the format of date | Swift | iOS

As per the requirement, my API might return date in either "2018-01-01" or "01-01-2018" or "2018-01-01T00:00:00" format
How can I check the format of the date?
eg: my code for API response "2018-01-01" should return me "yyyy-MM-dd" etc..
I can do this by checking length of my characters and by assigning date format accordingly..but i feel this is not the right approach.
You just need to define your date formats and try each of them. One of them will succeed. Just make sure all your date strings are from the same timezone (I suppose they are all UTC) and don't forget to set the date formatter locale to "en_US_POSIX" when working with fixed format dates:
let dateStrings = ["2018-01-01", "01-01-2018", "2018-01-01T00:00:00"]
let dateFormats = ["yyyy-MM-dd'T'HH:mm:ss", "yyyy-MM-dd", "MM-dd-yyyy"]
let formatter = DateFormatter()
formatter.calendar = Calendar(identifier: .iso8601)
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(secondsFromGMT: 0)
var dates: [Date] = []
for dateString in dateStrings {
for dateFormat in dateFormats {
formatter.dateFormat = dateFormat
if let date = formatter.date(from: dateString) {
dates.append(date)
print("dateFormat:", dateFormat)
print("date:", date)
break
}
}
}
This will print
dateFormat: yyyy-MM-dd
date: 2018-01-01 00:00:00 +0000
dateFormat: MM-dd-yyyy
date: 2018-01-01 00:00:00 +0000
dateFormat: yyyy-MM-dd'T'HH:mm:ss
date: 2018-01-01 00:00:00 +0000
It's risky to have ambiguous date formats in an API. But if you are stuck with this you could make multiple DateFormatters and configure each for a specific format (by setting their dateFormat accordingly) and attempt to convert the string using each of these in turn. Once you have a success, you know which format you got (it's dateFormat).

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

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.

GMT date string getting converted to UTC Date

**
GET GMT DATE STRING
**
func getGMTString(dateAsDate:NSDate) -> String
{
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss zzz"//this your string date format
// dateFormatter.locale = NSLocale.currentLocale()
// dateFormatter.timeZone = NSTimeZone(name: "GMT")
let date = dateFormatter.stringFromDate(dateAsDate)
return date
}
OUTPUT
startDate---2016-06-29 00:00:00 GMT+5:30
endDate----2016-06-30 03:57:39 GMT+5:30
NOW TRYING to get GMT Date object from output string
func getGMTDate(string:String) -> NSDate {
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss zzz"//this your string date format
// dateFormatter.timeZone = NSTimeZone(abbreviation: "GMT")!
// dateFormatter.locale = NSLocale.currentLocale()
let date = dateFormatter.dateFromString(string)
return date!
}
PROBLEM: OUTPUT DATE OBJECT MESS
startDateOBJECT---2016-06-28 18:30:00 +0000 endDateOBJECT----2016-06-30 17:30:00 +0000
Unable to figure what is going wrong
I don't understand your step 3. I looks like you're using NSLog or a Swift print to display the resulting date. That is ALWAYS done in UTC.
If you want to view your date in a different format, or with your local time zone, you need a second date formatter to convert the NSDate to an output date string.
Here's the flow:
input date string -> input date formatter -> NSDate
NSDate -> output date formatter -> display date in local time zone

Swift make NSDate from string not working as expected

I'm trying to convert a date string into a NSDate. I have this input date string 2014-10-09 17:57 and this timezone +4 or Asia/Dubai and for some reason, i get this NSDate after i execute the code below 2014-10-09 13:57:00 +0000.
let dateString = "2014-10-09 17:57"
let formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm"
formatter.timeZone = NSTimeZone(name: "Asia/Dubai")
println("\(formatter.dateFromString(dateString))")
I want to get a date like this 2014-10-09 17:57 +0400. What am i doing wrong? Can you help me figure it out? I need the date to make some calculations between this one and another one which is correctly formatted with timezone.
It helps to breakup compound statements. The result of the formatter is a date, seconds since the reference date (GMT), it has no concept of a format or timezone.
The println() displays the date based ion the default formatting of there description method.
If you want it display in a particular way use a date formatter to create the desired string representation.
Example:
let dateString = "2014-10-09 17:57"
let formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm"
formatter.timeZone = NSTimeZone(name: "Asia/Dubai")
let date = formatter.dateFromString(dateString)
println("date: \(date!)") // date: 2014-10-09 13:57:00 +0000
formatter.dateFormat = "yyyy-MM-dd HH:mm Z"
let formattedDateString = formatter.stringFromDate(date!)
println("formattedDateString: \(formattedDateString)") // formattedDateString: 2014-10-09 17:57 +0400

Resources