Swift: get the offset value from a date object - swift

as simple as it sounds, but it is hard to find my exact question in google.
I'm trying to ignore the UTC printed out value. I receive multiple dates, this one here is just an example: (it could be +0900, -0200, etc...)
"2017-05-01T12:30:00-0700"
once I apply it to a value using these lines:
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssxxxxx"
if let result = formatter.date(from: time) {print result}
the value of the dateTimeResult prints:
2017-05-01 19:30:00 UTC
Using swift date objects, how do I slice out the part "-0700", multiply the -7 or +7 (this example is negative) by minutes by seconds. I'll save that total as int in DB (I need it for categorizing the different timezones later). Then applying that total to the incoming date input using this line:
let output = Calendar.current.date(byAdding: .second, value: totalSecs, to: result)
The goal is to end up with this date:
"2017-05-01 12:30:00"
I already have a solution using string manipulation, but I don't think that is the ideal solution. If it must be done by string, how do you do it?

If I understand you correctly you want only the date and time portion ignoring always the time zone information.
In this case strip the time zone from the date string with regular expression
let dateString = "2017-05-01T12:30:00-0700"
let dateStringIgnoringTimeZone = dateString.replacingOccurrences(of: "[+-]\\d{4}", with: "", options: .regularExpression)
print(dateStringIgnoringTimeZone) // "2017-05-01T12:30:00"
let dateFormatter = DateFormatter()
dateFormatter.calendar = Calendar(identifier: .iso8601)
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
let date = dateFormatter.date(from: dateStringIgnoringTimeZone)!

I think you should keep the date as it is and then just use DateFormatter to display the time at that timezone
let time = "2017-05-01T12:30:00-0700"
let dateFormatter = DateFormatter()
dateFormatter.calendar = Calendar(identifier: .iso8601)
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssxxxxx"
if let result = dateFormatter.date(from: time) {
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
print(dateFormatter.string(from: result)) // "2017-05-01 16:30:00 (corresponding time at my location GMT-3)
// to display it at -0700 just set the formatter timaZone
dateFormatter.timeZone = TimeZone(secondsFromGMT: -3600 * 7)
print(dateFormatter.string(from: result)) // "2017-05-01 12:30:00\n"
}
To get the timezone offset from the string:
let hours = Int(time.suffix(5).prefix(3)) ?? 0
let minutes = Int(time.suffix(2)) ?? 0
let offset = hours * 3600 + minutes * 60
print(offset) // -25200

Related

Swift Convert UTC string to UTC Interval

I am getting UTC date in string format from server which is "Sep 8 2022 10:14AM"
Now I want to convert it into same time interval like this 1662632040.
Below Is my code I am not getting why I am getting different time interval
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MMM dd yyyy HH:mma"
dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
let dt = dateFormatter.date(from: "Sep 8 2022 10:14AM")!
let interval = dt.timeIntervalSince1970
interval is giving result 1662596040 but correct one is 1662632040.
I am not getting what is missing

Is there a more efficient way to combine a date and time in swift 5? [duplicate]

This question already has an answer here:
How to combine two strings (date & time) into a new date in Swift 3
(1 answer)
Closed 2 years ago.
I have function which receives 2 strings the first is a date "y-M-d" and the second a time "HH:mm". I then combine them using the following code.
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "y-M-d"
let date = dateFormatter.date(from: dateStr)!
dateFormatter.dateFormat = "HH:mm"
let time = dateFormatter.date(from: timeStr)!
let calendar = Calendar.init(identifier: .iso8601)
let components = NSDateComponents()
components.day = calendar.component(.day, from: date) //split from date above
components.month = calendar.component(.month, from: date)
components.year = calendar.component(.year, from: date)
components.hour = calendar.component(.hour, from: time) //split from time above
components.minute = calendar.component(.minute, from: time)
let newDate = calendar.date(from: components as DateComponents)
The code all works fine and is doing what I want it to. However, I was wondering if anyone can suggest a slicker way of doing it, using less lines of code?
You can join the date & time strings and parse them in one go:
let dateStr = "2020-03-12"
let timeStr = "15:35"
let df = DateFormatter()
df.dateFormat = "y-M-d HH:mm"
let date = df.date(from: dateStr + " " + timeStr)
// prints: 2020-03-12 13:35:00 +0000 (my machine is GMT+2)
Edit: As Leo Dabus said in the comments, a more appropriate format for the provided strings should be yyyy-MM-dd HH:mm (just kept the provided format from the question). The spirit of the answer was not to propose a format but to provide a way to avoid parsing date/time separately.
Simply get a combined String using date and time. Then use that String to get the Date instance from it.
func getDate(d: String, t: String) -> Date? {
let str = d + t
let formatter = DateFormatter()
formatter.dateFormat = "y-M-dHH:mm"
let date = formatter.date(from: str)
return date
}

How to convert date/time from GMT to local timezone

