Swift displaying the time or date based on timestamp - swift

I have an API that returns data including a timestamp for that record.
In swift I have the timestamp element loaded and converted into a double and can then convert that into time. I want to be able to return the time if the date of the record is today and return the date if the record is not today.
See below:
let unixTimeString:Double = Double(rowData["Timestamp"] as! String)!
let date = NSDate(timeIntervalSince1970: unixTimeString) // This is on EST time and has not yet been localised.
var dateFormatter = NSDateFormatter()
dateFormatter.timeStyle = .ShortStyle
dateFormatter.doesRelativeDateFormatting = true
// If the date is today then just display the time, if the date is not today display the date and change the text color to grey.
var stringTimestampResponse = dateFormatter.stringFromDate(date)
cell.timestampLabel.text = String(stringTimestampResponse)
Do I use NSCalendar to see if 'date' is today and then do something?
How do you then localise the time so that its correct for the user rather than server time?

There is a handy function on NSCalendar that tells you whether an NSDate is in today or not (requires at least iOS 8) isDateInToday()
To see it working, put this into a playground:
// Create a couple of unix dates.
let timeIntervalToday: NSTimeInterval = NSDate().timeIntervalSince1970
let timeIntervalLastYear: NSTimeInterval = 1438435830
// This is just to show what the dates are.
let now = NSDate(timeIntervalSince1970: timeIntervalToday)
let then = NSDate(timeIntervalSince1970: timeIntervalLastYear)
// This is the function to show a formatted date from the timestamp
func displayTimestamp(ts: Double) -> String {
let date = NSDate(timeIntervalSince1970: ts)
let formatter = NSDateFormatter()
formatter.timeZone = NSTimeZone.systemTimeZone()
if NSCalendar.currentCalendar().isDateInToday(date) {
formatter.dateStyle = .NoStyle
formatter.timeStyle = .ShortStyle
} else {
formatter.dateStyle = .ShortStyle
formatter.timeStyle = .NoStyle
}
return formatter.stringFromDate(date)
}
// This should just show the time.
displayTimestamp(timeIntervalToday)
// This should just show the date.
displayTimestamp(timeIntervalLastYear)
Or, if you just want to see what it looks like without running it yourself:

Abizern's answer in Swift 3:
import UIKit
let timeIntervalToday: TimeInterval = Date().timeIntervalSince1970
let timeIntervalLastYear: TimeInterval = 1438435830
// This is just to show what the dates are.
let now = Date(timeIntervalSince1970: timeIntervalToday)
let then = Date(timeIntervalSince1970: timeIntervalLastYear)
// This is the function to show a formatted date from the timestamp
func displayTimestamp(ts: Double) -> String {
let date = Date(timeIntervalSince1970: ts)
let formatter = DateFormatter()
//formatter.timeZone = NSTimeZone.system
if Calendar.current.isDateInToday(date) {
formatter.dateStyle = .none
formatter.timeStyle = .short
} else {
formatter.dateStyle = .short
formatter.timeStyle = .none
}
return formatter.string(from: date)
}
// This should just show the time.
displayTimestamp(ts: timeIntervalToday)
// This should just show the date.
displayTimestamp(ts: timeIntervalLastYear)

Related

Creating Date object from timestamp in Swift [duplicate]

