How to split date from string in Swift? - swift

How can I split only "2017-09-10" from strings like"\u200c2017-09-10".
days = "\u200c2017-09-10"
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
date = formatter.date(from: days)
date return nil when it is not split.

Try this:
days = "\u200c2017-09-10"
let last10 = String(days.characters.suffix(10))
Output: 2017-09-10
Basically you are just taking the last 10 characters of the string days.

You used string seprated function like this:-
func SplitDatefromString() -> String {
let getString = self.components(separatedBy: "-")
guard getString.count != 0 else {
return "0"
}
return getString[0]
}

Related

Date not coming correctly after formate in swift

I have separated date and time according to my code, then I have used DateFormatter but date not coming correctly.. why?
coming like this: Optional("08/15/0020")
var formateFromdate: String?
var formateTodate: String?
func addDate(){
var fromDateArr = fromDateLabel.text!.components(separatedBy: ",")
fromDate = fromDateArr[0]
fromTime = fromDateArr[1].replacingOccurrences(of: " ", with: "")
var toDateArr = toDateLabel.text!.components(separatedBy: ",")
toDate = toDateArr[0]
toTime = toDateArr[1].replacingOccurrences(of: " ", with: "")
let inputFormatter = DateFormatter()
inputFormatter.dateFormat = "MM/dd/yyyy"
let showDateFrom = inputFormatter.date(from: fromDate)
inputFormatter.dateFormat = "MM/dd/yyyy"
formateFromdate = inputFormatter.string(from: showDateFrom!)
print(formateFromdate)
}
note: here fromDate = 08/15/2020 coming correct but after formate date not coming correct
OutPut:
Optional("08/15/0020") it should be 08/15/2020
From the formatted date output, it seems the value of fromDate = fromDateArr[0] is "08/15/20" If that's the case, you will have to use a date format as below;
let inputFormatter = DateFormatter()
inputFormatter.dateFormat = "MM/dd/yy"
let showDateFrom = inputFormatter.date(from: fromDate)
inputFormatter.dateFormat = "MM/dd/yyyy"
let formateFromdate = inputFormatter.string(from: showDateFrom!)
print(formateFromdate)
You need to unwrap it first
if let formate = inputFormatter.string(from: showDateFrom!){
print(formate)
}

Create TimeZone object from timeZoneOffset string?

What would be a clean way to initialise a Swift TimeZone object from timeZoneOffset string of the form: "+HH:MM".
I am looking for something of the form:
extension TimeZone {
init?(UTCOffsetString ofs: String) {
let signIndex = ofs.firstIndex(of: "+") ?? ofs.firstIndex(of: "-")
let sign = ofs[signIndex!]
let separatorIndex = ofs.firstIndex(of: ":")!
let hhRange = ofs.index(signIndex!, offsetBy: 1)..<separatorIndex
let hh = ofs[hhRange]
let mmRange = ofs.index(separatorIndex, offsetBy: 1)..<ofs.index(separatorIndex, offsetBy: 3)
let mm = ofs[mmRange]
var offsetInMin = (Int(String(hh))! * 60) + Int(String(mm))!
if sign == "-" {
offsetInMin.negate()
}
let offsetInSec = offsetInMin * 60
// Convert string to TimeZone, eg.
self.init(secondsFromGMT: offsetInSec)
}
}
let tz = TimeZone.init(UTCOffsetString: "-07:30")
print(tz?.identifier ?? "unknown")
The above code block is a correct solution and prints:
GMT-0730
However I am looking for a cleaner solution where I don't need to extract substrings in order to compute the offset.
My suggestion is to use DateFormatter which is able to parse the time zone string format. refZoneString is the reference to UTC in the current time zone.
extension TimeZone {
init?(UTCOffsetString ofs: String) {
let refZoneString = "+0000"
let formatter = DateFormatter()
formatter.dateFormat = "Z"
guard let refDate = formatter.date(from: refZoneString),
let date = formatter.date(from: ofs) else { return nil }
self.init(secondsFromGMT: Calendar.current.dateComponents([.second], from: date, to: refDate).second!)
}
}
let tz = TimeZone.init(UTCOffsetString: "-07:30")
print(tz?.identifier ?? "unknown")
I don't know what you mean by a cleaner but you can combine collection methods suffix and prefix to avoid the need to use String index to access the desired values:
let time = "-02:00"
let hours = Int(time.suffix(5).prefix(2)) ?? 0
let minutes = Int(time.suffix(2)) ?? 0
var offset = hours * 3600 + minutes * 60
if time.first == "-" { offset = -offset }
print(offset) // -7200

NSNumberFormatter.number for currency format not working in Device but works in simulator

