Invalid date after conversion 12h -> 24h - ios

I want to convert AM/PM time to 24h. That should be totally trivial... however I'm standing against a weird issue:
let inputDateString = "11:05:45PM"
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "HH:mm:ssa"
let inputDate = dateFormatter.dateFromString(inputDateString) // "Jan 1, 2000, 12:05 PM" ???
if let inputDate = inputDate {
dateFormatter.dateFormat = "HH:mm:ss"
print(dateFormatter.stringFromDate(inputDate))
}
I thought that maybe it's converting the time using some weird timezone. So I've tried to add systemLocale or GB locale, that didn't help.
Then I've came up with the idea, that maybe it can't set date previous to 01.01.2000 12:00:00 (what is without sense, because it should work at least from year ~1970). So I've added the day, month etc to move it to 2005 year, but the issue still persists.
You can easily paste this to the Playground with import Foundation to test it out.
Why am I getting wrong hour?
-- Edit --
If you change inputDateString to any other hour like "01:05:45PM", the inputDate would be the same :/ But if you change minutes or seconds, it gets updated accordingly.

You need to change the dateFormat to "hh:mm:ssa", as the lowercase h signalizes that the input time is in 12-hour format.
DateFormatter uses the Unicode standard for formatting, so it uses the values found in the Unicode Documentation (Valid for macOS 10.9 and iOS 7 and newer, as of 08/2016).
An easier-to-use reference can be found on http://nsdateformatter.com.

let inputDateString = "11:05:45PM"
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "HH:mm:ssa" // Here, change the format string to "hh:mm:ssa"
let inputDate = dateFormatter.dateFromString(inputDateString) // "Jan 1, 2000, 12:05 PM" ???
if let inputDate = inputDate {
dateFormatter.dateFormat = "HH:mm:ss"
print(dateFormatter.stringFromDate(inputDate))
}

Related

Formatting a date from a string in swift [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 3 years ago.
i have the following date coming from a server 2019-09-05T10:37:49.494Z as a string and i need to parse this and convert it to a format like this Fri September 13,2019 12:36 AM and back to a string again:
i found multiple question links but none of them are working for me Question One
Question Two
it tried doing this:
let dateFormatterGet = DateFormatter()
let dateFormatterPrint = DateFormatter()
var rawDate = "2019-09-05T10:37:49.494Z"
dateFormatterGet.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
dateFormatterPrint.dateFormat = "E, d MMM yyyy HH:mm"
var formattedDate = "Error Formatting date"
if let date = dateFormatterGet.date(from: rawDate) {
formattedDate = dateFormatterPrint.string(from: date)
print("Formatted Date : \(formattedDate)")
}else {
print("There was an error decoding the string")
}
this fails printing the error message, what am i doing wrong and how can i fix it?
You are almost there.
A small tip playing with (NS)DateFormatter put the dateFormat above/under the date string.
yyyy-MM-dd'T'HH:mm:ssZ
2019-09-05T10:37:49.494Z
Then, add "spaces" to align and separate them.
yyyy - MM - dd 'T' HH : mm : ss Z
2019 - 09 - 05 T 10 : 37 : 49 . 494Z
^ ^^^
I highlighted the missing ones. You need to tell the (NS)DateFormatter through the dateFormat how to interpret theses additional characters.
Let's check the documentation.
It's
Fractional Second - truncates (like other time fields) to the count of letters. (example shows display using pattern SSSS for seconds value 12.34567)
So using yyyy-MM-dd'T'HH:mm:ss.SSSZ should interpret them and fix your issue.
That's how you fix your issue. And it explained your error.
But since as pointed by #Zombie it's using a ISO format, use if available the ISO8601DateFormatter if possible (iOS10+)
If in future cases you don't have an ISO something format, you can use theses tips ;)
The format you provided seems like an iso 8601 date for this reason I would suggest using the ISO8601DateFormatter
You can specify the options to match your string
here is an example
let dateString = "2019-09-05T10:37:49.494Z"
let formatter = ISO8601DateFormatter()
formatter.formatOptions = [
.withDashSeparatorInDate,
.withFullDate,
.withFullTime,
.withFractionalSeconds,
.withColonSeparatorInTime
]
// "Sep 5, 2019 at 12:37 PM"
let date = formatter.date(from: dateString) ?? Date()
//"Thursday, September 5, 2019 at 12:37:49 PM"
let formattedDate = DateFormatter.localizedString(
from: date,
dateStyle: .full,
timeStyle: .medium
)
The problem is you don't tell dateFormatterGet how to parse milliseconds. Modify the dateFormat to:
dateFormatterGet.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"

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
}

Converting time from GMT in iOS behaving oddly (Reverse)

