Converting String to Date assigns wrong values - swift

I am trying to construct a date from a string. The date is in .islamic calendar. I am using the following code
let StringValue = "1439/01/02"
//constructing the Hijri Date
let HijriFormatter = DateFormatter ()
HijriFormatter.calendar = Calendar(identifier: .islamic)
HijriFormatter.dateFormat="yyyy/MM/dd"
HijriFormatter.timeZone = TimeZone(abbreviation: "GMT+0:00")
let hijriDate = HijriFormatter.date(from: StringValue)
print (hijriDate!)
The output should be similar to the string. However, for some reason I am getting the following output:
2017-09-22 00:00:00 +0000
Any idea of why the code is behaving this way

You can get date components from hijri date using calendar:
let calenadr = Calendar(identifier: .islamicUmmAlQura)
let unitFlags: Set<Calendar.Component> = [.day, .month, .year]
let comps = calenadr.dateComponents(unitFlags, from: hijriDate!)
print(comps.day , comps.month, comps.year)

Related

Does dateFromServer return the current Timezone of the person?

When I am running the code below the date and time returned are in correct format but just not from what's coming from the API which in this case is the currentVehicle.LastCommunicationDate!
Instead of coming the time from the currentVehicle.LastCommunicationDate! it's just returning a random timezone I think that is getting from the Server or something like that.
The output of the code I have right now is: 2022-01-21 02:04:15 when it should have been the live time in my local timezone but it's getting a different timezone.
The LastCommunicationDate coming from postman is in json format: "LastCommunicationDate": "2022-01-21T10:58:21.367",
The time i want to be is the one from Postman just converted from json to normal time like: yyyy-MM-dd HH:mm:ss
let timeinterval : TimeInterval = (currentVechicle.LastCommunicationDate! as NSString).doubleValue
let dateFromServer = NSDate(timeIntervalSinceNow:timeinterval)
let outFormatter = DateFormatter()
outFormatter.locale = Locale(identifier: "en_Al")
print(dateFromServer)
let dateFormater = outFormatter
outFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
print(dateFormater.string(from: dateFromServer as Date))
let dateFromServers = dateFormater.string(from: dateFromServer as Date)
LastCommunicationDate is a string, but you are converting it to a Double. Try this instead:
let lastCommunicationDate = "2022-01-21T10:58:21.367"
//Create dateformatter to convert string to Date
let isoDateFormatter = ISO8601DateFormatter()
isoDateFormatter.formatOptions = [
.withFullDate,
.withTime,
.withColonSeparatorInTime,
.withFractionalSeconds
]
let isoDateFormatter2 = ISO8601DateFormatter()
isoDateFormatter2.formatOptions = [
.withFullDate,
.withTime,
.withColonSeparatorInTime
]
let date = isoDateFormatter.date(from: lastCommunicationDate) ?? isoDateFormatter2.date(from: lastCommunicationDate)
//Create dateformatter to format date for output
let outFormatter = DateFormatter()
outFormatter.locale = Locale(identifier: "en_Al")
outFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let dateFromServers = outFormatter.string(from: date!)

Assigning NSDateComponents to a label

