How to calculate the correct time interval between two times that span two days in swift? - swift

I'm trying to get the correct time interval between two times that span two days (Overnight). Here is my code successfully printing out the difference between two times - however for my use case I need the ability to span overnight, how might I do this?
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "HH:mm"
//This time represents (23:00, Aug 07) for example
let date1 = dateFormatter.date(from: "23:00")!
//This time represents (06:00, Aug 08) for example
let date2 = dateFormatter.date(from: "06:00")!
let elapsedTime = date2.timeIntervalSince(date1)
print(abs(elapsedTime)/60/60)
//prints 17.0
My desired result is a print out of 7, as that is the amount of hours between 23:00, Aug 7 and 06:00, Aug 8 - My current code is correctly showing me the interval between those two times (as if they were from the same day) but I am trying to work out how to account for when those times overlap two days. Any help would be much appreciated.
UPDATE:
To give a more complete picture I have an object that has a start and and end date represented by a string:
Activity(startTime: "23:00", endTime: "06:00")
I use some functions to turn those strings into dates:
func startDate(startTime: String) -> Date {
let currentDate = Date().string(format: "dd-MM-yyyy")
let myStartingDate = "\(currentDate) \(startTime)"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd-MM-yyyy HH:mm"
let startDate = dateFormatter.date(from: myStartingDate)
return startDate!
}
func endDate(endTime: String) -> Date {
let currentDate = Date().string(format: "dd-MM-yyyy")
let myEndingDate = "\(currentDate) \(endTime)"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd-MM-yyyy HH:mm"
let endDate = dateFormatter.date(from: myEndingDate)
return endDate!
}
So my more complete workings look more like this:
func calculateTimeInterval(activity: Activity) {
let startHourDate = self.startDate(startTime: activity.startTime)
let endHourDate = self.endDate(endTime: activity.endTime)
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "HH:mm"
//This time represents (23:00, Aug 07) for example
let date1 = startHourDate!
//This time represents (06:00, Aug 08) for example
let date2 = endHourDate!
let elapsedTime = date2.timeIntervalSince(date1)
print(abs(elapsedTime)/60/60)
}
//prints 17.0

Without a date part the only way to determine if the end time is past midnight is if the end time is less than the start time. If so your code can be changed to
var elapsedTime = date2.timeIntervalSince(date1)
if elapsedTime < 0 {
let date3 = date2 + 60 * 60 * 24
elapsedTime = date3.timeIntervalSince(date1)
}
print(elapsedTime/60/60)

You can write an Extension to Date like this:
extension Date {
func hours(from date: Date) -> Int {
return Calendar.current.dateComponents([.hour], from: date).hour ?? 0
}
}
And just use it on any Date directly. This way you don't need DateFormatter at all. Hope this helps!

Related

How do I compare two Date objects by hours, minutes and seconds; ignoring the dates? [duplicate]