I'm getting a date time string from a JSON response that looks like this:
2019-07-18 13:39:05
This time is GMT. How can I convert this to locale time zone, in my case Eastern with day light savings.
func convertDateFormat(date:String) -> String {
let dateFormatterGet = DateFormatter()
dateFormatterGet.dateFormat = "yyyy-MM-dd HH:mm:ss"
let dateFormatterPrint = DateFormatter()
dateFormatterPrint.dateStyle = .long
dateFormatterPrint.timeStyle = .short
let date = dateFormatterGet.date(from: date)
return dateFormatterPrint.string(from: date!)
}
In the code above the result should be July 18, 2019 at 9:39 AM
Thanks
The input is a fixed-format date string in GMT, therefore dateFormatterGet must have
the locale set to "en_US_POSIX" (otherwise it can default to the user's locale settings, compare What is the best way to deal with the NSDateFormatter locale "feechur"?), and
the time zone set to GMT (otherwise it defaults to the user's time zone):
Example:
let dateFormatterGet = DateFormatter()
dateFormatterGet.locale = Locale(identifier: "en_US_POSIX")
dateFormatterGet.timeZone = TimeZone(secondsFromGMT: 0)
dateFormatterGet.dateFormat = "yyyy-MM-dd HH:mm:ss"
Everything else should be OK: you don't set a time zone for dateFormatterPrint so that the user's time zone is used.

NSDate startOfDay is 4AM?

I'm trying to write a loop for every 10 minutes of a given 24 hour day, starting at midnight and ending at ten minutes before midnight. So I tried this...
let x = Calendar.current.component(.year, from: Date())
let dateFormatter = DateFormatter()
dateFormatter.dateFormat="dd-MM-yyyy"
let june = dateFormatter.date(from: "21-06-" + String(x))
The result for june is "2017-06-21 04:00:00 UTC". Now technically this is correct, my local day will be 4 AM UTZ, but the code I'm passing this into, from the Astronomical Almanac, already handles local/global conversion.
So then I tried this:
var UTZCal = Calendar.current
UTZCal.timeZone = TimeZone(abbreviation: "GMT")!
let x = UTZCal.component(.year, from: Date())
let dateFormatter = DateFormatter()
dateFormatter.dateFormat="dd-MM-yyyy"
dateFormatter.calendar = UTZCal
let june = dateFormatter.date(from: "21-06-" + String(x))
This produced the exact same result. What am I missing?
It seems that the date formatter does not use the timezone of the
assigned calendar, and adding
dateFormatter.timeZone = UTZCal.timeZone
to your code makes it produce the expected result. But note that you
can simplify the calculation to
var utzCal = Calendar(identifier: .gregorian)
utzCal.timeZone = TimeZone(secondsFromGMT: 0)!
let year = utzCal.component(.year, from: Date())
let june = DateComponents(calendar: utzCal, year: year, month: 6, day: 21).date!
print(june) // 2017-06-21 00:00:00 +0000

Extracting the offset value from a ISO-8601 string in Swift

With NSDateFormatter, if I pass in an ISO-8601 date+time value with an offset, it will read the offset and adjust the output to a UTC value, like so:
// Setup
let formatter = NSDateFormatter()
formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
// Test
let input = "2016-04-16 04:12:00-0800"
let output = formatter.dateFromString( input )
let outputStr = formatter.stringFromDate( output )
print( outputStr ) // "2016-04-15 08:12:00-0000"
So far, so good.
But I want to get at that offset value myself. My application is a client for a webservice which preserves date-time offset information, so I must do the same (as if I blindly return outputStr to the webservice, it will have lost the offset information so the database won't know what the offset was when the datetime was collected.
NSDateFormatter only seems to accept timezone information for outputting dates, there's no way for me to get the numeric offset out of an input string.
'self explanatory' example
import Foundation
let formatter = NSDateFormatter()
formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
formatter.dateFormat = "yyyy-MM-dd HH:mm:ssZ"
// Test
let input = "2016-04-16 04:12:00-0800"
let output = formatter.dateFromString( input )
// with curent time zone (system default
let outputStrL = formatter.stringFromDate( output! )
// with time zone Z+0000
formatter.timeZone = NSTimeZone(forSecondsFromGMT: 0)
let outputStr = formatter.stringFromDate( output! )
// with time zone Z-0800
formatter.timeZone = NSTimeZone(forSecondsFromGMT: -8 * 3600)
let outputStr1 = formatter.stringFromDate( output! )
print("My local time:", outputStrL)
print("GMT+0000 time:", outputStr)
print("GMT-0800 tume:", outputStr1)
/*
My local time: 2016-04-16 14:12:00+0200
GMT+0000 time: 2016-04-16 12:12:00+0000
GMT-0800 tume: 2016-04-16 04:12:00-0800
*/
if you replace the input string with any of output strings (outputStr, outputStrL, outputStr1), NSDate created from it represents the same value (time)