Just a question in regards to the times in Swift. I have a timestamp, which I want to validate whether it is 24 hours past the current time at the moment. I tried a few options and this is where my code is at the moment however I am stuck. Any tips will be highly appreciated!
let timeStampsOfUser = timeStampsOfUser.value as Any as! Double
print(timeStampsOfUser)
let timeInMiliSecDate = Date()
let timeInMiliSec = Double (timeInMiliSecDate.timeIntervalSince1970 * 1000)
print(timeInMiliSec)
if timeInMiliSec - timeStampsOfUser > 86400000 {
// how do I get the total count of timestamps which have been more than 24 hours and vice versa?
}
Update: However, how do I found the count? As in, how many of the timestamps are more and less than 24 hours? Thanks
let timeStampsOfUser = timeStampsOfUser.value as Any as! Double
print(timeStampsOfUser)
let timeInMiliSecDate = Date()
let timeInMiliSec = Double (timeInMiliSecDate.timeIntervalSince1970 * 1000)
print(timeInMiliSec)
let timeDone = timeInMiliSec - timeStampsOfUser > 86400000
if timeDone == true {
print("more than 24 hours")
} else {
print("less than 24 hours")
}
86400000 is the wrong approach. Never use 86400-math. Days could have 23 or 25 hours.
Create an extension of Date with 2 functions, an init method which takes a timestamp in milliseconds and a function to check if a given date is in the last 24 hours (actually the difference is less than one day). Calendar can do this with DateComponents pretty reliably.
extension Date {
init(timestampInMilliseconds: Double) {
self.init(timeIntervalSince1970: timestampInMilliseconds / 1000.0)
}
func isDateInLast24Hours() -> Bool {
Calendar.current.dateComponents([.day], from: self, to: .now).day! == 0
}
}
And use it
let timeStamp = 1665584000000.0 // 12. Oct 2022, 16:13
let date = Date(timestampInMilliseconds: timeStamp)
let isInLast24Hours = date.isDateInLast24Hours()
To check multiple timestamps use a loop or map
Related
I coded a SwiftUI App, and the User can choose how much days are left. For example he choose 20 days, it should count in a Circle. For example 10 days are done, the circle should be at 50%.
So I thought I create a Int that is everyday increasing by one. When the user choose 20 days, the Int should start to increase and after 10 days for example the Int is at 10 and because the user choose 20 days, the circle should be at 50%.
Days / Int(that is increasing)
But I dont know how to code the Int that is increasing everyday.
Could anyone help me?
Adding to the suggestion of storing the start date and using today's date to know how many days have passed, you can use this extension
extension Date {
func daysSinceDate(_ fromDate: Date = Date()) -> Int {
let earliest = self < fromDate ? self : fromDate
let latest = (earliest == self) ? fromDate : self
let earlierComponents:DateComponents = Calendar.current.dateComponents([.day], from: earliest)
let laterComponents:DateComponents = Calendar.current.dateComponents([.day], from: latest)
guard
let earlierDay = earlierComponents.day,
let laterDay = laterComponents.day,
laterDay >= earlierDay
else {
return 0
}
return laterDay - earlierDay
}
func dateForDaysFromNow(_ days: Int) -> Date? {
var dayComponent = DateComponents()
dayComponent.day = days
return Calendar.current.date(byAdding: dayComponent, to: self)
}
}
I am getting time from the response in hours, minutes and seconds like "01:32:34" of multiple objects. I have saved it in a custom date object, where i am saving the date value and the string value, there are a large number of records so i am saving it in my local db and upon retrieving i get the date value in the format 1999-12-31 19:01:04 +0000 whereas my string value which i am getting from response as well is 19:01:04. now i would like to add all of these values to return a string e.g 1:15:16, 00:15:02, 00:45:27 should return 2 hours 15 minutes 45 seconds. I have explored Calendar.Components.byAdding but the methods there only let me add one single component, it doesn't receive an array and return Date. Is there any swifty way to achieve this, I want to achieve this via an elegant and proper method, i could think of a few fixes but they don't seem appropriate.
I’m going to assume that “01:32:34” represents an elapsed time of 5,554 seconds, not 1:32am. So, I’d convert it to a TimeInterval, not a Date:
func timeInterval(from string: String) -> TimeInterval? {
let components = string.components(separatedBy: ":").map { Double($0) }
guard
components.count == 3,
let hours = components[0],
let minutes = components[1],
let seconds = components[2]
else { return nil }
return ((hours * 60) + minutes) * 60 + seconds
}
You can chose to store either the original “01:32:34” string or this value, 5,554.0.
Anyway, then adding these numeric time intervals is trivial addition. And to display a resulting TimeInterval, you’d use a DateComponentsFormatter, e.g.
let timeIntervalFormatter: DateComponentsFormatter = {
let formatter = DateComponentsFormatter()
formatter.unitsStyle = .positional
formatter.allowedUnits = [.hour, .minute, .second]
return formatter
}()
func totalElapsed(_ strings: [String]) -> String? {
let total = strings.reduce(TimeInterval.zero) { sum, string in
sum + (timeInterval(from: string) ?? 0)
}
return timeIntervalFormatter.string(from: total)
}
let strings = ["1:15:16", "00:15:02", "00:45:27"]
let result = totalElapsed(strings)
02:15:45
Or if you want more of a (localized) natural language representation, use unitsStyle of .full:
2 hours, 15 minutes, 45 seconds
This approach (using TimeInterval, not Date) has the virtue that it also can represent intervals that exceed 24 hours.
I have 2 dates. I don't care about the date portion, just the time.
How can I compare 2 dates and get the timeinterval between 2 dates?
Should I set the dates to 01-01-2000 and leave the time alone to compare?
Use DateComponents and get the hour, minute, and second of the two dates. At this point you have to assume a full 24 hour, 86400 seconds per day. There's no need to worry about daylight saving or leap seconds or anything since you are doing date independent calculations.
Convert the hours, minutes, and seconds into total seconds of the day for the two dates. Then simply subtract the two totals and you have the difference.
Here's a helpful Date extension:
extension Date {
func secondsSinceMidnight() -> TimeInterval {
let comps = Calendar.current.dateComponents([.hour,.minute,.second], from: self)
return TimeInterval(comps.hour! * 3600 + comps.minute! * 60 + comps.second!)
}
func timeDifference(to date: Date) -> TimeInterval {
return date.secondsSinceMidnight() - self.secondsSinceMidnight()
}
}
Call timeDifference(to:) using your two dates and you will get the difference in seconds ignoring the date portion of the dates.
A negative result means that the to date is closer to midnight.
This is an alternative to rmaddy's solution completely based on DateComponents
extension Date {
func timeComponents() -> DateComponents {
return Calendar.current.dateComponents([.hour,.minute,.second], from: self)
}
func timeDifference(to date: Date) -> Int {
return Calendar.current.dateComponents([.second], from: date.timeComponents(), to: self.timeComponents()).second!
}
}
If you have two dates you can use the method timeIntervalSince(Date).
For instance:
func calculateElapsedTime(from someTime: Date) -> TimeInterval {
let currentTime = Date()
var elapsedTime = currentTime.timeIntervalSince(someTime)
return elapsedTime
}
If you only want to consider the time difference between the two dates, you first have to normalize the date. This can be done in the following cumbersome way:
let currentDate = Date()
let anotherDate = Date(timeInterval: 60, since: currentDate)
let formatter = DateFormatter()
formatter.timeStyle = .short
let currentTime = formatter.string(from: currentDate)
let anotherTime = formatter.string(from: anotherDate)
let currentIntervalTime = formatter.date(from: currentTime)
let anotherIntervalTime = formatter.date(from: anotherTime)
let elapsedTime = anotherIntervalTime?.timeIntervalSince(currentIntervalTime!)
I have an app that presents data that expires every 30 seconds (precisely, at h/m/s 11:30:00, 11:30:30, 11:31:00, etc).
I can get the current time, but I am unsure on how to calculate the time between now and the nearest thirty seconds.
Anything I've found is in Objective-C, and I've been unable to convert it.
Here's what I tried:
func nearestThirtySeconds() -> Date? {
var components = NSCalendar.current.dateComponents([.second], from: self)
let second = components.second ?? 30
components.second = second >= 30 ? 60 - second : -second
return Calendar.current.date(byAdding: components, to: self)
}
But this returns the nearest minute (I think, it always returns a definite minute)
Any ideas?
You can round the seconds to the nearest multiple of 30,
and then add the difference between the rounded and the original
value to the date:
extension Date {
func nearestThirtySeconds() -> Date {
let cal = Calendar.current
let seconds = cal.component(.second, from: self)
// Compute nearest multiple of 30:
let roundedSeconds = lrint(Double(seconds) / 30) * 30
return cal.date(byAdding: .second, value: roundedSeconds - seconds, to: self)!
}
}
That should be good enough to display the rounded time, however it
is not exact: A Date includes also fractional seconds, so
for example "11:30:10.123" would become "11:30:00.123" and not "11:30:00.000". Here is another approach which solves that problem:
extension Date {
func nearestThirtySeconds() -> Date {
let cal = Calendar.current
let startOfMinute = cal.dateInterval(of: .minute, for: self)!.start
var seconds = self.timeIntervalSince(startOfMinute)
seconds = (seconds / 30).rounded() * 30
return startOfMinute.addingTimeInterval(seconds)
}
}
Now seconds is the time interval since the start of the current minute
(including fractional seconds). That interval is rounded to the nearest
multiple of 30 and added to the start of the minute.
I used the answer by Martin R to write a more generic version to round by any time period.
Answer is outdated and only works with time, check gist for the latest version.
https://gist.github.com/casperzandbergenyaacomm/83c6a585073fd7da2e1fbb97c9bcd38a
extension Date {
func rounded(on amount: Int, _ component: Calendar.Component) -> Date {
let cal = Calendar.current
let value = cal.component(component, from: self)
// Compute nearest multiple of amount:
let roundedValue = lrint(Double(value) / Double(amount)) * amount
let newDate = cal.date(byAdding: component, value: roundedValue - value, to: self)!
return newDate.floorAllComponents(before: component)
}
func floorAllComponents(before component: Calendar.Component) -> Date {
// All components to round ordered by length
let components = [Calendar.Component.year, .month, .day, .hour, .minute, .second, .nanosecond]
guard let index = components.index(of: component) else {
fatalError("Wrong component")
}
let cal = Calendar.current
var date = self
components.suffix(from: index + 1).forEach { roundComponent in
let value = cal.component(roundComponent, from: date) * -1
date = cal.date(byAdding: roundComponent, value: value, to: date)!
}
return date
}
}
To round to x minutes you need to also floor the seconds so this also contains the floor method I wrote.
How to use:
let date: Date = Date() // 10:16:34
let roundedDate0 = date.rounded(on: 30, .second) // 10:16:30
let roundedDate1 = date.rounded(on: 15, .minute) // 10:15:00
let roundedDate2 = date.rounded(on: 1, .hour) // 10:00:00
There's a Cocoapod called 'SwiftDate' that is great for date formatting and manipulation that can applied to your Date() instance.
Example of how to use the date rounding method:
let date = Date() // 2018-10-01 23:05:29
date.dateRoundedAt(at: .toFloor5Mins) // 2018-10-01 23:05:00
date.dateRoundedAt(at: .toCeil5Mins) // 2018-10-01 23:10:00
date.dateRoundedAt(at: .toFloorMins(1)) // 2018-10-01 23:05:00
date.dateRoundedAt(at: .toCeilMins(1)) // 2018-10-01 23:06:00
(For reference, check out the documentation at https://cocoapods.org/pods/SwiftDate)
let now = Date()
var timeInterval = now.timeIntervalSinceReferenceDate
timeInterval += 30 - timeInterval.truncatingRemainder(dividingBy: 30)
let rounded = Date(timeIntervalSinceReferenceDate: timeInterval)
print("\(now) rounded to nearest 30 seconds is \(rounded)")
var timeIntervalSince1970: NSTimeInterval {get}
I just hope someone can help me with this.
TimeInterval Since 1970 returns epoch time in seconds, you can change it to return milliseconds multiplying it by 1000.
Date().timeIntervalSince1970 * 1000
if you need it to count from start of today you can use calendar method startOfDay(for: Date)
extension Date {
var startOfDay: Date {
Calendar.current.startOfDay(for: self)
}
var millisecondsSince1970: Int {
.init(timeIntervalSince1970 * 1000)
}
}
let millisecondsSince1970 = Date().millisecondsSince1970 // 1604931753291
let startOfDayMsSince1970 = Date().startOfDay.millisecondsSince1970 // 1604890800000