I'm creating a mobile app that has a countdown to a specific date. I think I have the timer itself correct, but I'm struggling to get it into a format where I can assign it to my label. I'm getting an error "Cannot invoke initializer for type 'String' with an argument list of type '(NSDateComponents)'. This error is found at the line "var date = String(openingGavelDate)". The outlet for the label has been properly created in this file.
First step I took was creating the date variable and setting it equal to the converted value of my other variable. Second step involved trying to look through documentation but so far I haven't really found any substantial documentation that can help.
func createGavelTimer() {
let openingGavelDate = NSDateComponents()
openingGavelDate.year = 2019
openingGavelDate.month = 7
openingGavelDate.day = 16
openingGavelDate.hour = 14
openingGavelDate.minute = 00
openingGavelDate.timeZone = NSTimeZone(abbreviation: "CST")! as TimeZone
var date = String(openingGavelDate) //problem is here
countdownLabel.text = date
}
One of possible solutions:
let date = Calendar.current.date(from: openingGavelDate)
let dateFormatter = DateFormatter()
dateFormatter.timeStyle = .short
dateFormatter.dateStyle = .medium
dateFormatter.doesRelativeDateFormatting = true
dateFormatter.timeZone = TimeZone(abbreviation: "CST")!
let yourString = dateFormatter.string(from: date)
Try converting the NSDateComponents object to a Date by using Calendar.date(from:), and then converting that to a String using a DateFormatter:
let gregorianCalendar = Calendar(identifier: .gregorian)
if let date = gregorianCalendar.date(from: openingGavelDate as DateComponents) {
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = .medium
dateFormatter.timeStyle = .none
countdownLabel.text = dateFormatter.string(from: date)
}
Also, as #Sh_Khan and #rmaddy have commented, you should be using DateComponents, TimeZone, etc. instead of their NS counterparts (unless you're using Swift 2 or lower).
Two things you need to do to form your date:
Set a calendar on the DateComponents instance.
Get your date by accessing the date property on your DateComponents instance.
Also, I'd recommend using time zone identifiers instead of abbreviation to specify a time zone; advantage is that identifiers will automatically apply special rules such as daylight savings as appropriate. (Below I've substituted the "America/Chicago" zone for UTC.)
Try this code in a playground:
var openingGavelDate = DateComponents()
let timeZone = TimeZone(identifier: "America/Chicago")!
openingGavelDate.year = 2019
openingGavelDate.month = 7
openingGavelDate.day = 16
openingGavelDate.hour = 14
openingGavelDate.minute = 00
openingGavelDate.calendar = Calendar.current
openingGavelDate.timeZone = timeZone
let date = openingGavelDate.date
print(date ?? "no date")
Output: 2019-07-16 19:00:00 +0000 (your date in GMT.)
This will get you a date, but notice that the Date class prints in GMT by default, because Date has no concept of timezone.
To print date in the timezone and format you want, use DateFormatter:
let f = DateFormatter()
f.dateFormat = "yyyy-MM-dd hh:mm a"
f.timeZone = TimeZone(identifier: "America/Chicago")!
print(f.string(from: date!))
Output: 2019-07-16 02:00 PM (your date & time, in CST and formatted for reading.)
DateFormatter allows you to either control the format yourself, or follow the user's system settings to determine what is in the final string. See the docs for DateFormatter to see how to get it into the format you want to display.

Why does Date formatter returns date correctly but time is showing as 00:00:00 when converting string to NSDate

I have a function where i have to retrieve a date from my own sqlite db of app. I have saved it using the formatter
My work flow
1..Save a date to db on Application did enter background(Saved as String)
2..When application become foreground again i make a date instance at that point of time too. Now i have two date's.
3..Convert both dates to correct format and get the seconds difference.
Convert from date to String-->
let formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss.Z"
let myString = formatter.stringFromDate(NSDate()) // i get value"2017-05-18 16:49:38.+0530"
But when i reconvert it to NSDate(I Mean when i convert this to string again)-->
let formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss.Z"
let lastloginDate=formatter.dateFromString(lastLogin) // i get value(Converting back to string \n for checking as the time difference was zero ) 2017-05-18 00:00:00.+0530
I want to compare two dates like a session out service , I do this by getting the calendar components difference of minute. However since its coming like this, the difference his always zero .
let myString1 = formatter.stringFromDate(date1)
let myString2 = formatter.stringFromDate(date2)
print("DATE 1\(myString1) DATE 2 \(myString2)")
let components = calendar.components(flags, fromDate: date2, toDate: date1, options: [])
let diff = components.second
print("Diffrence is \(diff)") // Always zero 😱
Why is this?
Try this one.
let myString1 = formatter.stringFromDate(date1)
let myString2 = formatter.stringFromDate(date2)
print("DATE 1\(myString1) DATE 2 \(myString2)")
let components = NSCalendar.currentCalendar().components([.Month, .Day, .Hour, .Minute, .Second], fromDate: myString1, toDate: myString2, options: [])
let diff = components.second
print("Difference is \(diff)")

Swift3 extracting a Date from a Custom Format String

