FSCalendar select day selects previous day at 23:00 - ios

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.

Related

Dateformatter Result

Here is my DateFormatter Code
let formatter = DateFormatter()
formatter.dateFormat = "MMM dd"
let dateString = formatter.string(from: date)
Now:
po dateString
gives the result "May 18"
po date gives the result 2021-05-17 18:30:00 +0000
This does not make sense to me - why is the Date May 17 2021 being converted to the String May 18?
A Date object records an instant in time anywhere on the planet.
That instant in time will be on a different calendar day (day/month/year) depending on what time zone you are in.
By default, date formatters work in the device's current time zone.
When you log a Date using po date or print(date) the default description of a Date displays that date in UTC using the ISO 8601 date format. Depending on the user's time zone, the Date in UTC might be on a different calendar day than it is in the local time zone
If you want to log a date in the user's local time zone, use po date.description(with: Locale.current) or po DateFormatter.localizedString(from: date, dateStyle: .medium, timeStyle: .medium)
This depends on the current time zone of the formatter used , for 0 based use
formatter.timeZone = TimeZone(abbreviation: "UTC")

Swift date formatter ignoring months

I wrote a date reformatter but it appears Swift's date formatter itself is ignoring the months. The documentation says this shouldn't be happening. How do I make it not ignore months?
let testDate:String = "2020-11-22-11:00"
print("start date: ",testDate," reformatted date: ", reformatDate(dateString: testDate))
func reformatDate(dateString: String) -> String? {
print("dateString: ",dateString)
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-DD-HH:mm"
dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
return dateFormatter.string(from: dateString)
}
this prints:
start date: 2020-11-22-11:00 converted date: 22-01-2020 11:00 AM
It unreasonably turns all months to 1!
Your format string is incorrect. It should be:
yyyy-MM-dd-HH:mm
and
dd-MM-yyyy h:mm a
dd means day-of-month, whereas DD means day-of-year.
Note that you should also do:
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
whenever you are using a custom date format.
Parsing 2020-11-22-11:00 with yyyy-MM-DD-HH:mm means that you want the twenty second day of the year 2020, in the month November. That makes no sense, and DateFormatter ends up ignoring the month because apparently day-of-year is a "stronger" date component. The 22nd day of any year is the 22nd of January.
Then, when you format the parsed date with DD-MM-yyyy h:mm a, the month component gets displayed as 01, and the day-of-year is still displayed as 22.
Here are some useful links to learn about format specifiers, you'll just how much lowercase/uppercase matters.
NSDateFormatter.com
TR-35

how to make 24 hours time format from string in Swift

I want to convert a string that was generated by the user to a Date data type. I want the time to be in 24-hour format
let dateFormatter = DateFormatter()
let timeAsString : String = "22:30"
dateFormatter.dateFormat = "HH:mm"
let timeFromString = dateFormatter.date(from: timeAsString)
result : "Jan 1, 2000 at 10:30 PM"
but the result is in 12-hour format. How can I get 22:30 as a Date data type?
Date has no format, so only can change the string converted from the date
Swift 4
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "HH:mm"
let newDateString = dateFormatter.string(from: yourDate)
for different date format, you can check nsdateformatter.com
You code is absolutely correct, there no problem in your code. String HH in date format represent 24 hours time display format.
But developer (application) has no control over time format. You can set date format string supporting 24 hours time but if user has (not enabled) turned of 24 hours support from device then it will display time for 12 hours format.
Check your simulator/mac system/iPhone device time format and set it for 24 hours display.
Refer this apple document for 24 hours time support: Date Formatters
The representation of the time may be 13:00. In iOS, however, if the user has switched 24-Hour Time to Off, the time may be 1:00 pm.
func convertToString(of dateTo: Date) -> String {
let dateFormatter = CustomDateFormatter()
//Your New Date format as per requirement change it own
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let newDate: String = dateFormatter.string(from: dateTo) //pass Date here
// print(newDate) //New formatted Date string
return newDate
}

1st april dates of 80s failed to parse in iOS 10.0

I found that DateFormatter date(from:) method can't parse a couple of specific dates. Method returns nil for the 1st april of 1981-1984 years. Is it a bug of Foundation? What can we do to perform parsing of such dates?
Xcode 8.0, iOS SDK 10.0. Here is a screenshot of a short playground example:
This problem occurs if daylight saving time starts exactly on
midnight, as it was the case in Moscow in the years 1981–1984 (see for example Clock Changes in Moscow, Russia (Moskva)).
This was also observed in
Why does NSDateFormatter return nil date for these 4 time zones? and
Why NSDateFormatter is returning null for a 19/10/2014 in a Brazilian time zone?
For example, at midnight of April 1st 1984, the clocks were adjusted one hour forward, which means that the date "1984-04-01 00:00"
does not exist in that timezone:
let dFmt = DateFormatter()
dFmt.dateFormat = "yyyy-MM-dd"
dFmt.timeZone = TimeZone(identifier: "Europe/Moscow")
print(dFmt.date(from: "1984-04-01")) // nil
As a solution, you can tell the date formatter to be "lenient":
dFmt.isLenient = true
and then it will return the first valid date on that day:
dFmt.isLenient = true
if let date = dFmt.date(from: "1984-04-01") {
dFmt.dateFormat = "yyyy-MM-dd HH:mm:ss"
print(dFmt.string(from: date))
}
// 1984-04-01 01:00:00
A different solution
was given by rob mayoff, which is to make the date formatter use noon instead of midnight as the
default date. Here is a translation of rob's code from Objective-C to Swift:
let noon = DateComponents(calendar: dFmt.calendar, timeZone: dFmt.timeZone,
year: 2001, month: 1, day: 1, hour: 12, minute: 0, second: 0)
dFmt.defaultDate = noon.date
if let date = dFmt.date(from: "1984-04-01") {
dFmt.dateFormat = "yyyy-MM-dd HH:mm:ss"
print(dFmt.string(from: date))
}
// 1984-04-01 12:00:00

Convert two strings to NSDate

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.

Resources