I've been trying to implement currency format based on passing my custom language identifier.
Below is my code
func currencyFormatter(language:String, amount:String) -> String {
let nsFormatter = NumberFormatter()
nsFormatter.numberStyle = .currency
nsFormatter.currencySymbol = ""
var formattedString: String?
var amountInNumber:NSNumber!
if let number = nsFormatter.number(from: amount)
{
amountInNumber = number.doubleValue as NSNumber
}
nsFormatter.locale = Locale(identifier: language)
formattedString = ((amountInNumber?.intValue) != nil) ? nsFormatter.string(from: amountInNumber) : amount
guard let finalString = formattedString else {
return ""
}
return finalString
}
I am trying to pass language as "fr-FR" and amount as "1234.45" then expecting output is "1 234,45".
This is working fine in simulator but not working in device (returning same value 1234.45)
Do i missed anything. Please help!
Thanks in advance
The decimal separator is locale-dependent, therefore parsing "1234.45"
fails if the locale's separator is not a period.
It the input string uses a fixed format with a period as decimal separator
then you can set the formatter's locale to "en_US_POSIX" for the conversion
from a string to a number. Then set it to the desired locale for the conversion
from number to a string.
Example:
func currencyFormatter(language: String, amount: String) -> String {
let nsFormatter = NumberFormatter()
nsFormatter.locale = Locale(identifier: "en_US_POSIX")
nsFormatter.numberStyle = .decimal
guard let number = nsFormatter.number(from: amount) else {
return amount
}
nsFormatter.locale = Locale(identifier: language)
nsFormatter.numberStyle = .currency
return nsFormatter.string(from: number) ?? amount
}
print(currencyFormatter(language: "fr-FR", amount: "1234.45"))
// 1 234,45 €

Date string conversion doesn't return decimal miliseconds Swift

I need to check if a date string is of this exact format 2017-01-01 00:00:00.000 with 3 decimal milliseconds, otherwise return.
I'm using yyyy-MM-dd hh:mm:ss.SSS but this doesn't return any decimal milliseconds. Why is that? When I convert Date() to string with DateFormatter, then it returns correct ss.SSS.
let str = "2017-01-01 00:00:00.000"
let df = DateFormatter()
df.dateFormat = "yyyy-MM-dd HH:mm:ss.SSS"
df.timeZone = NSTimeZone(abbreviation: "GMT") as TimeZone!
if let date = df.date(from: str) {
print("date: \(date)")
} else {
print("no")
}
output: date: 2017-01-01 00:00:00 +0000
More, there is no error if I add ss.S/ss.SS all return true. why?
The date formatter patterns says that 1...n digits for the milliseconds is valid. You can write as many capital S as you want - it makes no difference. You have to check for the second condition separately:
extension String {
var endsWithThreeDecimalDigits: Bool {
return self.range(of: "\\.\\d{3}$", options: .regularExpression) != nil
}
}
let df = DateFormatter()
df.dateFormat = "yyyy-MM-dd HH:mm:ss.SSS"
df.timeZone = TimeZone(abbreviation: "GMT")
if let date = df.date(from: str), str.endsWithThreeDecimalDigits {
print("date: \(date)")
} else {
print("no")
}

How to extract TimeZone from Date object?

I have an ISO-8601 date string like this: "2017-02-07T00:00:00-08:00".
How can I extract the TimeZone object from this date?
Unfortunately, DateFormatter is no help since you don't want a Date nor does it provide any information about any timezone info about a parsed date string. And TimeZone doesn't have any initializer that can parse a timezone offset string.
So you will have to do the work yourself. Since you have a fixed format date string, you know the timezone offset is always going to be the last 6 characters of the string. The last 2 of those are the number of minutes and the first 3 of those are the number of hours (including the sign).
Extract these two substrings (hours and minutes) from the date string. Convert them both to Int. Then do some simple math to calculate an offset in seconds (hours * 3600 + minutes * 60).
Once you have that offset in seconds, you can create a TimeZone instance using the init(secondsFromGMT:) initializer.
Using rmaddys proposed solution, I wrote an extension for TimeZone which should do the job.
extension TimeZone {
init?(iso8601String: String) {
let timeZoneString = String(iso8601String.suffix(6))
let sign = String(timeZoneString.prefix(1))
guard sign == "+" || sign == "-" else {
return nil
}
let fullTimeString = timeZoneString.filter("0123456789".contains)
guard fullTimeString.count == 4 else {
return nil
}
guard let hours = Int(sign+fullTimeString.prefix(2)), let minutes = Int(sign+fullTimeString.suffix(2)) else {
return nil
}
let secondsFromGMT = hours * 3600 + minutes * 60
self.init(secondsFromGMT: secondsFromGMT)
}
}
You could create a date formatter that only returns the time zone such as below. Change the abbreviation to whichever time zone you are looking for.
let timeZoneOnlyDateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.timeZone = TimeZone(abbreviation: "UTC")
formatter.dateStyle = .none
formatter.timeStyle = .none
return formatter
}()
And use these functions to convert it to a string or convert your string to a date.
func formatDateIntoString(date: Date, dateFormatter: DateFormatter) -> String {
return dateFormatter.string(from: date)
}
func formatStringIntoDate(string: String, dateFormatter: DateFormatter) -> Date! {
return dateFormatter.date(from: string)
}