I have two Date Objects:
2017-01-13 11:40:17 +0000
2016-03-15 10:22:14 +0000
I need to compare just the time of these values and ignore the date
example: 12:00am and 12:01am, 12:01 is later so (12:01am > 12:00am) == true
This is the route I took in the end, which makes it easy to compare just the time of a Date in swift
New Object Time:
class Time: Comparable, Equatable {
init(_ date: Date) {
//get the current calender
let calendar = Calendar.current
//get just the minute and the hour of the day passed to it
let dateComponents = calendar.dateComponents([.hour, .minute], from: date)
//calculate the seconds since the beggining of the day for comparisions
let dateSeconds = dateComponents.hour! * 3600 + dateComponents.minute! * 60
//set the varibles
secondsSinceBeginningOfDay = dateSeconds
hour = dateComponents.hour!
minute = dateComponents.minute!
}
init(_ hour: Int, _ minute: Int) {
//calculate the seconds since the beggining of the day for comparisions
let dateSeconds = hour * 3600 + minute * 60
//set the varibles
secondsSinceBeginningOfDay = dateSeconds
self.hour = hour
self.minute = minute
}
var hour : Int
var minute: Int
var date: Date {
//get the current calender
let calendar = Calendar.current
//create a new date components.
var dateComponents = DateComponents()
dateComponents.hour = hour
dateComponents.minute = minute
return calendar.date(byAdding: dateComponents, to: Date())!
}
/// the number or seconds since the beggining of the day, this is used for comparisions
private let secondsSinceBeginningOfDay: Int
//comparisions so you can compare times
static func == (lhs: Time, rhs: Time) -> Bool {
return lhs.secondsSinceBeginningOfDay == rhs.secondsSinceBeginningOfDay
}
static func < (lhs: Time, rhs: Time) -> Bool {
return lhs.secondsSinceBeginningOfDay < rhs.secondsSinceBeginningOfDay
}
static func <= (lhs: Time, rhs: Time) -> Bool {
return lhs.secondsSinceBeginningOfDay <= rhs.secondsSinceBeginningOfDay
}
static func >= (lhs: Time, rhs: Time) -> Bool {
return lhs.secondsSinceBeginningOfDay >= rhs.secondsSinceBeginningOfDay
}
static func > (lhs: Time, rhs: Time) -> Bool {
return lhs.secondsSinceBeginningOfDay > rhs.secondsSinceBeginningOfDay
}
}
Date Extension for easy access:
//Adds ability to just get the time from a date:
extension Date {
var time: Time {
return Time(self)
}
}
Example:
let firstDate = Date()
let secondDate = firstDate
//Will return true
let timeEqual = firstDate.time == secondDate.time
Much simpler than accepted answer:
SWIFT 4
// date1 and date2 are the dates you want to compare
let calendar = Calendar.current
var newDate = Date(TimeIntervalSinceReferenceDate: 0) // Initiates date at 2001-01-01 00:00:00 +0000
var newDate1 = Date(TimeIntervalSinceReferenceDate: 0) // Same as above
// Recieving the components from the dates you want to compare
let newDateComponents = calendar.dateComponents([.hour, .minute], from: date1)!
let newDate1Components = calendar.dateComponents([.hour, .minute], from: date2)!
// Adding those components
newDate = calendar.date(byAdding: newDateComponents, to: newDate)
newDate1 = calendar.date(byAdding: newDate1Components, to: newDate1)
My approach would be to use Calendar to make them Date objects with the same day and then comparing them using for example timeIntervalSinceReferenceDate.
Another, cleaner (but most likely with more lines of resulting code) would be to create extension for Date called secondsFromBeginningOfTheDay() -> TimeInterval and then comparing the resulting double values.
Example based on the second approach:
// Creating Date from String
let textDate1 = "2017-01-13T12:21:00-0800"
let textDate2 = "2016-03-06T20:12:05-0900"
let dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZ"
formatter.timeZone = TimeZone.current
return formatter
} ()
// Dates used for the comparison
let date1 = dateFormatter.date(from: textDate1)
let date2 = dateFormatter.date(from: textDate2)
// Date extensions
extension Date {
func secondsFromBeginningOfTheDay() -> TimeInterval {
let calendar = Calendar.current
// omitting fractions of seconds for simplicity
let dateComponents = calendar.dateComponents([.hour, .minute, .second], from: self)
let dateSeconds = dateComponents.hour! * 3600 + dateComponents.minute! * 60 + dateComponents.second!
return TimeInterval(dateSeconds)
}
// Interval between two times of the day in seconds
func timeOfDayInterval(toDate date: Date) -> TimeInterval {
let date1Seconds = self.secondsFromBeginningOfTheDay()
let date2Seconds = date.secondsFromBeginningOfTheDay()
return date2Seconds - date1Seconds
}
}
if let date1 = date1, let date2 = date2 {
let diff = date1.timeOfDayInterval(toDate: date2)
// as text
if diff > 0 {
print("Time of the day in the second date is greater")
} else if diff < 0 {
print("Time of the day in the first date is greater")
} else {
print("Times of the day in both dates are equal")
}
// show interval as as H M S
let timeIntervalFormatter = DateComponentsFormatter()
timeIntervalFormatter.unitsStyle = .abbreviated
timeIntervalFormatter.allowedUnits = [.hour, .minute, .second]
print("Difference between times since midnight is", timeIntervalFormatter.string(from: diff) ?? "n/a")
}
// Output:
// Time of the day in the second date is greater
// Difference between times since midnight is 8h 51m 5s
My solution for comparing two times of day while ignoring the date:
let date1 = some time as a date
let date2 = some other time as a date
let time1 = 60*Calendar.current.component(.hour, from: date1!) + Calendar.current.component(.minute, from: date1!)
let time2 = 60*Calendar.current.component(.hour, from: date2!) + Calendar.current.component(.minute, from: date2!)
Now you can compare the integers time1 and time2 without regard to the day. You could add the seconds/60 if you need more precision.
This code works, check it easily in playground
let s1 = "22:31"
let s2 = "14:31"
let f = DateFormatter()
f.dateFormat = "HH:mm"
f.date(from: s1)! //"Jan 1, 2000 at 10:31 PM"
f.date(from: s2)! //"Jan 1, 2000 at 2:31 PM"
f.date(from: s1)! > f.date(from: s2)! // true
There's no standard type for a time-of-day. A reasonable type to start with is just a tuple:
typealias TimeOfDay = (hour: Int, minute: Int, second: Int)
To create these TimeOfDay values, you'll need a Calendar. By default, a Calendar uses the device's system-wide time zone. If you don't want that, set the Calendar's time zone explicitly. Example:
var calendar = Calendar.autoupdatingCurrent
calendar.timeZone = TimeZone(abbreviation: "UTC")!
Now you can use a DateFormatter to convert strings to Dates (if necessary), and then use calendar to extract the time-of-day components from the Dates:
let strings: [String] = ["2017-01-13 11:40:17 +0000", "2016-03-15 10:22:14 +0000"]
let parser = DateFormatter()
parser.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
let timesOfDay: [TimeOfDay] = strings.map({ (string) -> TimeOfDay in
let components = calendar.dateComponents([.hour, .minute, .second], from: parser.date(from: string)!)
return (hour: components.hour!, minute: components.minute!, second: components.second!)
})
Swift.print(timesOfDay)
// Output: [(11, 40, 17), (10, 22, 14)]
Finally, you can compare these TimeOfDay values. Swift comes with standard comparison operators for tuples whose elements are Comparable, so this TimeOfDay type qualifies. You can just say this:
if timesOfDay[0] < timesOfDay[1] {
Swift.print("date[0] comes first")
} else if timesOfDay[0] == timesOfDay[1] {
Swift.print("times are equal")
} else {
Swift.print("date[1] comes first")
}
Let say we got two dates in string format:
// "2017-01-13 11:40:17 +0000"
// "2016-03-15 10:22:14 +0000"
We need to convert this strings to Date format, we create DateFormatter() and set the format ("yyyy-MM-dd' 'HH:mm:ssZ") it gonna convert
//date formatter converts string to date in our case
let firstDateFormatter = DateFormatter()
firstDateFormatter.dateFormat = "yyyy-MM-dd' 'HH:mm:ssZ"
Now we can get our date from string to Date format
//convert string to dates
if let date1 = firstDateFormatter.date(from: "2017-01-13 09:40:17 +0000"),
let date2 = firstDateFormatter.date(from: "2016-03-15 10:22:14 +0000") {
What we want is to compare only Hours and Minutes. So change dateformat to "HH:mm"
//we ve got the dates, now switch dateformat for other job
firstDateFormatter.dateFormat = "HH:mm"
Now get the string value from our date, that only contain "HH:mm"
// convert date to string ( part of string we want to compare )
let HHmmDate1 = firstDateFormatter.string(from: date1) //"17:40"
let HHmmDate2 = firstDateFormatter.string(from: date2) //"18:22"
Final step is to get date from our "HH:mm" values, let say we ask DateFormatter to give us a date, based on time only, in our case "17:40" and "18:22". DateFormatter will put some values for dates, so we get Jan 1, 2000 automatically for both dates, but it will get the time we provide.
//produce "default" dates with desired HH:mm
//default means same date, but time is different
let HH1 = firstDateFormatter.date(from: HHmmDate1) //"Jan 1, 2000 at 5:40 PM"
let HH2 = firstDateFormatter.date(from: HHmmDate2) //"Jan 1, 2000 at 6:22 PM"
Now we could easily compare dates
//compare
HH1! > HH2!
}
There are many options to compare dates with Calendar also
This is very simple in Swift if you use Swifter Swift
date1.day = 1
date1.month = 1
date1.year = 2000
date2.day = 1
date2.month = 1
date2.year = 2000
now you can use >,<,== operators on date1 and date2 to compare just the time components.
edit - you could do this your self by extending the date class, for example swifter-swift does the bellow for the day component.
public var day: Int {
get {
return Calendar.current.component(.day, from: self)
}
set {
let allowedRange = Calendar.current.range(of: .day, in: .month, for: self)!
guard allowedRange.contains(newValue) else { return }
let currentDay = Calendar.current.component(.day, from: self)
let daysToAdd = newValue - currentDay
if let date = Calendar.current.date(byAdding: .day, value: daysToAdd, to: self) {
self = date
}
}
}

