Date comparison or timezone not set properly - ios

I'm trying to do a simple comparison of dates with the intent of moving to another array index based on the day.
Though vastly more efficient than the code I was using, the following (Unable to parse a date) doesn't preserve the timezone offset:
let noaaDate = "2014-08-22T15:00:00-04:00"
let format="yyyy-MM-dd'T'HH:mm:ssZ"
var dateFmt = NSDateFormatter()
dateFmt.dateFormat = format
let newreadableDate = dateFmt.dateFromString(noaaDate)
println(newreadableDate)
Output:
Optional(2014-08-22 19:00:00 +0000)
When I add the following:
dateFmt.timeZone = NSTimeZone.localTimeZone() // I've even tried defaultTimeZone
the output is the same. Where this seems to become an issue is later on when I'm doing the following:
// FYI: parseNOAADateTime is that code above
var earliestTimeNS = parseNOAADateTime(earliestTime!)
let calendar = NSCalendar.currentCalendar()
let components = calendar.components(.CalendarUnitDay, fromDate: earliestTimeNS)
let dayZero = components.day
// stuff, like starting a loop
let tempDateTimeString = "2014-08-31T01:00:00-04:00"
let thisDateTime = parseNOAADateTime(tempDateTimeString!)
let tempDateTimeComponents = calendar.components(.CalendarUnitDay, fromDate: thisDateTime)
let forecastIndex = tempDateTimeComponents.day - dayZero
Now, forecastIndex SHOULD be 6 because tempDateTimeComponents.day SHOULD be 31. However, they're 5 and 30, respectively, meaning four hour's worth of data is ending up with the previous day's data.
Where am I messing up?
Thanks

Related

How to calculate time (minutes) between two dates in swift?

What do we got: Date+time (format yyyy-mm-dd hh:mm a)
What are we looking for: Time difference in minutes
What operation: NewDate - OldDate
So, I wonder how I could accomplish above goal? I would like to format the date and time to US, regardless from which locale the user has. How can I do that?
Then I will save the 'oldTime' into UserDefaults, and use it for later calculation. The goal is to put the user on delay for 5 minutes and the calculations will be performed to determine if user should be on delay or not.
Just make a function that takes two dates and compares them like this.
import UIKit
func minutesBetweenDates(_ oldDate: Date, _ newDate: Date) -> CGFloat {
//get both times sinces refrenced date and divide by 60 to get minutes
let newDateMinutes = newDate.timeIntervalSinceReferenceDate/60
let oldDateMinutes = oldDate.timeIntervalSinceReferenceDate/60
//then return the difference
return CGFloat(newDateMinutes - oldDateMinutes)
}
//Usage:
let myDateFormatter = DateFormatter()
myDateFormatter.dateFormat = "yyyy-MM-dd HH:mm"
//You'll need both dates to compare, you can get them by just storing a Date object when you first start the timer.
//Then when you need to check it, compare it to Date()
let oldDate: Date = myDateFormatter.date(from: String("2019-06-22 11:25"))
func validateRefresh() {
//do the comparison between the old date and the now date like this.
if minutesBetweenDates(oldDate, Date()) > 5 {
//Do whatever
}
}
You can, of course, change the .dateFormat value on the date formatter to be whatever format you'd like. A great website for finding the right format is: https://nsdateformatter.com/.
You say:
I would like to format the date and time to US, regardless from which locale the user has. How can I do that?
Specify a Locale of en_US_POSIX:
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd hh:mm a"
formatter.locale = Locale(identifier: "en_US_POSIX")
The locale is not the only question.
There’s also a timezone question. For example, you're driving out of Chicago and go from Central to Eastern timezones; do you really want to consider that one hour has passed?
Do you really want to discard seconds? If you do that, the 59 seconds between going from 8:00:00pm to 8:00:59pm will be considered “zero minutes” but the one second between 8:00:59pm and 8:01:00pm will be considered “one minute”.
Frankly, if I wanted to save a locale and timezone invariant date string, I’d suggest using ISO8601DateFormatter.
Then I will save the 'oldTime' into UserDefaults, and use it for later calculation.
If that’s why you’re using this DateFormatter, I’d suggest saving the Date object directly.
UserDefaults.standard.set(oldTime, forKey: "oldTime")
And to retrieve it:
if let oldTime = UserDefaults.standard.object(forKey: "oldTime") as? Date {
...
}
In terms of calculating the number of minutes between two Date objects
let minutes = Calendar.current
.dateComponents([.minute], from: date1, to: date2)
.minute
If you want the number of seconds, you can also use timeIntervalSince:
let seconds = date2.timeIntervalSince(date1)
And if you wanted to show the amount of elapsed time as a nice localized string:
let intervalFormatter = DateComponentsFormatter()
intervalFormatter.allowedUnits = [.minute, .second]
intervalFormatter.unitsStyle = .full
let string = intervalFormatter.string(from: date1, to: date2)
I'm not convinced that your question is the best way to go about accomplishing your aim, but the code below will work.
let dateFormatterNow = DateFormatter()
dateFormatterNow.dateFormat = "yyyy-MM-dd hh:mm a"
dateFormatterNow.timeZone = TimeZone(abbreviation: "EST")
let oldDateString = "2019-06-23 12:44 p"
let oldDate = dateFormatterNow.date(from: oldDateString)
let newDateString = "2019-06-23 12:54 p"
let newDate = dateFormatterNow.date(from: newDateString)
if let oldDate = oldDate, let newDate = newDate {
let diffInMins = Calendar.current.dateComponents([.minute], from: oldDate, to: newDate).minute
print(diffInMins)
}

