I'm getting a string representation of a date from a json that looks like the following:
let dateString = "2016-12-31T00:10:00+01:00"
In order to model it as a Date object I'm using a date formatter like so:
let dateForm = DateFormatter()
dateForm.locale = Locale(identifier: "fr_FR")
dateForm.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
dateForm.timeZone = TimeZone.current
When I turn it into a Date, my Playground output is correct:
let date = dateForm.date(from: dateString)
=> Output: "Dec 31, 2016, 12:10 AM"
But if I try to print this exact same object (date) I get the following output:
print(date!)
=> Output: "2016-12-30 23:10:00 +0000\n"
My question is: How can I be sure that I'm dealing with the correct date (by correct I mean with my local time zone (GMT+01)) ?
When you print the date output 2016-12-30 23:10:00 +0000 and your GMT is +00:00
but when you get the string from date it will return string as per your given format And your Locale (fr_FR) output 2016-12-31T00:10:00+01:00 and your GMT is +01:00
if you want to date from string then
date output = your string date - (your GMT)
In your case
2016-12-30 23:10:00 = 2016-12-31 00:10:00 - (+01:00)
Related
I'm using FSCalendar in a Swift app, and when user selects a day, I'm printing the selected day, and the it prints the previous day, at 23:00. I'm not sure why and how can I solve this. I'm in spain. Maybe it's related with where you are and your local hour?
This is how I'm printing the selected day:
extension CalendarDataViewViewController: FSCalendarDataSource {
func calendar(_ calendar: FSCalendar, didSelect date: Date, at monthPosition: FSCalendarMonthPosition) {
let df = DateFormatter()
df.dateFormat = "yyyy-MM-dd hh:mm:ss"
let now = df.string(from: date)
logger.debug("Date: \(date)")
}
}
And this is what it's printed when I select 18 march:
21:01:24.646 💚 DEBUG CalendarDataViewViewController.calendar():258 - Date: 2021-03-17 23:00:00 +0000
Your code creates a date formatter, converts the returned date to a date string with that formatter, and then ignores that and simply prints the date, which is being displayed in UTC. (Note the output Date: 2021-03-17 23:00:00 +0000)
Change your log command to read:
logger.debug("Date: \(now)")
And by the way, the variable name now is a terrible choice for holding a user-selected date that is not the current date.
I'd suggest renaming the returned date parameter selectedDate and the String output of the formatter as selectedDateString
Edit:
Consider this code:
import Foundation
func dateStringFromDate(_ inputDate: Date) -> String {
let df = DateFormatter()
df.dateFormat = "yyyy-MM-dd hh:mm:ss a"
let dateString = df.string(from: inputDate)
return dateString
}
func isoDateStringFromDate(_ inputDate: Date) -> String {
let df = ISO8601DateFormatter()
df.formatOptions = .withInternetDateTime
df.timeZone = TimeZone.current //Force the formatter to express the time in the current time zone, including offset
let dateString = df.string(from: inputDate)
return dateString
}
let now = Date()
print("Current timezone = \(TimeZone.current)")
print("now in 'raw' format = \(now)")
let localizedDateString = DateFormatter.localizedString(from: now,
dateStyle: .medium,
timeStyle: .medium)
print("localizedString for the current date = \(localizedDateString)")
print("dateStringFromDate = \(dateStringFromDate(now))")
print("isoDateStringFromDate = \(isoDateStringFromDate(now))")
Right now, at about 9:16 PM EDT on Thursday March 18th, that logs the following:
Current timezone = America/New_York (current)
now in 'raw' format = 2021-03-19 01:16:52 +0000
localizedString for the current date = Mar 18, 2021 at 9:16:52 PM
dateStringFromDate = 2021-03-18 09:16:52 PM
isoDateStringFromDate = 2021-03-18T21:16:52-04:00
The 'raw' date format is in GMT, with an offset value of 0. In that form, in GMT, the calendar date is already March 19th. (Because GMT is 4 hours ahead of EDT)
The class function NSDateFormatter.localizedString(from:dateStyle:timeStyle) displays a date in the current time zone and using the device's locale settings. The dateStyle and timeStyle parameters give you the option to choose whether or not, and in what format (short, medium, or long) to display the date or time.
An ISO8601DateFormatter displays the date following the conventions in the ISO8601 standard. The isoDateStringFromDate(:) function above uses the .withInternetDateTime option to express the date in the ISO8601 "internet date and time" format. I forced that date to be in the local time zone, so it displays the date with a -4 hour offset from GMT (since it is EDT, eastern daylight savings time where I live.)
The function dateStringFromDate(_:) is a slight variation on your function. It returns a date string in the current time zone, using 12 hour times and an AM/PM string.
I need to convert my date to string and then string to date. date is "2020-10-17 1:22:01 PM +0000"
Here is my date to string conversion code:
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssXXXXX"
let string = formatter.string(from: "2020-10-17 1:22:01 PM +0000")
let createdAT = string
its returning "2020-10-17 18:51:30+05:30"
Here is my string to date conversion code:
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.dateFormat = "yyyy-MM-dd' 'HH:mm:ssZ"
let date = dateFormatter.date(from:date)!
its returning "2020-10-17 1:21:30 PM +0000 - timeIntervalSinceReferenceDate : 624633690.0"
its returning the wrong date after i convert string to date. i need "2020-10-17 18:51:30+05:30" this time to be return when i convert string to date.....
The code in your question is muddled up. You try to convert a string into a string in the first example and something unspecified into a Date in the second example.
Here's how to convert a Date into a String:
import Foundation
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssXXXXX"
let string: String = formatter.string(from: Date())
print(string) // prints for example 2020-10-18T10:54:07+01:00
Here's how to convert a string into a date
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "yyyy-MM-dd' 'HH:mm:ssZ"
let date: Date = formatter.date(from: "2020-10-18 10:59:56+0100")! // In real life, handle the optional properly
print(date) // prints 2020-10-18 09:59:56 +0000
When you print a Date directly, it automatically uses UTC as the time zone. This is why it changed it in the code above.
In the examples, I explicitly specified the type of string and date to show what type they are. Type inference means you can omit these in normal code.
As a general rule when handling dates:
always use Date in your code. Date is a type that stores the number of seconds since Jan 1st 1970 UTC.
Only convert dates to strings when displaying them to the user or communicating with an external system.
When calculating periods etc, always use a Calendar to get things like date components and intervals in units other than seconds. You might think to get "the same time tomorrow" you could just add 24 * 60 * 60 to a Date but in many countries, like mine, that will work on only 363 days in the year. Calendar will correctly handle things like daylight saving and leap years.
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).
i am trying to calculate the time between two dates. One of the dates is today and the other date is somewhere in the future.
The issue is the date in future is separated into two string, the first containing the date and the other containing the time for that date. When i put the two strings together to a single string and try to convert it to a NSDate i get Nil.
I assume there is something wrong with my date variable.
let eventDate: String? = "21 Aug Sun 2016"
let eventTime: String? = "9:00 PM"
let date : String? = "\(eventDate!) \(eventTime!)"
print(date!) // "21 Aug Sun 2016 9:00 PM"
let formatter = NSDateFormatter()
formatter.dateFormat = "dd MMM eee yyyy HH:MM a"
formatter.AMSymbol = "AM"
formatter.PMSymbol = "PM"
if let dateTimeForEvent = formatter.dateFromString(date!) {
print(dateTimeForEvent)
}else {
print("Error")// prints error
}
Two things:
You have the wrong format for the time. It should be h:mm a. HH is for a two-digit, 24-hour hour. You have a 1 or 2 digit, 12-hour hour. And MM is for a 2-digit month. Use mm for a two-digit minute.
If your date and time strings will always be in English, you need to set the formatter's locale to an English locale. If you don't, your code will always return a nil date on any device using a language other than English.
Your primary issue is that you're using HH, which is for 24-hour time, instead of hh, and MM (which is for month) instead of mm. Try this:
import Foundation
let eventDate = "21 Aug Sun 2016"
let eventTime = "9:00 PM"
let eventDateTime = "\(eventDate) \(eventTime)"
print(eventDateTime) // "21 Aug Sun 2016 9:00 PM"
let formatter = NSDateFormatter()
formatter.dateFormat = "dd MMM eee yyyy hh:mm a"
if let date = formatter.dateFromString(eventDateTime) {
print(date) // 2016-08-21 21:00:00 +0000
}
else {
print("Error")// prints error, no shit? why is this comment here?
}
Side notes:
Why is a variable called date, if it's a String??
Why is date an optional, anyway? You assigned it a literal value.
You don't have to set the AMSymbol and the PMSymbol. Those only pertain to printing dates, not parsing them.
I am trying to convert UTC Date to local date in swift but after get UTC To Local date in string i convert that string to again in NSDate but i am always getting in UTC date format, below is my code
Date : in UTC : 2016-07-20 18:30:00 +0000
I am trying this date in local date, check below code:
let dateInUTC = NSDate()
let seconds: Int = NSTimeZone.systemTimeZone().secondsFromGMT
print(seconds)
let localDateFormatter: NSDateFormatter = NSDateFormatter()
localDateFormatter.dateFormat = "MM/dd/yyyy HH:mm"
localDateFormatter.timeZone = NSTimeZone(forSecondsFromGMT: seconds)
let lastDate: String = localDateFormatter.stringFromDate(dateInUTC)
print(lastDate)
at this time i am getting “07/12/2016 16:56:36 GMT+5:30”, means i got local date in string but i want this date in NSDate so again i convert this string date in NSDate,check below
let getDate:NSDate = localDateFormatter.dateFromString(lastDate)!
print(getDate)
but at this stage again i got date in UTC (2016-07-12 11:26:36 +0000) but i want in local date,
I tried a lot of times in Swift but not getting local date from string,this line of code i used in objective-c, its working fine in obj-c but when i am trying in swift i always get UTC date,suggest me and give me right way to sol this.
NSDates don't save time zone information. You always have to use the dateFormatter with time zone when retrieving.