Swift - Find Difference Between Upcoming Time and Current Time

I have a date/time returning from an API that is formatted in RFC 3339. RFC3399 looks like the following: "2021-07-24T22:36:39-04:00"
To be even more clear, it can be generated directly in swift doing something like the following:
let RFC3339DateFormatter = DateFormatter()
RFC3339DateFormatter.locale = Locale(identifier: "en_US_POSIX")
RFC3339DateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
RFC3339DateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
/* 39 minutes and 57 seconds after the 16th hour of December 19th, 1996 with an offset of -08:00 from UTC (Pacific Standard Time) */
let string = "1996-12-19T16:39:57-08:00"
let date = RFC3339DateFormatter.date(from: string)
My question is, how can I find the difference between times stored in RFC 3339 format in String variables.
For example, I have one variable titled currentTime that returns the current date/time in RFC 3339 format, and I have data from my API that returns a future time in RFC 3339 format. How can I subtract the time returned in each of these to determine the difference between the two?
Also, the date returned is not a concern to me. Only need to find the difference in time.
once you have your dates from the strings, you coud do something like this using component:
EDIT, using Alexander suggestion:
struct ContentView: View {
#State var timediff = ""
var body: some View {
Text(timediff)
.onAppear {
let RFC3339DateFormatter = DateFormatter()
RFC3339DateFormatter.locale = Locale(identifier: "en_US_POSIX")
RFC3339DateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
RFC3339DateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
let string1 = "1996-12-19T16:39:57-08:00"
let date1 = RFC3339DateFormatter.date(from: string1)
let string2 = "1996-12-19T13:19:27-08:00"
let date2 = RFC3339DateFormatter.date(from: string2)
if let d1 = date1, let d2 = date2 {
let result = Calendar.current.dateComponents([.hour, .minute], from: d1, to: d2)
timediff = result.description
}
}
}

Date format from url (JSON)

How would I be able to take the date format from a URL and turn It into 2 separate date values in SwiftUI. The format from JSON is 2019-11-06 18:30:00 and I'm trying to get it to show as Dec 5 and would also like it to separate the time and show 8:00PM, is this possible?
This is the code that references the start time:
let startTime: String
var startTime: String {
return self.post.startTime
}
Let's step around the fact that 2019-11-06 18:30:00 can't be represented as Dec 5 and 8:00PM and focus on the work flow you'd need.
The basic idea is to:
Convert the String to a Date, via a DateFormatter
Use a custom DateFormatter to format the Date to the required "date" value
Use a custom DateFormatter to format the Date to the required "time" value
This might look something like...
let startTime = "2019-11-06 18:30:00"
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
if let date = formatter.date(from: startTime) {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MMM d"
let dateString = dateFormatter.string(from: date)
let timeFormatter = DateFormatter()
timeFormatter.dateFormat = "h:ma"
let timeString = timeFormatter.string(from: date)
} else {
print("Bad date/format")
}
In my testing, this outputs Nov 6 and 6:30PM
you can pass your string date to date with this function
func stringToDate(date: String, format: String) -> Date
{
let date2 = date.count == 0 ? getCurrentDate(format: "dd-MM-yyyy") : date
let dateFormatter = DateFormatter()
dateFormatter.timeZone = TimeZone.init(identifier: "América/Mexico_City")
dateFormatter.dateFormat = format
let dateDate = dateFormatter.date(from: date2)
return dateDate!
}
func getCurrentDate(format: String) -> String
{
let formD = DateFormatter()
formD.dateFormat = format
let str = formD.string(from:Date())
return str
}
let dateA = stringToDate(date: "2019-11-06 18:30:00", format: "yyyy-MM-dd HH:mm:ss")
if dateA < Date() //Date() always will be the current date, including the time
{
print("dateA is older")
}
else
{
print("dateA in newer")
}
play with the format examples formats

Swift unix timestamp too short [duplicate]

I am taking the current time, in UTC, and putting it in nanaoseconds and then I need to take the nanoseconds and go back to a date in local time.
I am able to do get the time to nanoseconds and then back to a date string but the time gets convoluted when I go from a string to date.
//Date to milliseconds
func currentTimeInMiliseconds() -> Int! {
let currentDate = NSDate()
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = format
dateFormatter.timeZone = NSTimeZone(name: "UTC") as TimeZone!
let date = dateFormatter.date(from: dateFormatter.string(from: currentDate as Date))
let nowDouble = date!.timeIntervalSince1970
return Int(nowDouble*1000)
}
//Milliseconds to date
extension Int {
func dateFromMilliseconds(format:String) -> Date {
let date : NSDate! = NSDate(timeIntervalSince1970:Double(self) / 1000.0)
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = format
dateFormatter.timeZone = TimeZone.current
let timeStamp = dateFormatter.string(from: date as Date)
let formatter = DateFormatter()
formatter.dateFormat = format
return ( formatter.date( from: timeStamp ) )!
}
}
The timestamp is correct but the date returned isn't.
I don't understand why you're doing anything with strings...
extension Date {
var millisecondsSince1970:Int64 {
Int64((self.timeIntervalSince1970 * 1000.0).rounded())
}
init(milliseconds:Int64) {
self = Date(timeIntervalSince1970: TimeInterval(milliseconds) / 1000)
}
}
Date().millisecondsSince1970 // 1476889390939
Date(milliseconds: 0) // "Dec 31, 1969, 4:00 PM" (PDT variant of 1970 UTC)
As #Travis Solution works but in some cases
var millisecondsSince1970:Int WILL CAUSE CRASH APPLICATION ,
with error
Double value cannot be converted to Int because the result would be greater than Int.max if it occurs Please update your answer with Int64
Here is Updated Answer
extension Date {
var millisecondsSince1970:Int64 {
return Int64((self.timeIntervalSince1970 * 1000.0).rounded())
//RESOLVED CRASH HERE
}
init(milliseconds:Int) {
self = Date(timeIntervalSince1970: TimeInterval(milliseconds / 1000))
}
}
About Int definitions.
On 32-bit platforms, Int is the same size as Int32, and on 64-bit platforms, Int is the same size as Int64.
Generally, I encounter this problem in iPhone 5, which runs in 32-bit env. New devices run 64-bit env now. Their Int will be Int64.
Hope it is helpful to someone who also has same problem
#Travis solution is right, but it loses milliseconds when a Date is generated. I have added a line to include the milliseconds into the date:
If you don't need this precision, use the Travis solution because it will be faster.
extension Date {
func toMillis() -> Int64! {
return Int64(self.timeIntervalSince1970 * 1000)
}
init(millis: Int64) {
self = Date(timeIntervalSince1970: TimeInterval(millis / 1000))
self.addTimeInterval(TimeInterval(Double(millis % 1000) / 1000 ))
}
}
//Date to milliseconds
func currentTimeInMiliseconds() -> Int {
let currentDate = Date()
let since1970 = currentDate.timeIntervalSince1970
return Int(since1970 * 1000)
}
//Milliseconds to date
extension Int {
func dateFromMilliseconds() -> Date {
return Date(timeIntervalSince1970: TimeInterval(self)/1000)
}
}
I removed seemingly useless conversion via string and all those random !.
let dateTimeStamp = NSDate(timeIntervalSince1970:Double(currentTimeInMiliseconds())/1000) //UTC time //YOUR currentTimeInMiliseconds METHOD
let dateFormatter = NSDateFormatter()
dateFormatter.timeZone = NSTimeZone.localTimeZone()
dateFormatter.dateFormat = "yyyy-MM-dd"
dateFormatter.dateStyle = NSDateFormatterStyle.FullStyle
dateFormatter.timeStyle = NSDateFormatterStyle.ShortStyle
let strDateSelect = dateFormatter.stringFromDate(dateTimeStamp)
print("Local Time", strDateSelect) //Local time
let dateFormatter2 = NSDateFormatter()
dateFormatter2.timeZone = NSTimeZone(name: "UTC") as NSTimeZone!
dateFormatter2.dateFormat = "yyyy-MM-dd"
let date3 = dateFormatter.dateFromString(strDateSelect)
print("DATE",date3)
#Prashant Tukadiya answer works. But if you want to save the value in UserDefaults and then compare it to other date you get yout int64 truncated so it can cause problems. I found a solution.
Swift 4:
You can save int64 as string in UserDefaults:
let value: String(Date().millisecondsSince1970)
let stringValue = String(value)
UserDefaults.standard.set(stringValue, forKey: "int64String")
Like that you avoid Int truncation.
And then you can recover the original value:
let int64String = UserDefaults.standard.string(forKey: "int64String")
let originalValue = Int64(int64String!)
This allow you to compare it with other date values:
let currentTime = Date().millisecondsSince1970
let int64String = UserDefaults.standard.string(forKey: "int64String")
let originalValue = Int64(int64String!) ?? 0
if currentTime < originalValue {
return false
} else {
return true
}
Hope this helps someone who has same problem
Heres a simple solution in Swift 5/iOS 13.
extension Date {
func toMilliseconds() -> Int64 {
Int64(self.timeIntervalSince1970 * 1000)
}
init(milliseconds:Int) {
self = Date().advanced(by: TimeInterval(integerLiteral: Int64(milliseconds / 1000)))
}
}
This however assumes you have calculated the difference between UTF time and local time and adjusted and accounted for in the milliseconds. For that look to calendar
var cal = Calendar.current
cal.timeZone = TimeZone(abbreviation: "UTC")!
let difference = cal.compare(dateGiven, to: date, toGranularity: .nanosecond)
Simple one-line code to get time token in UInt64
let time = UInt64(Date().timeIntervalSince1970 * 1000)
print(time) <----- prints time in UInt64
Additional tip:
For timestamp with 10 Digit milliseconds since 1970 for API call then
let timeStamp = Date().timeIntervalSince1970
print(timeStamp) <-- prints current time stamp
Watch out if you are going to compare dates after the conversion!
For instance, I got simulator's asset with date as TimeInterval(366144731.9), converted to milliseconds Int64(1344451931900) and back to TimeInterval(366144731.9000001), using
func convertToMilli(timeIntervalSince1970: TimeInterval) -> Int64 {
return Int64(timeIntervalSince1970 * 1000)
}
func convertMilliToDate(milliseconds: Int64) -> Date {
return Date(timeIntervalSince1970: (TimeInterval(milliseconds) / 1000))
}
I tried to fetch the asset by creationDate and it doesn't find the asset, as you could figure, the numbers are not the same.
I tried multiple solutions to reduce double's decimal precision, like round(interval*1000)/1000, use NSDecimalNumber, etc... with no success.
I ended up fetching by interval -1 < creationDate < interval + 1, instead of creationDate == Interval.
There may be a better solution!?
Unless you absolutely have to convert the date to an integer, consider using a Double instead to represent the time interval. After all, this is the type that timeIntervalSince1970 returns. All of the answers that convert to integers loose sub-millisecond precision, but this solution is much more accurate (although you will still lose some precision due to floating-point imprecision).
public extension Date {
/// The interval, in milliseconds, between the date value and
/// 00:00:00 UTC on 1 January 1970.
/// Equivalent to `self.timeIntervalSince1970 * 1000`.
var millisecondsSince1970: Double {
return self.timeIntervalSince1970 * 1000
}
/**
Creates a date value initialized relative to 00:00:00 UTC
on 1 January 1970 by a given number of **milliseconds**.
equivalent to
```
self.init(timeIntervalSince1970: TimeInterval(milliseconds) / 1000)
```
- Parameter millisecondsSince1970: A time interval in milliseconds.
*/
init(millisecondsSince1970 milliseconds: Double) {
self.init(timeIntervalSince1970: TimeInterval(milliseconds) / 1000)
}
}

App Crashed when device time is in 24 hour format

In my App if IPhone device time is in 12 hour formate then date formatter works correctly but if device time is in 24 hour formate then app crashed.
let dateFormatter = NSDateFormatter();
dateFormatter.dateStyle = NSDateFormatterStyle.ShortStyle
dateFormatter.timeStyle = NSDateFormatterStyle.NoStyle;
dateFormatter.dateFormat = "hh:mm a";
var dt1 = dateFormatter.dateFromString(arrSecond.objectAtIndex(n) as! String)
#Rajan Thanks for giving me idea of NSLocale. I set the dateformatter's locale identifier to "en_US_POSIX".
i just add this below line in my code after allocating date formatter. dateformatter.locale = NSLocale(localeIdentifier:"en_US_POSIX")
Thanks frnd for giving this idea
Nandini answer is correct. But the only issue is that if you harcode the locale, the dates are displayed only in english.
In my case I wanted it in french, here is a workaround that worked for me in Swift 3 :
dateformatter.locale = Locale(identifier: NSLocale.current.identifier)
Assuming that you are using Swift 2.x version after seeing your code.
The problem is because your dateFormatter contains a and for the 24 Hour Format time we don't have a
So in order to fix your problem, you have to check whether your device is in 24-Hour format or 12 Hour format
Taking your array's index object in a variable time and keep that as var because we will change that later.
var time = arrSecond.objectAtIndex(n) as! String //this contains 07:45 AM
//Now create your Date Formatter
let dateFormatter = NSDateFormatter();
dateFormatter.dateStyle = NSDateFormatterStyle.ShortStyle
dateFormatter.timeStyle = NSDateFormatterStyle.NoStyle;
//Now check whether your phone is in 12 hour or 24 hour format
let locale = NSLocale.currentLocale()
let formatter : String = NSDateFormatter.dateFormatFromTemplate("j", options:0, locale:locale)!
//we have to change our dateFormatter as per the hour format
if formatter.containsString("a") {
print("phone is in 12 Hour Format")
dateFormatter.dateFormat = "hh:mm a";
} else {
print("phone is in 24 Hour Format")
time = convertTo24HourFormat(time) //time changed to 24 Hour format and AM/PM removed from string
dateFormatter.dateFormat = "HH:mm";
}
let finalDate = dateFormatter.dateFromString(time)
print(finalDate!)
And we need a function to make your time string converted to 24 hour format if your phone is in 24 Hour Format.Function defination of convertTo24HourFormat is
//Example 08:45 PM to 20:45
func convertTo24HourFormat(time:String) -> String {
var formattedTime = time
if formattedTime.containsString("PM") {
var hour = Int(formattedTime.substringToIndex(formattedTime.startIndex.advancedBy(2)))
if hour != 12 {
hour = hour! + 12
formattedTime.removeRange(Range<String.Index>(start: formattedTime.startIndex, end: formattedTime.startIndex.advancedBy(2)))
formattedTime = "\(hour!)\(formattedTime)"
}
} else {
// For AM time
var hour = Int(formattedTime.substringToIndex(formattedTime.startIndex.advancedBy(2)))
//case for 12 AM
if hour == 12 {
formattedTime.removeRange(Range<String.Index>(start: formattedTime.startIndex, end: formattedTime.startIndex.advancedBy(2)))
formattedTime = "00\(formattedTime)"
}
}
formattedTime = formattedTime.substringToIndex(time.startIndex.advancedBy(5))
return formattedTime
}
But converting only the time to date object don't make any sense as it will give a wrong date.
NOTE:-
The convertTo24HourFormat function will only work fine if you send the time in the format hh:mm a. For example 07:45 AM
I had to change my formatter from this:
dateFormatter.dateFormat = "dd MM yyyy hh:mm:ss.SSS"
to this:
dateFormatter.dateFormat = "dd MM yyyy HH:mm:ss.SSS"