Using the following overly complex code a date can almost be extracted from a string:
let dateStringArray:[String] = ["29-01-2017 10:41:18:825325012","29-01-2017 10:41:18:894631028"]
let formatString = "dd-MM-yyyy HH:mm:ss:nnnnnnnnn"
let dayRange = formatString.range(of: "dd")
let monthRange = formatString.range(of: "MM")
let yearRange = formatString.range(of: "yyyy")
let hourRange = formatString.range(of: "HH")
let minuteRange = formatString.range(of: "mm")
let secondRange = formatString.range(of: "ss")
let nanoRange = formatString.range(of:"nnnnnnnnn")
let dateString = dateStringArray[0]
let dateComponents = DateComponents( year:Int(dateString.substring(with: yearRange!)),
month:Int(dateString.substring(with: monthRange!)),
day:Int(dateString.substring(with: dayRange!)),
hour:Int(dateString.substring(with: hourRange!)),
minute:Int(dateString.substring(with: minuteRange!)),
second:Int(dateString.substring(with: secondRange!)),
nanosecond:Int(dateString.substring(with: nanoRange!)))
let nano = Int(dateString.substring(with: nanoRange!))
let currentCalendar = Calendar.current
let dateExtracted = currentCalendar.date(from: dateComponents)
print("\(dateExtracted!)")
The output from the final print is: "2017-01-29 10:41:18 +0000\n"
There are issues with this (1) there must be an easier way. (2) & more important, why is the nanosecond component apparently not appearing?
(1) there must be an easier way
Use a date formatter:
let dateString = "29-01-2017 10:41:18:825325012"
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.dateFormat = "dd-MM-yyyy HH:mm:ss:SSSSSSSS"
let dateExtracted = dateFormatter.date(from: dateString)!
(2) why is the nanosecond component apparently not appearing?
The description method of Date does not show fractional seconds, but
you can extract it again with
currentCalendar.component(.nanosecond, from: dateExtracted!)
The result may be slightly different from the original nanosecond value
in the string due to rounding errors, because Date stores internally
a floating point number (number of seconds since the reference date
Jan 1, 2001). If you use a date formatter as suggested above then
the resolution is limited to milliseconds (compare NSDateFormatter milliseconds bug).

NSDate which is returned is incorrect

I am build a function to get the date for the Chinese new year from the date which is passed from a datePicker. the convertDateFormater converts a string formatted date to a date object. the date which i get back is
Returned date = "03-Feb-2030" for the year "1970-05-22"
but if i run the current date with "NSDate() as Date" i get the right output. for the year 2016.
func convertDateFormater(date: String) -> Date
{
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"//this your string date format
dateFormatter.timeZone = NSTimeZone(name: "UTC") as TimeZone!
let date = dateFormatter.date(from: date)
return date!
}
var inputDate1 = convertDateFormater(date: "1970-05-22")
print(inputDate1)
let chineseCalendar = NSCalendar(calendarIdentifier: NSCalendar.Identifier.chinese)!
let formatter: DateFormatter = {
let fmt = DateFormatter()
fmt.dateStyle = .full
fmt.timeStyle = .full
fmt.dateFormat = "dd-MMM-yyyy"
return fmt
}()
var comps = chineseCalendar.components([.year], from: inputDate)
guard let newYear = chineseCalendar.date(from: comps) else { fatalError("no date for \(comps.year)")}
let getNewYear = formatter.string(from: newYear)
print("\(NSDate() as Date) : \(getNewYear) - \(newYear)")
In the Gregorian calendar, there are two eras: the current "Common Era" (abbreviated "CE" and also known as "Anno Domini" or "AD") and "Before Common Era" (abbreviated "BCE" and also known as "Before Christ" or "BC"). So a year number on the Gregorian calendar is ambiguous: "1970" by itself can mean either "1970 CE" or "1970 BCE". We usually assume CE when no era is specified.
I know almost nothing about the Chinese calendar, but I know it has many more eras than the Gregorian calendar, so a year number on the Chinese calendar is even more ambiguous. The code you posted doesn't do anything about eras. So I copied and pasted your code into a playground and made one change:
var comps = chineseCalendar.components([.era, .year], from: inputDate)
// ^^^^^^
The output:
1970-05-22 00:00:00 +0000
2016-11-30 01:40:12 +0000 : 06-Feb-1970 - 1970-02-06 06:00:00 +0000
Indeed, 1970-02-06 was the date of the Chinese new year in 1970 CE on the Gregorian calendar.