How does function `DateFormatter.dateFormat(fromTemplate:)` work? - ios

With some digging, and help from a thread on SO, I was able to figure out that if you set up a DateFormatter with code like this:
let locale = NSLocale.current
let format : String = DateFormatter.dateFormat(fromTemplate: "j:mm.ss.SSS", options:0, locale:locale)!
print("format = \(format)")
let formatter = DateFormatter()
formatter.dateFormat = format
You get a date formatter with a date string that adapts to the user's 12/24 hour clock setting.
If you run that code in the US with the device set to 12 hour time, you see the following on the console:
format = h:mm:ss.SSS a
If you set your device to 24 hour time, you instead see
format = HH:mm:ss.SSS
That makes sense.
However, once you assign the resulting format string to your date formatter, it should be fixed. I would expect the date formatter to generate 12 or 24 hour times until I explicitly change it's format string.
That is not what happens. If I switch to settings and change the clock settings from 12 to 24 hours, the date formatter magically starts producing 24 hour time strings. I can log the date formatter's format string, and it sill shows the 12 hour string "h:mm:ss.SSS a". What's going on?

Related

How to know Date format getting from sever [duplicate]

This question already has answers here:
How can I parse / create a date time stamp formatted with fractional seconds UTC timezone (ISO 8601, RFC 3339) in Swift?
(13 answers)
Closed 1 year ago.
I am trying to get date format of a date that I am getting from server.
What will be the format of this date:
2021-10-14T17:53:03.753588+05:30
What I tried:
yyyy-MM-dd'T'HH:mm:ssXXX
But Its not working.
How to (my tips & steps):
When you are struggling to find the date format for String -> Date ask you this: What my format is really doing? What's it's parsing/interpreting? Just let's see with Date -> String...
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssXXX"
print(formatter.string(from: Date()))
Output: 2021-10-14T13:06:38+02:00: Is it the "same" as the string we have? No, some are the same, but not all...
Let's continue with another tip:
Let's put our format and the string one above the other one:
2021-10-14T17:53:03.753588+05:30
yyyy-MM-dd'T'HH:mm:ssXXX
Then, let's add "spaces", to make each pattern match its corresponding input:
2021-10-14 T 17:53:03.753588 +05:30
yyyy-MM-dd 'T' HH:mm:ss XXX
Then, let's check the doc (it's bookmarked in my web browser) for interpretation of the pattern and check if they correspond if needed, and to find the missing one if needed too.
Ok, so we aren't interpreting .753588 at all, that's why it's failing...
It's for the fractional seconds, so if we change the format to: "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", it should work. Note, you can replace XXX with Z if you want...
Now, remember that patterns are case sensitive, so if you have strange hours, minutes, or nil because of that, check if you didn't misuse minutes vs month, 12h format vs 24 hour format...
If you have hours diff (or usually 30min diff), the issue could be then a timezone issue.
If you have a day diff, it could also be a timezone issue (interpret it as hours diffs around midnight, so there is a day change).
If you have a year diff, check if you didn't misuse yyyy vs YYYY.
Etc. But that should cover most of your cases (basic issues).
Try this format.
"yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXX"
As the date format you mentioned in your question contains milliseconds as well as timezone offset info.
Once date is parsed then based on your need you can set output date format and will get formatted date.
let sampleDate = "2021-10-14T17:53:03.753588+05:30"
let dateFormatter = DateFormatter() dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXX" // Set input date format.
let inputDate = dateFormatter.date(from: sampleDate)
print("Input Date:- \(inputDate)")
dateFormatter.dateFormat = "yyyy-MM-dd hh:mm:ss" // Set output date format as per need
let outputDate = dateFormatter.string(from: inputDate ?? Date())
print("Output Date:- \(outputDate)")

Swift 4 wrong date and time

