I have following UTC like 2020-07-15T12:32:38+00:00. I actually need to convert this string to local date in phone taking into account a timezone. Here is my try that I see from other stackoverflow answers:
func UTCToLocal(date: String) -> Date? {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
//I thought than below can help
dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
return dateFormatter.date(from: date)
}
Another approach:
func UTCToLocal2(date: String) -> Date? {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
/// I thought that specifying current time zone would help
dateFormatter.timeZone = TimeZone.current
return dateFormatter.date(from: date)
}
But none of approach works. My 2020-07-15T12:32:38+00:00 is not converted to date with my timezone. Where is my mistake?
Related
I have a string that looks like this:
"date": "2022-06-30T02:15:00.000+07:00"
And I formatted it to convert to "HH:mm" like this:
func formatTime(string: String) -> String {
let dateFormatterGet = DateFormatter()
dateFormatterGet.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
let dateFormatterPrint = DateFormatter()
dateFormatterPrint.dateFormat = "HH:mm"
let date: Date? = dateFormatterGet.date(from: string)
return dateFormatterPrint.string(from: date ?? Date())
}
The result I want it returns is 09:15, but it returns 02:15.
Can someone tell me where I went wrong? Thank you
"2022-06-30T02:15:00.000+07:00" is the date in the time zone plus 7 hours from the UTC time zone. Than this date in UTC is “ 2022-06-29T19:15:00Z”
while dateFormatterPrint has a default locale configuration according to the phone settings
You need to set UTC timezone
In this case you might want to convert the DateTime to your local time first:
Convert To LocalTime:
func utcToLocal(dateStr: String) -> String? {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "HH:mm"
dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
if let date = dateFormatter.date(from: dateStr) {
dateFormatter.timeZone = TimeZone.current
dateFormatter.dateFormat = "HH:mm"
return dateFormatter.string(from: date)
}
return nil
}
And then:
let utcTime = formatTime(string: "2022-06-30T02:15:00.000+07:00")
let localTime = utcToLocal(dateStr: utcTime)
print(localTime)
The Result:
09:15
I hope this help you solve your problem.
I am using this function to convert UTC time to my local time stamp.
func UTCToLocal(date:String, timeZone: String) -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "H:mm:ss"
dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
let dt = dateFormatter.date(from: date)
dateFormatter.timeZone = TimeZone(identifier: timeZone)
dateFormatter.dateFormat = "h:mm a"
return dateFormatter.string(from: time)
}
But this doesn't check DST. So, I am getting one hour difference. Can anyone help me with some general solution for this problem?
Thanks to Leo who have figured out the issue. I have updated the functions as:
func UTCToLocal(date:String, timeZone: String) -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
let dt = dateFormatter.date(from: date)
dateFormatter.timeZone = TimeZone(identifier: timeZone)
dateFormatter.dateFormat = "dd-MM-yyyy hh:mm aa"
return dateFormatter.string(from: dt!)
}
Now the date string in function paramter have value in this format "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'". This solves the issue.
The issue here is the lack of the date. You are always passing only the time components without the day so the daylight savings time Will always be correspondent to January 1st 2001. If you need today’s date you need to set the date formatter defaultDate property to the startOfDay for today. Btw don’t forget to set the locale first to “en_US_POSIX” before setting the fixed date format.
In my application for selecting of date, I use the date picker with "MM-dd-yyyy" format again send back to the backend with "yyyy-MM-dd" format with the following code.
func DateFromApptoWeb(_ date: String) -> String
{
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MM-dd-yyyy"
let date = dateFormatter.date(from: date)
dateFormatter.dateFormat = "yyyy-MM-dd"
return dateFormatter.string(from: date!)
}
Here I am displaying date with my format getting from backend format with the following method.
func DateFromWebtoApp(_ date: String) -> String
{
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "America/New_York")
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
let date = dateFormatter.date(from: date)
dateFormatter.dateFormat = "MM-dd-yyyy"
return dateFormatter.string(from: date!)
}
But when I display the date it is showing one day delay.
I have a method that converts my SQL date to "MM-dd-yyyy, HH:mm" in swift. I need to be able to convert this back to "yyyy-MM-dd'T'HH:mm:ss". This will be in server time and also eastern time zone.
Converting to "MM-dd-yyyy, HH:mm":
static func dateView(_ DateString: String) -> String {
var returnDate = ""
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
let string = String(DateString)
if let date = dateFormatter.date(from: string) {
dateFormatter.dateStyle = .short
dateFormatter.timeStyle = .short
returnDate = dateFormatter.string(from: date)
}
return returnDate
}
Trying to convert to "yyyy-MM-dd'T'HH:mm:ss":
static func dateToSQLDate(_ DateString: String) -> String {
var returnDate = ""
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.dateFormat = "MM/dd/yy HH:mm"
let string = String(DateString)
if let date = dateFormatter.date(from: string) {
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
//dateFormatter.timeStyle = .short
returnDate = dateFormatter.string(from: date)
}
return returnDate
}
Example would be:
var date = "3/10/16, 10:00AM"
dateToSQLDate(date)
Expected Out: 2016-03-10T10:00:00
Any ideas to what I am doing wrong?
Your date format is wrong.
Compare the string "3/10/16, 10:00AM" with the date format "MM/dd/yy HH:mm". There are three issues:
The comma is missing
The AM/PM specifier a is missing
12 hour mode is hh
static func dateToSQLDate(_ string: String) -> String {
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.dateFormat = "MM/dd/yy, hh:mma"
guard let date = dateFormatter.date(from: string) else { return "" }
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
return dateFormatter.string(from: date)
}
Try this
static func dateToSQLDate(_ DateString: String) -> String {
var returnDate = ""
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
let string = String(DateString)
if let date = dateFormatter.date(from: string) {
dateFormatter.dateFormat = "MM/dd/yy HH:mm"
returnDate = dateFormatter.string(from: date)
}
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
return returnDate
}
Others have answered your question, but a few observations:
It is probably prudent to always save your IS8601 timestamp strings in GMT/UTC/Zulu timezone (by setting the timeZone of your ISO8601 date string formatters to TimeZone(secondsFromGMT: 0), perhaps adding the X qualifier in the string to make it completely unambiguous. It shouldn’t be “server time zone” and probably shouldn’t be the device’s local time zone either.
Even better, I might suggest using the ISO8601DateFormatter instead, which sets timezones, locales, etc., automatically, making configuration less fragile.
I’d suggest instantiating two separate date formatters, one for the ISO 8601 date format (the one with the T in it), and another for presenting dates in your UI. While the ISO 8601 date formatter should use the en_US_POSIX locale (and if you use ISO8601DateFormatter, that’s taken care of for you), the UI date formatter should not (because you presumably want to show the date in the user’s device’s current locale).
I personally would suggest that your model objects don’t use a string for the date, but rather use a Date object, instead. So, use ISO8601DateFormatter when converting between Date and API strings, store the Date in your model object, and only use the DateFormatter with dateStyle and timeStyle when presenting the Date in the user interface.
So this means that rather than two string-to-string routines, you have string-to-date (and vice versa) for each of the two formatters.
Date formatters are notoriously computationally expensive to create. So you might consider creating these two formatters once, save them in ivars, and then you don’t have to repeatedly reinstantiate them.
I am trying to convert a UTC time to local timezone, but it doesn't seem to be converting it at all:
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
let date1 = dateFormatter.dateFromString(dateStringFromServer)!
dateFormatter.timeZone = NSTimeZone.localTimeZone()
let date2 = dateFormatter.dateFromString(dateStringFromServer)!
The dateStringFromServer is a string representation of a UTC date. So I was expecting date1 to be in UTC, and date2 to be in PDT (my local time zone), but they are both the same. Something wrong with my syntax?
This is what I'm getting:
dateStringFromServer: 2016-10-21T05:24:26.000Z
date1: 2016-10-21 05:24:26 +0000
date2: 2016-10-21 05:24:26 +0000
How can I get date2 be in the device's local timezone?
If you want to convert to the time zone set on the device you can do this
Swift3
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
let date1 = dateFormatter.date(from: dateStringFromServer)
// return the timeZone of your device i.e. America/Los_angeles
let timeZone = TimeZone.autoupdatingCurrent.identifier as String
dateFormatter.timeZone = TimeZone(identifier: timeZone)
let date2 = dateFormatter.string(from: date1)
Swift2
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
let date1 = dateFormatter.dateFromString(dateStringFromServer)
// return the timeZone of your device i.e. America/Los_angeles
let timeZone = NSTimeZone.localTimeZone().name
dateFormatter.timeZone = NSTimeZone(name: timeZone)
let date2 = dateFormatter.stringFromDate(date1!)
It's the same because even though you think you're setting the date formatter's time zone to the current time zone after setting the first date, it doesn't matter. If you don't set the date formatter's time zone, it automatically sets to the system time zone as specified in Apple's docs for NSDateFormatter:
If unspecified, the system time zone is used.
Therefore the date formatter's time zone is set to be the same both implicitly for the first date and explicitly for the second date because they happen to be identical, hence you're getting the same date back.
Here is the code that work in swift4.
func UTCToLocal(date:String, fromFormat: String, toFormat: String) -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = fromFormat
dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
let dt = dateFormatter.date(from: date)
dateFormatter.timeZone = TimeZone.current
dateFormatter.dateFormat = toFormat
return dateFormatter.string(from: dt!)
}
How to use :-
let localDateAsString = UTCToLocal(date: deadline!, fromFormat: "yyyy-MM-dd HH:mm:ss", toFormat: "MM-dd-yyyy hh:mm a")