Time Duration From Labels

I've looked at all the Code on here that has to do with getting time duration. All I need to do is simply take a time that is in a label in this format hr:m:s like 20:23:04 for example. I need to take the times from currentTime.StringValue and the time from oldTime.StringValue and then have it show the duration of hours in durationOfTime.StringValue.
So for example say currentTime = 11:00:04 and oldTime = 9:00:04 then I want durationOfTime = 2hr's.
That's it right now I have a code that get's the time and stores it in the format above. However I run into all kinds of problems trying different codes on here that have to do with Time Duration.
Use 2 formatters: a DateFormatter to convert the strings to Date objects and a DateComponentFormatter to display the duration between the 2 Dates:
let currentTimeStr = "11:00:04"
let oldTimeStr = "9:00:04"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "H:mm:ss"
let dateComponentFormatter = DateComponentsFormatter()
dateComponentFormatter.allowedUnits = [.hour, .minute]
dateComponentFormatter.unitsStyle = .short
if let currentTime = dateFormatter.date(from: currentTimeStr),
let oldTime = dateFormatter.date(from: oldTimeStr),
let durationStr = dateComponentFormatter.string(from: oldTime, to: currentTime)
{
print(durationStr) // 2 hrs
}
Hope this is helpful. Edited maddy's suggestion.
let currentTime = "11:00:04"
let oldTime = "9:00:04"
let currentTimeComponents = currentTime.components(separatedBy: ":")
let oldTimeComponents = oldTime.components(separatedBy: ":")
let hrsDifference = Int(currentTimeComponents[0])! - Int(oldTimeComponents[0])!
let minutesDifference = Int(currentTimeComponents[1])! - Int(oldTimeComponents[1])!
let secondsDifference = Int(currentTimeComponents[2])! - Int(oldTimeComponents[2])!
print("hrsDifference = ",hrsDifference)
print("minutesDifference = ",minutesDifference)
print("secondsDifference = ",secondsDifference)

How to create dateComponents from Date stored in CoreData

I am trying to create dateComponents from Date stored in CoreData from UIDatePicker. However, I am not able to make it. I am first converting Date which is stored in editnotes?.sSelectedDate into dateComponents and then using the dateComponents for triggering my notifications.
Here is what I am doing:
var date = Date()
if let editnote = editnotes
{
date = editnote.sSelectedDate
}
else
{
print("nil")
}
let calendar = NSCalendar.current
let unitFlags = Set<Calendar.Component>([.day, .month, .year, .hour, .minute])
let anchorComponents = calendar.dateComponents(unitFlags, from: date)
var dateInfo1 = DateComponents()
dateInfo1.day = anchorComponents.day
dateInfo1.month = anchorComponents.month
dateInfo1.hour = anchorComponents.hour
dateInfo1.minute = anchorComponents.minute
dateInfo1.year = anchorComponents.year
let trigger = UNCalendarNotificationTrigger(dateMatching:dateInfo1, repeats: false)
I am doing this:
if let editnote = editnotes
{
date = editnote.sSelectedDate
}
else
{
print("nil")
}
to unwrap the optional but it's not working still. Continue reading!
I know I can use anchorComponents but that wasn't working so I copied those into a new DataComponents instance.
I am trying to print the what is stored indateInfo1.hour and I get
Optional(2)
I reckon this is the reason why dateComponents is not working for triggering notifications at scheduled time.
Help will be appreciated?
Explicit cast it like this
let anchorComponents = calendar.dateComponents(unitFlags, from: date) as! DateComponents
You'r using anchorComponents.days / .hours / .days / .minutes it's all optional. Instead, I'd used initialiser for DateComponents where you explicitly set your properties you needed. But I think you'r just doing something wrong and that's why notification not working and the reason is not date. You can simply check it by setting from date to current date plus few seconds to see whether you'll get notification or not

How to query realm db to obtain relevant data for each day based on stored timestamp?