So I am trying to convert some times I receive in UTC/GMT to the local time zone using the following code:
let gmtFormatter: NSDateFormatter = NSDateFormatter()
gmtFormatter.timeZone = NSTimeZone(name: "GMT")
gmtFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let gmtDate: NSDate = gmtFormatter.dateFromString(dateString)!
print("GMT \(gmtDate)")
let localFormatter: NSDateFormatter = NSDateFormatter()
localFormatter.timeZone = NSTimeZone.localTimeZone()
localFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let localDate: NSDate = localFormatter.dateFromString(gmtFormatter.stringFromDate(gmtDate))!
print("Local \(localDate)")
However, I find that the conversion is working in revers. PST is UTC-8 and the outputs are 8 hours ahead instead of 8 hours behind. So I tested with a London Time Zone (CET) which is UTC+1 and should be 1 hour ahead of GMT. The results was a time that was 1 hour behind.
This was the string I am testing with: "2016-02-24 00:05:54"
For PST this should convert to 2016-02-23 04:05:54, but instead converts to 2016-02-24 08:05:54 (notice the way it should be is on the 23rd and not the 24th)
For CET this should convert to 2016-02-24 01:05:54, but instead converts to 2016-02-23 23:05:54 (notice the way it should be is on the 24th and not the 23rd)
Am I missing something glaring?
The problem is that in the second part of your code...
let localDate: NSDate =
localFormatter.dateFromString(gmtFormatter.stringFromDate(gmtDate))!
... you're doing the opposite of what you want. An NSDate is absolute. Its string representation is what is volatile, as it were. So having turned a string into a date with your first formatter, what you now want to do is turn that date into a string with your second formatter.
For example, I'm in California. Now, watch this:
let dateString = "2016-02-24 10:09:08"
let gmtFormatter: NSDateFormatter = NSDateFormatter()
gmtFormatter.timeZone = NSTimeZone(name: "GMT")
gmtFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let gmtDate: NSDate = gmtFormatter.dateFromString(dateString)!
print("GMT \(gmtDate)")
let localFormatter: NSDateFormatter = NSDateFormatter()
localFormatter.timeZone = NSTimeZone.localTimeZone()
localFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let localDateString = localFormatter.stringFromDate(gmtDate) // <-- !!!
print("Local \(localDateString)")
Result:
GMT 2016-02-24 10:09:08 +0000
Local 2016-02-24 02:09:08
That's correct. When it's 10 AM in London, it's 2 AM here.
To put it another way, if you think what you're doing is converting a date from one time zone to another, you have not understood what a date is. It is a date-time and a time zone. There is nothing to convert: it is completely determined, and it is correct no matter where you are, because it says what time zone it is.
Perhaps it would be a bit clearer to you if I changed the next-to-last line format to this:
localFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
The final output is then:
Local 2016-02-24 02:09:08 -0800
which is obviously correct.

NSDateFormatter parses two-digit year as 2046 instead of 1946 or 2040 instead of 1940

I have a scenario where I'm getting a date string as "46-05-24" (yy-mm-dd), and I need to re-format the date as "1946-05-24". The NSDateFormatter interprets the string as "2046-05-24".
I'm using this code:
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yy-mm-dd"
let gmt : NSTimeZone = NSTimeZone(abbreviation: "GMT")!
dateFormatter.timeZone = gmt
let dateFromString = dateFormatter.dateFromString(date as String)
dateFormatter.dateFormat = "yyyy-mm-dd"
if dateFromString != nil{
let dateString = dateFormatter.stringFromDate(dateFromString!)
print(dateString)
}
Is there something I'm missing here?
It happens because if you're giving NSDateFormatter a two-digit year, it needs to decide what century that year is in. It does this using its twoDigitStartDate property, which sets the earliest date that a two-digit year can represent. It has a default value of December 31, 1949. A date in 46 falls on the low side of 50 so it gets treated as 2046.
You can change the value of twoDigitStartDate to adjust the results. For example, you could set it to a date exactly 100 years in the past. That would mean that any two-digit year would be interpreted as the most recent year with those two digits:
let oneCenturyAgo = NSCalendar.currentCalendar().dateByAddingUnit(NSCalendarUnit.Year, value: -100, toDate: NSDate(), options: NSCalendarOptions(rawValue:0))
dateFormatter.twoDigitStartDate = oneCenturyAgo
Of course if you get someone whose date is over 100 years ago, there's no good way for your code to know which year is appropriate. If the year is "10", was that person born in 1910 or 2010? You have no way of knowing, and all your code can do is make the best guess.
The cause of your problem is that your data omits some relevant information: the century. Using only the last two digits you as the dev have to decide which century the dates are in. If all of them are in the 20th century (1900 - 1999) you can use the following approach:
You could simply prepend 19 before the string to parse. Assuming date is the string that you want to parse you can use
let dateFromString = dateFormatter.dateFromString("19" + (date as String))
instead of your
let dateFromString = dateFormatter.dateFromString(date as String)
If the dates you are going to handle are in the 20th and the 21st century you are going to have a bad time because what year is 05 supposed to reflect? 1905? 2005? 2105?

NSDateFormatter always returning nil

This is my code:
var sdArr = sd.componentsSeparatedByString(".")
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'hh:mm:ss"
let date = dateFormatter.dateFromString(sdArr[0])
The value of sdArr[0] is "2015-10-01T14:30:00"
Why is the value of date is nil? This was working fine 2 days ago and I didn't touch my code. Now suddenly out of the blue value of date is nil.
I've tried putting the date string in place of sdArr[0] but it still not working
Please use date formatter as
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
You are using hh which is for 12 hour format, HH is for 24 hour format
add dateformat yyyy-MM-dd'T'hh:mm:ss to yyyy-MM-dd'T'HH:mm:ss because you are getting hour in 24 hour format not 12 hour format so you have to use HH
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss" //HH
Please refer Formatting date and time with iPhone SDK? (Vanya's answer) to know more regarding date formaters.
Use this NSDateFormatter
var dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"

Resources