I am struggle with timezone because I tried to set time to midnight to 23:00:00, however, the result show start with 6am until 5am next day. I tried to set timezone to current, still same result. Here my code
let day1num = Int(todaynumber.string(from: Date()))! + 1
let day1start = Calendar.current.date(bySetting: .day, value: day1num, of: Date())
let day1end = Calendar.current.date(bySetting: .hour, value: 23, of: day1start!)
print("\(day1start!) to \(day1end!)")
I got result
2020-04-22 06:00:00 +0000 to 2020-04-23 05:00:00 +0000
I don't want 6am to 5am next day, I want result:
2020-04-22 00:00:00 +0000 to 2020-04-22 23:00:00 +0000
How can I solve it?
Thanks!
Your issue is you're misunderstanding Date and how it prints to the console.
Dates are representative of moments in time. Think of them as an Integer that represents the amount of time that has passed since a reference date. It's NOT a human-readable string. To convert a date to a human-readable string, you need to use a DateFormatter and make sure to set the timeZone of the date formatter to be the time zone in which you want the string to be representative of (it will default to the system's current time zone). The timeZone will impact what the resulting string is. For example, if you have a date formatter where the time zone is Pacific time, it might return a value like April 22, 2020 6:00 PM, but then if you change the time zone to mountain time and get the string from the date, it will return April 22, 2020 7:00 PM.
When you print a Date instance to the console, the system formats it to be a human-readable string in the UTC time zone. If I'm doing my math correctly, you're in mountain time, which is why the value you're seeing logged is 6 hours ahead of the value you're expecting.
If you want to see the date logged to the console as the user will see it, you should use a DateFormatter instance. It will default to use the user's system time zone, then use the Date value you've calculated to get the String representation of that date, and then log that String to the console, rather than the date itself.
let formatter = DateFormatter()
formatter.dateStyle = .medium // Customize as needed
formatter.timeStyle = .medium // Customize as needed
// formatter.timeZone = ... something else if you don't want to use the system time zone
let day1StartAsString = formatter.string(from: day1start!)
let day1EndAsString = formatter.string(from: day1end!)
print("\(day1StartAsString) to \(day1EndAsString)")

Format date with 7 fractional seconds

I have the need of parsing a date that looks like this:
"2018-03-08T17:37:09.2694781-00:00"
Notice the fractional seconds, I need to keep all 7 digits because then I need to send back to my server exactly the same date.
So, I need to be able to convert that string to Date, do some stuff and then send it back to another server thus converting that Date back to String again and keeping the same format and fractional seconds, keeping the original date as String is not an option here.
I already tried this but it does not work because the original Date/Time gets modified for some unknown reason
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.Axxx"
let dateObj = formatter.date(from:("2018-03-08T17:37:09.2694781-00:00"))
//This produces: "2018-03-08 00:44:54 UTC", nothing to do with the original date, it would be fine if converted to UTC, though
I also tried a formatter like
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSSZZZZZ"
But that truncates my fractional seconds to 3 digits.

Issue with 24hour date format

I am trying to convert Date object in string using DateFormatter but I am getting some weird behavior. I have a timestamp value (1513356296) which I want to convert in 24hour format along with date and timeZone (My current is -0800). Here is my code:
let date = Date(timeIntervalSince1970: Double(1513356296))
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
dateFormatter.timeZone = TimeZone(secondsFromGMT: -(8*3600))
dateFormatter.locale = Locale.current
I am expecting a result value of 2017-12-15T08:44:56-0800 but I am getting 2017-12-15T8:44:56-0800. Everything is same except the hour value. The hour value is 8 instead of 08.
This is not happing with all the test, it happened in only one device and rest are fine.
I also tried by checking if hour value changes if I change device time setting to 12hour format from 24hour format to see what I get for HH and it was always giving me 08 in my case. Only one user was facing this issue.
What's wrong with my code? or is there something wrong with HH I am using?

iOS How to show 12 hour time format if user set 24 hour time in system without changing locale to specific identifier

My question is how to show 12 hour time format in app, if user's system setting is 24 hour time. I don't want to change dateFromatter.locale to a specific one.
My research is:
If system setting using 12 Hour, format "HH" will show 24H and "hh" will show 12H.
However, if system setting using 24H, both format "HH" and "hh" will show 24H, and "a" is ignored.
Seems like 24H system setting is overriding format string in app.
I've known NSLocale(localeIdentifier: "en_US_POSIX") will show 12H and NSLocale(localeIdentifier: "en_GB") will show 24H. However, changing locale of NSDateFormatter will result in fixed time string in other language such as Chinese and Japanese

Resources