A user posts a comment in a different timezone and another user views the comment in different timezone. The time should be the same when converted back to the users timezone on their device.
Here's what I am trying but getting an "fatal error: unexpectedly found nil while unwrapping an Optional value". The error is happening in my distance time variable when its trying to subtract "time". I printed time before it executed and its saying "nil". Any help please?
import UIKit
class EventCommentCell: UITableViewCell {
var obj : EventCommentObj!
#IBOutlet var profileImage: UIImageView!
#IBOutlet var commentMessage: UITextView!
#IBOutlet var time: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func setData(){
profileImage.layer.borderWidth = 1
profileImage.layer.masksToBounds = false
profileImage.layer.borderColor = UIColor(red: 0.125, green: 0.757, blue: 0.569, alpha: 1.0).CGColor
profileImage.layer.cornerRadius = profileImage.frame.height/2
profileImage.clipsToBounds = true
print("The Image URL : \(obj.profileImage)")
ImageLoader.sharedLoader.imageForUrl(obj.profileImage, completionHandler:{(image: UIImage?, url: String) in
self.profileImage.image = image
})
let message = "\(obj.username) \n\(obj.comment)"
let attributedString = NSMutableAttributedString(string: message as String)
let range: NSRange = (message as NSString).rangeOfString(obj.username as String)
let range1: NSRange = (message as NSString).rangeOfString(obj.comment as String)
let font = UIFont.boldSystemFontOfSize(commentMessage.font!.pointSize)
attributedString.addAttribute(NSFontAttributeName, value: font, range: range)
attributedString.addAttribute(NSForegroundColorAttributeName, value: UIColor(red: 0.125, green: 0.757, blue: 0.569, alpha: 1.0), range: range)
commentMessage.attributedText = attributedString
time.text = getCreationTimeInt(obj.created_on)
}
func getCreationTimeInt(dateString : String) -> String{
let dateFormatter = NSDateFormatter()
dateFormatter.locale = NSLocale.currentLocale()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
dateFormatter.timeZone = NSTimeZone(forSecondsFromGMT: 0)
dateFormatter.timeZone = NSTimeZone.systemTimeZone()
let time = dateFormatter.dateFromString(dateString)?.timeIntervalSince1970
let distanceTime = NSDate().timeIntervalSince1970 - time!
let stringTime = returnDistanceTime(distanceTime)
print("**** The time \(stringTime)", terminator: "")
return stringTime
}
func returnDistanceTime(distanceTime : Double) -> String{
var stringTime = ""
if (distanceTime < 0) {
stringTime = "0s"
}else{
if(distanceTime < 60){
stringTime = "\(Int(distanceTime))s"
}else{
if(distanceTime < 3600){
stringTime = "\(Int(distanceTime/60))m"
}else{
if(distanceTime < 3600*24){
stringTime = "\(Int(distanceTime/3600))h"
}else{
if(distanceTime < 3600*24*7) {
stringTime = "\(Int(distanceTime/3600/24))d"
}else{
stringTime = "\(Int(distanceTime/3600/24/7))w"
}
}
}
}
}
return stringTime
}
}
Welcome to stack overflow. I plugged what you had into a Playground and it worked perfectly. Here is what I have:
//: Playground - noun: a place where people can play
import Cocoa
func returnDistanceTime(distanceTime: NSTimeInterval) -> String{
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
return dateFormatter.stringFromDate(NSDate())
}
func getCreationTimeInt(dateString : String) -> String{
let dateFormatter = NSDateFormatter()
dateFormatter.locale = NSLocale.currentLocale()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
dateFormatter.timeZone = NSTimeZone(forSecondsFromGMT: 0)
dateFormatter.timeZone = NSTimeZone.systemTimeZone()
dateFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
let time = dateFormatter.dateFromString(dateString)?.timeIntervalSince1970
let distanceTime = NSDate().timeIntervalSince1970 - time!
let stringTime = returnDistanceTime(distanceTime)
print("**** The time \(stringTime)", terminator: "")
return stringTime
}
getCreationTimeInt("2016-03-01 12:12:12")
This is an answer from above from Aaron but in Swift 5
func returnDistanceTime(distanceTime: TimeInterval) -> String{
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
return dateFormatter.string(from: NSDate() as Date)
}
func getCreationTimeInt(dateString : String) -> String{
let dateFormatter = DateFormatter()
dateFormatter.locale = NSLocale.current
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
dateFormatter.timeZone = NSTimeZone(forSecondsFromGMT: 0) as TimeZone
dateFormatter.timeZone = NSTimeZone.system
dateFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") as Locale
let time = dateFormatter.date(from: dateString)?.timeIntervalSince1970
let distanceTime = NSDate().timeIntervalSince1970 - time!
let stringTime = returnDistanceTime(distanceTime: distanceTime)
print("**** The time \(stringTime)", terminator: "")
return stringTime
}
Related
I'm trying to make a converter from Grigorian date to Hijri date. For this I'm using UIDatePicker. Here is how it looks now: https://i.stack.imgur.com/s5hAk.png
Here is my code in viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
topPicker.datePickerMode = .date
bottomPicker.datePickerMode = .date
bottomPicker.calendar = Calendar(identifier: .islamicUmmAlQura)
topPicker.calendar = Calendar(identifier: .gregorian)
topPicker.addTarget(self, action: #selector(datePickerValueChange(sender:)), for: .valueChanged)
bottomPicker.addTarget(self, action: #selector(datePickerValueChange(sender:)), for: .valueChanged)
hijriLabel.text = setHijri(date: Date())
grigorianLabel.text = setGrigorian(date: Date())
}
Methods which I've tried to convert the date:
func setDateFormat(date: Date) -> String {
let dateFormatter: DateFormatter = DateFormatter()
dateFormatter.dateStyle = .medium
dateFormatter.timeStyle = .short
dateFormatter.dateFormat = "dd-MM-yyyy"
//dateFormatter.locale = NSLocale(localeIdentifier: "ru_RU") as Locale!
let string = dateFormatter.string(from: date.convertedDate)
return string
}
func setHijri(date:Date) -> String {
let dateFor = DateFormatter()
let hijriCalendar = Calendar.init(identifier: Calendar.Identifier.islamic)
dateFor.locale = Locale.init(identifier: LocalizationVars.localizationCode) // or "en" as you want to show numbers
dateFor.calendar = hijriCalendar
dateFor.dateStyle = .medium
dateFor.timeStyle = .none
//dateFor.dateFormat = "dd-MM-yyyy"
dateFor.dateFormat = "dd MMMM yyyy "
return dateFor.string(from: date) + "AH"
}
func setGrigorian(date:Date) -> String {
let dateFor = DateFormatter()
let hijriCalendar = Calendar.init(identifier: Calendar.Identifier.gregorian)
dateFor.locale = Locale.init(identifier: LocalizationVars.localizationCode) // or "en" as you want to show numbers
dateFor.calendar = hijriCalendar
dateFor.dateStyle = .medium
dateFor.timeStyle = .none
dateFor.dateFormat = "EEEE, MMMM d"
// dateFor.dateFormat = "dd MMMM yyyy "
return dateFor.string(from: date)
}
}
extension Date {
var convertedDate:Date {
let dateFormatter = DateFormatter();
let dateFormat = "dd MMM yyyy";
dateFormatter.dateFormat = dateFormat;
let formattedDate = dateFormatter.string(from: self);
dateFormatter.locale = NSLocale.current;
dateFormatter.timeZone = TimeZone.current
dateFormatter.dateFormat = dateFormat as String;
let sourceDate = dateFormatter.date(from: formattedDate as String);
return sourceDate!;
}
}
And here is the code, in changeValue method:
#objc func datePickerValueChange(sender: UIDatePicker){
// self.view.endEditing(true)
let dateFormatter: DateFormatter = DateFormatter()
dateFormatter.dateStyle = .medium
dateFormatter.timeStyle = .none
dateFormatter.timeZone = TimeZone.current
dateFormatter.dateFormat = "dd-MM-yyyy"
let hinjiData = setHijri(date: sender.date)
let formatter = DateFormatter()
formatter.dateFormat = "dd-MM-yyyy"
let GregorianDate = formatter.date(from: hinjiData)
let islamic = NSCalendar(identifier: NSCalendar.Identifier.islamicUmmAlQura)
//let components = islamic?.components(NSCalendar.Unit(rawValue: UInt.max), from: GregorianDate!)
let selectedDate = setDateFormat(date: sender.date)
if sender.tag == 1 {
print(hinjiData)
//bottomPicker.setDate((components?.date)!, animated: true)
print(bottomPicker.date)
hijriLabel.text = setHijri(date: sender.date)
print(hijriLabel.text)
grigorianLabel.text = setGrigorian(date: sender.date)
}else {
topPicker.date = dateFormatter.date(from: selectedDate)!
hijriLabel.text = setHijri(date: sender.date)
grigorianLabel.text = setGrigorian(date: sender.date)
print(selectedDate)
}
}
The date is converting good, but it only displayed in the label, not in UIDatePicker.
I need to return date string is same format I retrieve it, but after converting to Date and back it lose few characters
var dateStr = "2019-08-02T11:46:46.5117312Z"
let formatter = DateFormatter()
formatter.calendar = Calendar(identifier: .iso8601)
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
let date = formatter.date(from: dateStr)
var str = formatter.string(from: date!) // ===>>> "2019-08-02T11:46:46.511Z"
You can do it with custom formatter. But note that there not enough Double precision to store date. Result is 2019-08-02T11:46:46.5117311Z. Code:
class CustomDateFormatter {
private let dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.calendar = Calendar(identifier: .iso8601)
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
return formatter
}()
func date(fromString str: String) -> Date? {
let strs = str.components(separatedBy: CharacterSet(charactersIn: ".Z"))
if strs.count != 3 {
return nil
}
let dateStr = strs[0]
let secondsStr = strs[1]
guard let date = dateFormatter.date(from: dateStr),
let seconds = Double("0."+secondsStr) else {
return nil
}
let timeinteval = date.timeIntervalSince1970 + seconds
return Date(timeIntervalSince1970: timeinteval)
}
func string(fromDate date: Date) -> String {
let clippedDate = Date(timeIntervalSince1970: floor(date.timeIntervalSince1970))
let seconds = date.timeIntervalSince1970.truncatingRemainder(dividingBy: 1)
var lastPart = String(format: "%.7f", seconds)
lastPart = (lastPart as NSString).substring(from: 1)
return "\(dateFormatter.string(from: clippedDate))\(lastPart)Z"
}
}
let dateStr = "2019-08-02T11:46:46.5117312Z"
let formatter = CustomDateFormatter()
let date = formatter.date(fromString: dateStr)!
print(formatter.string(fromDate: date)) // =====>> 2019-08-02T11:46:46.5117311Z
I have two datepickers that contains time with format 7:00 AM and 8:00 PM for login and logout. These times may vary. I wanted to change the logout time and tried to use the login time as the minimum time but my code does not work, I can still select time like 1:00 AM or 6:00 AM as logout.
This is the code in my ViewDidLoad
if let actualLoginText = loginTextField.text {
let start = actualLoginText
let formatter = DateFormatter()
formatter.dateStyle = .none
formatter.timeStyle = .short
formattedTime = formatter.date(from: start)!
}
And this is the code of my logout picker
#objc func timeOutPickerValueChanged(sender: UIDatePicker) {
let formatter = DateFormatter()
formatter.dateStyle = .none
formatter.timeStyle = .short
timeOutPicker.minimumDate = Calendar.current.date(byAdding: .minute, value: 5, to: formattedTime)
logoutTextField.text = formatter.string(from: sender.date)
}
I also tried this but still doesn't work
if let actualLoginText = loginTextField.text {
let start = actualLoginText
let formatter = DateFormatter()
formatter.dateFormat = "hh:mm a"
formattedTime = formatter.date(from: start)!
}
Thank you.
When working with dates / times, work with Date objects, not strings. The "string representation" should only be used to display the date/time to the user, not when manipulating the values.
Here is a simple example (assuming you have added two UIDatePickers and connected their Value Changed events). On load, it initializes the timeInPicker to the current date/time. Any time you select a new "Time In", the timeOutPicker.minimumDate is set to 5-minutes from the selected time, and the timeOutPicker.maximumDate is set to 8-hours from the minimum time:
class ViewController: UIViewController {
#IBOutlet weak var timeInPicker: UIDatePicker!
#IBOutlet weak var timeOutPicker: UIDatePicker!
let dateFormatter: DateFormatter = {
let df = DateFormatter()
df.dateStyle = .short
df.timeStyle = .short
return df
}()
override func viewDidLoad() {
super.viewDidLoad()
// Initialize the TimeIn and TimeOut pickers to the current Date/Time
let now = Date()
updateTimeOutPicker(now)
}
func updateTimeOutPicker(_ withStartDateTime: Date) -> Void {
// add 5 minutes to the selected "In" time to get the "minimum time" for the Out Picker
guard let minDateTime = Calendar(identifier: .gregorian).date(byAdding: .minute, value: 5, to: withStartDateTime) else { return }
// add 8 hours to the to get the "maximum time" for the Out Picker
guard let maxDateTime = Calendar(identifier: .gregorian).date(byAdding: .hour, value: 8, to: minDateTime) else { return }
timeOutPicker.minimumDate = minDateTime
timeOutPicker.maximumDate = maxDateTime
print("New Min Out Time:", dateFormatter.string(from: minDateTime))
print("New Max Out Time:", dateFormatter.string(from: maxDateTime))
print()
}
#IBAction func timeInPickerValueChanged(_ sender: UIDatePicker) {
print("Selected In Time:", dateFormatter.string(from: sender.date))
print()
updateTimeOutPicker(sender.date)
}
#IBAction func timeOutPickerValueChanged(_ sender: UIDatePicker) {
print("Selected Out Time:", dateFormatter.string(from: sender.date))
print()
}
}
The login and logout time strings were pulled up from database. And when I don't edit the login textfield it's data remains as string since there was no value change, so I'm forced to use a string value as reference to my logout picker.
the result login being: 1999-12-31 23:00:00 +0000
and logout: 2018-01-04 22:24:20 +0000
this is the reason why using the login as my minimum time didn't work
so here's what I did, I added the current date so I can use it.
#objc func timeOutPickerValueChanged(sender: UIDatePicker) {
if let actualLoginText = loginTextField.text {
let date = Date()
let start = actualLoginText
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
let nowTime = formatter.string(from: date)
let concat = nowTime + " " + start
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd hh:mm a"
formattedTime = dateFormatter.date(from: concat)!
}
let formatter = DateFormatter()
formatter.dateStyle = .none
formatter.timeStyle = .short
timeOutPicker.minimumDate = Calendar.current.date(byAdding: .minute, value: 5, to: formattedTime)
logoutTextField.text = formatter.string(from: sender.date)
}
I am new to swift, Am using Fscalender in swift it's working fine, But I want add the Events to Fscalender, I can get events from Json
I Want Display the events in calender, I can try some of the code but its not working getting some errors pls help how to display events in calender
var EventsData = [Event]()
all events are stored Into Event
fileprivate lazy var dateFormatter2: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
return formatter
}()
inside Json
if let event_list = jsonData["events"] as? NSArray {
for i in 0 ..< event_list.count {
if let event = event_list[i] as? NSDictionary {
let data = event["date"]as?String
let newString = data?.replacingOccurrences(of: "/", with: "-")
print("new string data ",newString as Any)
self.compareDate(date: newString!)
self.EventsData.append(Event(
eventId: event["eventId"] as? String,
eventName:event["details"] as? String,
//eventDate: event["date"] as? String
eventDate: newString ))
}
}
}
Display the Events
func compareDate(date : String){
let date = date
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
let dateFromString : NSDate = dateFormatter.date(from: date)! as NSDate
===>> After this line showing Fatal error
dateFormatter.dateFormat = "yyyy-MM-dd"
let datenew = dateFormatter.string(from: dateFromString as Date)
print("datee",datenew)
}
func calendar(_ calendar: FSCalendar, willDisplay cell: FSCalendarCell, for date: Date, at position: FSCalendarMonthPosition) {
let dateFormatter3 = DateFormatter()
dateFormatter3.dateFormat = "yyyy-MM"
let dateString3 = dateFormatter3.string(from: date)
//print("datenew1",dateString3)
strcond = dateString3 as NSString
print("datenew1",strcond!)
}
func calendar(_ calendar: FSCalendar, numberOfEventsFor date: Date) -> Int {
let dateString = self.dateFormatter2.string(from: date)
for d in EventsData{
let date = d.eventDate
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
let dateFromString : NSDate = dateFormatter.date(from: date!)! as NSDate
dateFormatter.dateFormat = "yyyy-MM-dd"
let datenew = dateFormatter.string(from: dateFromString as Date)
if datenew.contains(dateString) {
return 1
}
}
return 0
}
func calendar(_ calendar: FSCalendar, appearance: FSCalendarAppearance, eventColorFor date: Date) -> UIColor? {
let dateString = self.dateFormatter2.string(from: date)
for d in EventsData{
let date = d.eventDate
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
let dateFromString : NSDate = dateFormatter.date(from: date!)! as NSDate
dateFormatter.dateFormat = "yyyy-MM-dd"
let datenew = dateFormatter.string(from: dateFromString as Date)
print("new calendar",dateString)
if datenew.contains(dateString) {
return UIColor.purple
}
}
return nil
}
func calendar(_ calendar: FSCalendar, didSelect date: Date, at monthPosition: FSCalendarMonthPosition) {
if monthPosition == .previous || monthPosition == .next {
calendar.setCurrentPage(date, animated: true)
print("title date",date)
}
}
how to show events in calendar ?
After some changes in my code it's working fine showing events in FsCalender
inside Json
if let event_list = jsonData["events"] as? NSArray {
for i in 0 ..< event_list.count {
if let event = event_list[i] as? NSDictionary {
self.EventsData.append(Event(
eventId: event["eventId"] as? String,
eventName:event["details"] as? String,
eventDate: event["date"] as? String
)
)
}
}
self.do_refresh()
}
func do_refresh()
{
DispatchQueue.main.async(execute: {
self.calender.reloadData()
return
})
}
Fscalender Implementation
func calendar(_ calendar: FSCalendar, willDisplay cell: FSCalendarCell, for date: Date, at position: FSCalendarMonthPosition) {
let dateFormatter3 = DateFormatter()
dateFormatter3.dateFormat = "yyyy-MM-dd"
let dateString3 = dateFormatter3.string(from: date)
strcond = dateString3 as NSString
}
func calendar(_ calendar: FSCalendar, numberOfEventsFor date: Date) -> Int {
let dateString = self.dateFormatter2.string(from: date)
print("this count first ",self.EventsData.count)
for d in EventsData{
let date = d.eventDate
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MM-dd-yyyy"
let dateFromString : NSDate = dateFormatter.date(from: date!)! as NSDate
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
let datenew = dateFormatter.string(from: dateFromString as Date)
if datenew.contains(dateString) {
return 3
}
}
return 0
}
func calendar(_ calendar: FSCalendar, appearance: FSCalendarAppearance, eventColorFor date: Date) -> UIColor? {
let dateString = self.dateFormatter2.string(from: date)
for d in EventsData{
let date = d.eventDate
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MM-dd-yyyy"
let dateFromString : NSDate = dateFormatter.date(from: date!)! as NSDate
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
let datenew = dateFormatter.string(from: dateFromString as Date)
if datenew.contains(dateString) {
return UIColor.init(red: 10, green: 200, blue: 399, alpha: 300)
}
}
return nil
}
I'm making a UILabel that indicates the value of the self.timer.
This is the code.
The problem is that I can't indicate the timeFormatter.stringFromDate(date_SSS) in the label.text.
Actually I also have a scrollView and a pageControl to scroll the label horizontally. But the main problem is at the UILabel and the self.timer.
import UIKit
class ViewController: UIViewController {
private var label: UILabel!
private var timer: NSTimer!
let intArray: String = ["12:00:00", "12:50:00", "15:30:00", "16:40:00"]
let i = 0
override func viewDidLoad() {
let timeFormatter = NSDateFormatter()
timeFormatter.dateFormat = "HH:mm:ss"
self.timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "update:", userInfo: nil, repeats: true)
self.timer.fire()
for (var i = 0; i < intArray.count; i++) {
let label: UILabel = UILabel(frame: CGRectMake(CGFloat(index) * 50,100,150,200)
label.cornerRadius = 20
label.text = timeFormatter.stringFromDate(date_SSS)
view.addSubView(label)
}
}
func dateFromString(date:String) -> NSDate? {
let calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
calendar.locale = NSLocale(localeIdentifier: "en_US_POSIX")
calendar.timeZone = NSTimeZone(abbreviation: "JST")!
let begin = date.startIndex
guard let hour = Int(date.substringWithRange(begin..<begin.advancedBy(2))),
let minute = Int(date.substringWithRange(begin.advancedBy(3)..<begin.advancedBy(5))),
let second = Int(date.substringWithRange(begin.advancedBy(6)..<begin.advancedBy(8))) else{
return nil
}
return calendar.dateBySettingHour(hour, minute: minute, second: second, ofDate: NSDate(), options: [])
}
func update(timer: NSTimer) {
let timeFormatter: NSDateFormatter = NSDateFormatter()
timeFormatter.timeZone = NSTimeZone(name: "GMT")
timeFormatter.dateFormat = "HH:mm:ss"
let time = dateFromString(intArray[i])
let remain = time!.timeIntervalSinceDate(NSDate())
let date_SSS = NSDate(timeIntervalSince1970: remain)
}
}
well, you are not setting your label in your update method, so it's hard to see how it would change. maybe I don't understand your question.