This is how my model look like
class Run: Object {
dynamic var duration:Double = 0
dynamic var elevation:Double = 0.0
dynamic var distance:Double = 0.0
dynamic var filePathString:String = ""
dynamic var exported:Bool = false
dynamic var timestamp:Date = Date()
let locations = List<Location>()
}
List of runs is presented in tableView, where each header denotes the exact date (for instance 10/10/2016).
Is it possible to construct realm query to obtain relevant runs for each day?
To be clear, I want to achieve something like this
let isSameDay = Calendar.current.isDate(date1, inSameDayAs: date2)
using Realm queries.
Realm lets you perform queries using Apple's NSPredicate formatting. In this particular case, it should be able to use the BETWEEN syntax to check which dates are within a specific slice of time, specifically between the timestamp representing the start of a day, as well as the end.
let calendar = NSCalendar(identifier: NSCalendarIdentifierGregorian)
let components = NSDateComponents()
components.year = 2016
components.month = 10
components.day = 10
components.hour = 0
components.minute = 0
components.second = 0
// Get the start date
let startDate = calendar?.dateFromComponents(components)
// Get the end date
components.day = 11
let endDate = calendar?.dateFromComponents(components)
// Query for the runs between these two dates
let runDates = realm.objects(Run.self).filter("timestamp BETWEEN {%#, %#}", startDate, endDate)
(NSDateComponents code stolen from http://nshipster.com/nsdatecomponents/)

Calculating date and time based on user's timezone [duplicate]

This question already has answers here:
iOS: Convert UTC NSDate to local Timezone
(15 answers)
Closed 6 years ago.
I have a requirement in which I have a local DB full of dates from a particular timezone and I want to convert this date from that particular timezone to user's local timezone. The way I've implemented is that first I am always converting the DB date to UTC by adding the hours difference and then converting it to user local time zone by taking the time interval using
NSTimeInterval(NSTimeZone.localTimeZone().secondsFromGMT
and adding it to the UTC date. I would like to know that is the approach fine because it worked till now on my limited testing. Also will it account for countries which has Day light saving currently active.
The complete code :
func calculateDate(model:EventModel) -> NSDate
{
let date = model.Date
let startTime = model.StartTime
let arrayForTime = startTime?.componentsSeparatedByString(":")
let arrayForDates = date?.componentsSeparatedByString("-")
let calender = NSCalendar(identifier:NSCalendarIdentifierGregorian)
let year = Int(arrayForDates![2])
let month = Int(arrayForDates![1])
let day = Int(arrayForDates![0])
let hour = Int(arrayForTime![0])! + 3 //UTC - 3 the local time
let minutes = Int(arrayForTime![1])
let dateComponents = NSDateComponents()
dateComponents.day = day!
dateComponents.month = month!
dateComponents.year = year!
dateComponents.hour = hour
dateComponents.minute = minutes!
dateComponents.second = 0
dateComponents.timeZone = NSTimeZone(name: "UTC")
let UTCDate = calender?.dateFromComponents(dateComponents)
let dateLocal = self.getLocalDate(UTCDate!)
return dateLocal
}
func getLocalDate(utcDate:NSDate) -> NSDate
{
let timeInterval = NSTimeInterval(NSTimeZone.localTimeZone().secondsFromGMT)
let localdate = utcDate.dateByAddingTimeInterval(timeInterval)
return localdate
}
Previously I was using this but it was not returning the correct local date for Day light saving countries.
func getLocalDate(utcDate:NSDate) -> NSDate
{
let timeInterval = NSTimeInterval(NSTimeZone.localTimeZone().secondsFromGMT)
// let timeZoneObj = NSTimeZone.localTimeZone()
let localdate = utcDate.dateByAddingTimeInterval(timeInterval)
// let isDayLightSavingOn = timeZoneObj.isDaylightSavingTimeForDate(localdate)
// if(isDayLightSavingOn == true)
// {
// let dayLightTimeInterval = timeZoneObj.daylightSavingTimeOffsetForDate(localdate)
// timeInterval -= dayLightTimeInterval
// }
// localdate = utcDate.dateByAddingTimeInterval(timeInterval)
return localdate
}
Thanks in advance. Cheers !
You don't "convert" the NSDate to a timezone. You simply create a string representation of the NSDate in the user's time zone using a NSDateFormatter. The timeZone of the NSDateFormatter defaults to the user's own timezone, so no adjustments are necessary when displaying it in the user's local timezone. For example:
let date = ... // let's imagine it was "2016-05-18 00:03:34 +0000"
let formatter = NSDateFormatter()
formatter.dateStyle = .LongStyle
formatter.timeStyle = .LongStyle
let userDateString = formatter.stringFromDate(date)
If the user was in GMT/UTC-7 timezone, for example, that would result in:
"May 17, 2016 at 5:03:34 PM PDT"
Clearly, change the dateStyle and timeStyle to format it however best for your user interface. But don't do any adjustments of NSDate objects at all, but rather just build a string representation in the user's own timezone.

Resources