Using DateFormatter with TimeZone to format dates in Swift - swift

How can I parse a date that has only date information (without time), like 2018-07-24
Im trying with
let dateFormatter = DateFormatter()
dateFormat.dateFormat = "yyyy-MM-dd"
dateFormatter.dateFormat = dateFormat
dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
dateFormatter.date(from: "2018-07-24")
prints day 23
It looks like it uses 00:00:00 as default time and then transform it into UTC results into the day before...
How can I change that?

Seems that you set time zone for formatter to UTC but then try to get the day in your local time zone.
If you use this code - you will see the 24-th day
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
let date = dateFormatter.date(from: "2018-07-24")
print(dateFormatter.string(from: date!)) // prints "2018-07-24"
But if you use "Calendar" to get the day component from the date you will get the day with your timeZone offset.
So for example in my time zone I see the 24th day (GMT+02) using this code
var calendar = Calendar.current
let day = calendar.component(.day, from: date!)
print(day) // prints 24
But if I set the time zone for calendar somewhere in USA I see the 23rd day
var calendar = Calendar.current
calendar.timeZone = TimeZone.init(abbreviation: "MDT")!
let day = calendar.component(.day, from: date!)
print(day) // prints 23
So the calendar uses your local time zone to get the component from date
So if you need to get the day component from date use the same time zone you used to parse the date from string.
var calendar = Calendar.current
calendar.timeZone = TimeZone(abbreviation: "UTC")!
let day = calendar.component(.day, from: date!)
print(day) // prints 24

Related

From UTC to local time doesn't consider daylight saving swift

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.

Swift: startOfDay function returning 5:00 AM

I am calling the startOfDay function on the current date but I am getting 05:00 instead of 00:00. Any input on why this is happening would be appreciated.
Code:
let date = Calendar.current.startOfDay(for: Date())
print(date)
output:
2020-08-05 05:00:00 +0000
That's because you're printing Date object directly it considers the time-zone. You can provide a date formatter to convert it.
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
let date = Calendar.current.startOfDay(for: Date())
let string = dateFormatter.string(from: date)
print(string)

How can I determine the time zone of a given (local) date

From an API I get the following two date strings. Those dates show the time of a weather observation of a weather station that’s located in some time zone.
dateUTC = "2019-06-14T18:00:00Z"
dateLocal = "2019-06-14 20:00:00"
How can I determine the time zone the weather station is in?
(Not the time zone of the user!)
I've tried to use the DateFormatter, but unfortunately the local date gets immediately transformed to GMT - and it's then identical with the UTC date.
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
let dateUTC = dateFormatter.date(from: current.currentObservation[0].timeUTC)!
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let dateLocal = dateFormatter.date(from: current.currentObservation[0].timeLocal)!
I would like to see as the result of the above date(s):
Time zone = GMT+2
The answer was quite simple - still I didn't see it for hours. The trick is to set a timeZone for the DateFormatter.
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
let dateUTC = dateFormatter.date(from: current.currentObservation[0].timeUTC)!
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
let dateLocal = dateFormatter.date(from: current.currentObservation[0].timeLocal)!
let difference = Calendar.current.dateComponents([.second], from: dateUTC, to: dateLocal).second!

Swift 3.0 Converting String to Date

I'm trying to convert String date to local timeZone date then convert it back to Date with my current timeZone first method is working well:
let date = convertToLocalTimeZone(dateStr:"2018-05-30T14:13:20.000Z")
print(date)
the following is printed which is right:
2018-05-30 16:13GMT+2
let newDate = convertStringToDate(dateStr:date)
print(newDate)
//Converted back to UTC Time Zone :(
2018-05-30 14:13:00 +0000
func convertToLocalTimeZone(dateStr:String)->String{
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:sss.SSSZ"
dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
let date = dateFormatter.date (from: dateStr)
dateFormatter.timeZone = TimeZone(secondsFromGMT: getSecondsFromGMT())
dateFormatter.dateFormat = "yyyy-MM-dd HH:mmz"
let strVal = dateFormatter.string(from: date!)
return strVal
}
The problem happens when i try to convert the new String date with my local timeZone to date it returns wrong timeZone:
func convertStringToDate(dateStr:String)->Date{
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mmz"
// dateFormatter.timeZone = TimeZone(abbreviation: "GMT+2")
let date = dateFormatter.date (from: dateStr)
let calendar = Calendar.current
let components = calendar.dateComponents([.year, .month, .day, .hour], from: date!)
let finalDate = calendar.date(from:components)
return finalDate!
}
Any Help will be much appreciated
I think your code is alright. You just have to understand that Date represents a point in time. It does not know anything about time zones. Time zones appears only when you format the date, so only in a String will you ever see a time zone. No matter how you create a Date, you are going to see it end up in UTC when it is printed directly.
So if you want to show a date in a time zone, format it, just like you did in convertToLocalTimeZone.
If you want, you could create your own date with a Date and a TimeZone:
struct ZonedDate: CustomStringConvertible {
var date: Date
var timeZone: TimeZone
var description: String {
// format the date using timeZone here...
}
}

UTC to local time conversion not working in Swift 2

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")