I get a crash when running and it points at the dateFormmater.timezone.
The error in the console is:
Could not cast value of type 'Swift.Optional' (0x1192bf4a8) to 'NSTimeZone' (0x1192c0270).
the value of rowEvents.date is "1480134638.0"
Im trying to pull out a Unix timestamp from Firebase saved as a string. Convert it to Date and again save it as a string so I can post it on a cell label.
I got this code from StackOverflow. I plugged in my data and everything is all good until I run it. I guess everything is not all good...
if let lastUpdated : String = rowEvents.date {
let epocTime = TimeInterval(lastUpdated)! / 1000 // convert it from milliseconds dividing it by 1000
let unixTimestamp = NSDate(timeIntervalSince1970: epocTime) //convert unix timestamp to Date
let dateFormatter = DateFormatter()
dateFormatter.timeZone = NSTimeZone() as TimeZone!
dateFormatter.locale = NSLocale.current // NSLocale(localeIdentifier: "en_US_POSIX")
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
dateFormatter.date(from: String(describing: unixTimestamp))
let updatedTimeStamp = unixTimestamp
let cellDate = DateFormatter.localizedString(from: updatedTimeStamp as Date, dateStyle: DateFormatter.Style.full, timeStyle: DateFormatter.Style.medium)
cell.subtitleLabel.text = cellDate
}
The result came from this code here:
let myTimeStamp = self.datePicker?.date.timeIntervalSince1970
let calendarDate = String(describing: myTimeStamp! /** 1000*/)
You can convert unixTimestamp to date using Date(timeIntervalSince1970:).
let unixTimestamp = 1480134638.0
let date = Date(timeIntervalSince1970: unixTimestamp)
If you want to display date in string with specific formate than you can use DateFormatter like this way.
let date = Date(timeIntervalSince1970: unixtimeInterval)
let dateFormatter = DateFormatter()
dateFormatter.timeZone = TimeZone(abbreviation: "GMT") //Set timezone that you want
dateFormatter.locale = NSLocale.current
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm" //Specify your format that you want
let strDate = dateFormatter.string(from: date)
The problem is the line dateFormatter.timeZone = NSTimeZone() as TimeZone!.
Simply use TimeZone instead of NSTimeZone like
dateFormatter.timeZone = TimeZone.current and your code will work.
You might also remove your / 1000 because 1480134638.0 looks more like seconds than milliseconds (since 1970).
Swift 4.1. I created a function. Just pass you timeStamp in function param and function will return data in string data type. You can add more properties to DateFormatter object.
func getDateFromTimeStamp(timeStamp : Double) -> String {
let date = NSDate(timeIntervalSince1970: timeStamp / 1000)
let dayTimePeriodFormatter = DateFormatter()
dayTimePeriodFormatter.dateFormat = "dd MMM YY, hh:mm a"
// UnComment below to get only time
// dayTimePeriodFormatter.dateFormat = "hh:mm a"
let dateString = dayTimePeriodFormatter.string(from: date as Date)
return dateString
}
Using playground all I did was this.
let epochTime = 1547855446
let newTime = Date(timeIntervalSince1970: TimeInterval(epochTime))
print(newTime)
Returns this - 2019-01-18 23:50:46 +0000
extension Double{
func convertDate(formate: String) -> String {
let date = (timeIntervalSince1970: self)
let dateFormatter = DateFormatter()
dateFormatter.timeZone = TimeZone.current
dateFormatter.locale = NSLocale(localeIdentifier: "(your localization language)" ) as Locale //localization language
dateFormatter.dateFormat = formate //Specify your format that you want let
strDate = dateFormatter.string(from: date)
return strDate
}
}
//usage
let timeStamp:Double = Double(1595407043)
print(timeStamp.convertDate(formate: "EEEE dd/MM/YYY"))
This solution is valid for swift 3 -> 4.2 :
you can add an extension on the Double that returns the date formatted:
extension Double {
// returns the date formatted.
var dateFormatted : String? {
let date = Date(timeIntervalSince1970: self)
let dateFormatter = DateFormatter()
dateFormatter.timeStyle = DateFormatter.Style.none //Set time style
dateFormatter.dateStyle = DateFormatter.Style.short //Set date style
return dateFormatter.string(from: date)
}
// returns the date formatted according to the format string provided.
func dateFormatted(withFormat format : String) -> String{
let date = Date(timeIntervalSince1970: self)
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = format
return dateFormatter.string(from: date)
}
}
example on the above :
let timeStamp = 82749029.0
print(timeStamp. dateFormatted)
//output
//12/11/1994
let timeStamp = 82749029.0
print(timeStamp. dateFormatted(withFormat : "MM-dd-yyyy HH:mm"))
//output
//12-11-1994 13:04

Getting Hour value from time string in Swift

I am trying to get an Int value for Hour from a string.
let time = 13:24
func getNtfHour() -> Date{
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "HH"
let result = dateFormatter.date(from: time)!
return result //2000-01-01 08:24:00 +0000
}
As you can see my current code return a whole date and the time does not match with the string. How do I fix it?
edit: I managed to to this by using date components
let time = 13:24
func getNtfHour() -> Int{
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "HH:mm"
let result = dateFormatter.date(from: time)!
let calendar = Calendar.current.component(.hour, from: result)
return calendar //13
}
As a time string is actually not related to a Dateformatter an easier way is to parse the string directly.
If the hour has always two digits
let time = "13:24"
let hour = Int(time.prefix(2))
or otherwise
let time = "13:24"
if let range = time.range(of: "^\\d+", options: .regularExpression) {
let hour = Int(time[range])
}

Problem converting a string to a Date Object

I have a DatePicker View, When the user clicks a UITextField, it show the DatePicker, which the user can of course, pick a date.
The problem is, when I'm trying to convert the String, to be a date object, I get nothing, so I cannot compare two dates for example.
func checkDate(){
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: Locale.current.identifier)
dateFormatter.timeZone = .current
dateFormatter.dateFormat = "dd/MM/yy"
guard let startDate = mView.startDateTextField.text else { return }
print("DATE: \(startDate)")
guard let startDateFromString = dateFormatter.date(from: startDate) else { return } //I think it returns here.
//Won't get here.
print("DATE: \(startDate)")
guard let endDate = mView.endDateTextField.text else { return }
guard let endDateFromString = dateFormatter.date(from: endDate) else { return }
if startDateFromString.compare(endDateFromString) == ComparisonResult.orderedDescending{
print("Start date cannot be greater than end date.")
}
}
I tried to debug, and the break point does gets to startDateFromString line, but from theres "jumps" outside, so I guess it won't get the Date from the string and returns.
I just can't figure out why.
EDIT: This is where I set the TextField Text to be the date chosen from the DatePicker.
#objc func datePickerValueChanged(sender: UIDatePicker){
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = .medium
dateTextField.text = dateFormatter.string(from: sender.date)
}
Maybe you are using wrong dateFormat. Check your dateFormat from here
For example if your dateString is "Mar 1, 2019", you have to use it as dateFormat "MMM d, yyyy"
dateFormatter.dateFormat = "MMM d, yyyy"

NSDateFormatter. Setting time elapsed since date in swift

I'm looking to call a function that checks time elapsed since date. This will determine how the timeLable displays in my messages view controller, similar to IMessage.
The code I'm using below only shows HH:MM
let date = dateFormatter().dateFromString((recent["date"] as? String)!)
timeLabel.text = NSDateFormatter.localizedStringFromDate(date!, dateStyle: NSDateFormatterStyle.NoStyle, timeStyle: NSDateFormatterStyle.NoStyle)
I'm looking to change it to something along the lines of:
If date is today, date = "HH:MM"
If date is Yesterday, date = "Yesterday"
If date is the day before yesterday and so on, date = "Monday, Tuesday, Wednesday..."
If date is over 1 week, date = MM/DD/YY
Or try this. Note that we have to use components:fromDate: and then use components:fromDateComponents:toDateComponents:options: because if we don't 23:59 last night returns 23:59 instead of Yesterday.
extension NSDateFormatter {
static func friendlyStringForDate(date:NSDate) -> String {
// Fetch the default calendar
let calendar = NSCalendar.currentCalendar()
// Compute components from target date
let from = calendar.components([.Day, .Month, .Year], fromDate: date)
// Compute components from current date
let to = calendar.components([.Day, .Month, .Year], fromDate: NSDate())
// Compute days difference between the two
let delta = calendar.components(.Day, fromDateComponents: from, toDateComponents: to, options: [])
switch delta.day {
case 0:
let formatter = NSDateFormatter()
formatter.timeZone = NSTimeZone.defaultTimeZone()
formatter.dateFormat = "HH:mm"
return formatter.stringFromDate(date)
case 1:
return "Yesterday"
case 2..<7:
let formatter = NSDateFormatter()
formatter.timeStyle = .NoStyle
formatter.dateFormat = "EEEE"
return formatter.stringFromDate(date)
default:
let formatter = NSDateFormatter()
formatter.timeStyle = .NoStyle
formatter.dateFormat = "MM/dd/YY"
return formatter.stringFromDate(date)
}
}
}
Now then, to use it just:
timeLabel.text = NSDateFormatter.friendlyStringForDate(date!)
SWIFT 3:
extension DateFormatter {
static func friendlyStringForDate(date: Date) -> String {
// Fetch the default calendar
let calendar = Calendar.current
let unitFlags: NSCalendar.Unit = [.day]
// Compute days difference between the two
let delta = (calendar as NSCalendar).components(unitFlags, from: date, to: Date(), options: [])
if let day = delta.day {
switch day {
case 0:
let formatter = DateFormatter()
formatter.timeZone = NSTimeZone.default
formatter.dateFormat = "hh:mm a"
return formatter.string(from: date)
case 1:
return "Yesterday"
case 2..<7:
let formatter = DateFormatter()
formatter.timeStyle = .none
formatter.dateFormat = "EEEE"
return formatter.string(from: date)
default:
let formatter = DateFormatter()
formatter.timeStyle = .none
formatter.dateFormat = "MM/dd/YY"
return formatter.string(from: date)
}
}
return ""
}
}

Convert long month name to int

I understand how to use an NSDateFormatter to convert a month component into a long name string, but how does one convert a month name to an int?
I've been using a switch statement to convert, but I'm thinking there must be a simpler way.
For example, I'd like to convert "May" to 5.
You can use DateFormatter custom format "LLLL" to parse your date string (Month). If you are only parsing dates in english you should set the date formatter locale to "en_US_POSIX":
let df = DateFormatter()
df.locale = Locale(identifier: "en_US_POSIX")
df.dateFormat = "LLLL" // if you need 3 letter month just use "LLL"
if let date = df.date(from: "May") {
let month = Calendar.current.component(.month, from: date)
print(month) // 5
}
Thanks Josh. I've converted the Obj-C code and posted it below for future reference:
let calendar = NSCalendar(identifier: NSCalendarIdentifierGregorian)
let components = NSDateComponents()
let formatter = NSDateFormatter()
formatter.dateFormat = "MMMM"
let aDate = formatter.dateFromString("May")
let components1 = calendar!.components(.CalendarUnitMonth , fromDate: aDate!)
let monthInt = components.month
Use MM for the month format. Use stringFromDate to convert your NSDate to a String. Then convert your string to an Int with .toInt()
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "MM"
let monthString = dateFormatter.stringFromDate(NSDate()) // "05"
let monthInt = monthString.toInt() // 5
NSDateFormatter has monthSymbols property. Try:
let formatter = NSDateFormatter()
formatter.calendar = NSCalendar(identifier: NSCalendarIdentifierGregorian)
let monthString = "September"
let month = find(formatter.monthSymbols as! [String], monthString).map { $0 + 1 }
// -> Optional(9)
let monthString2 = "Foobar"
let month2 = find(formatter.monthSymbols as! [String], monthString2).map { $0 + 1 }
// -> nil