TimeZone changed while converting string to Date - ios

When I'm changing date(which is in string form) to Date form,Then timezone change IST to UTC.Because of that I'm not getting notification
My code is :
#IBAction func datePickerDidSelectNewDate(_ sender: UIDatePicker) {
let selectedDate = sender.date
let dateStr = Date().currentTimeZoneDate(date: selectedDate as NSDate)
let date = dateFormatter.date(from: dateStr)
let delegate = UIApplication.shared.delegate as? AppDelegate
delegate?.scheduleNotification(at: date!)
}
In my code, I'm getting selectedDate is in UTC time zone.So I have converted it into currentTimeZone.But when I change String form to Date,means dateStrto date it again convert to UTC timeZone.

What is currentTimeZoneDate? This seems a deep misunderstanding of Date. Dates a never "in a time zone." Dates are an absolute point in time. All observers, no matter where they are, should agree on when a given Date occurs (ignoring relativistic effects).
You should configure UIDatePicker with the time zone you want it to represent. The default is localTimeZone, which always is the current time zone at the point that this action is called (so sender.date has already been adjusted). If you want it to represent some other time zone, change UIDatePicker.timeZone. Don't mess with the Date. Definitely don't convert it to a string and back.
It's unclear what scheduleNotification(at:) does, or what the final goal is. NSUserNotification by default will adjust all of its delivery dates if the time zone changes. If you don't want this (if you want to maintain the precise instant that the user selected, rather than the nominal time they selected), then you should set deliveryTimeZone on the notification (generally to NSTimeZone.default, which is a non-updating version of "the current time zone").

Swift's Date type (and also its Objective-C NSDate) doesn't have any notion of TimeZone in itself. It's just a simple timestamp. This means that if you set a timezone to a UIDatePicker, you can use its date as it is in that timezone without a need of converting it.
More explanation: when you po date in a debugger console, the debugger just select the UTC timezone as a presentation of the printing date. Its behavior doesn't related to the Date instance.

Related

in swift, wrong time is displayed for a date outside daylight saving, depending on the time of call

i am currently having the following problem with relation to daylight saving.
Using the UI the user creates an entry for a specific date and time.
eg.: on 20.10 (so DST, this is the time where she is using the app) she creates an entry for 28.10 11:00 (this is outside the DST)
we create a date object like this, the format is the one used in the UI:
let dateFormatter = DateFormatter.getFormatter()
dateFormatter.dateFormat = "MMMM d, yyyy HH:mm"
self.startDate = dateFormatter.date(from: label.text!)!
no further processing is done and the date object is saved locally in realm.
printing the object shows 2020-10-28 09:00:00 +0000 which is correct, since we are in CET (GMT +2 in summer).
As long as the device's date is before 25.10 (so in DST) the date is correctly displayed throughout the app.
Now, after the DST (starting with 25.10) the app wrongly displays 28.10 10:00.
We are now in winter time which is GMT +1
it seems that swift wrongly uses the DST setting for the time when it is called, rather then the actual datetime that is being converted.
what am i doing wrong? any other technology that we used would correctly display the time, as long as the timezone is the same.

How to set timezone on a UIDatePicker?

Is there any way to set a UIDatePicker's timezone to mine (e.g. GMT+3)?
I have tried a lot of solutions on the internet, yet none work.
This is from the Apple docs:
Configuring a Date Picker The configuration of a date picker is
determined by the datePickerMode property, whose value you can set
programmatically or in Interface Builder. For modes that include date
or time values, you can also configure the locale, calendar, and time
zone information as appropriate. The date picker uses that information
when formatting date and time values for the current user, and
defaults to the device’s locale, calendar and time zone. The date
property represents the currently selected date in the form of an
NSDate object, which is calendar and time zone agnostic.
You can set the time zone by configuring the date picker. TimeZone.current will initialise a TimeZone object with the devices current time zone. You can also configure the calendar or locale if needed (though they default to the current device setting).
var picker = UIDatePicker()
picker.calendar = Calendar.current
picker.locale = Locale.current
picker.timeZone = TimeZone.current
You can retrieve the current date with the picker.date property. This can also be set programmatically to animate the date picker to that value.
You can use the date from the datepicker separately as well. You need a date formatter to apply calendar and timezone information:
let date = picker.date
let formatter = DateFormatter()
// Optionally set calendar, timezone etc on formatter
print(formatter.string(from: date))
#IBAction func onValueChanged(_ sender: UIDatePicker) {
print(sender.date.description(with: .current))
}
Reference:
Swift | iOS | XCode - UIDatePicker timezone problem fix
https://www.youtube.com/watch?v=_B9TyvFugy8

NSDate date in objective-c gives different datetime than Date() in swift

I understand that IOS uses place independent times unless specified otherwise. However, for an unknown reason when I log to console [NSDate date] from Objective-C, I am getting the actual time where I'm located whereas when I print to console Date() from swift, I'm getting a getting Greenwich meantime.
In objective-C the first mention of date in the method is:
__block NSDate* rightNow = [NSDate date];
LogDebug(#"right now%#",rightNow);
/logs as: right nowFri Oct 26 14:18:37 2018
In swift, the first mention of date in the method is:
let now = Date()
print("right now date is",now)
//Prints as: right now date is 2018-10-26 18:19:10 +0000
I do set formats using dateformatter for date in other methods in the Objective-C class, but I don't see how they could carry over into this method.
What could account for there being different? Is there a way to force them to be one or the other?
Thanks in advance for any suggestions.
Although date() and NSDate are supposed to be the same thing, they log differently in the console whether using NSLog or a library such as LogDebug. You should be aware of this when examining console logs.
Where there is a practical consequence to the difference between the two, is that now.timeIntervalSince(someDate!) returns a different result than NSDate().timeIntervalSince(someDate). To avoid issues, compare apples with apples, in other words date() with date() and NSDate() with NSDate()

What is Difference among following time zones in swift

let timeZone = NSTimeZone.system.description
let localTimeZone = TimeZone.ReferenceType.local.description
let currentTimeZone = TimeZone.current.description
let defaultTimeZone = TimeZone.ReferenceType.default.description
let autoUpdateTimezon = TimeZone.autoupdatingCurrent.description
print ("System Timezone \(timeZone)")
print ("Local Timezone \(localTimeZone)")
print ("Current Timezone \(currentTimeZone)")
print ("Default Timezone \(defaultTimeZone)")
print ("Auto updating Timezone \(autoUpdateTimezon)")
OUTPUT
System Timezone Asia/Kolkata (current)
Local Timezone Asia/Kolkata (autoupdatingCurrent)
Current Timezone Asia/Kolkata (current)
Default Timezone Asia/Kolkata (current)
Auto updating Timezone Asia/Kolkata (autoupdatingCurrent)
So, i get all the output are same so whats the difference among these timezone and which timezone we should use in which case.
Problem
I used following to code for the date conversion
static func stringToString(strDate:String, fromFormat:String, toFormat:String)->String{
let dateFormatter = DateFormatter()
dateFormatter.timeZone = TimeZone.init(abbreviation: "UTC") ?? TimeZone(identifier: "UTC") ?? TimeZone.ReferenceType.default
dateFormatter.dateFormat = fromFormat
let currentDate = dateFormatter.date(from: strDate) ?? Date()
dateFormatter.dateFormat = toFormat
dateFormatter.timeZone = TimeZone.ReferenceType.default
let currentDates = dateFormatter.string(from: currentDate)
return currentDates
}
Scene : My app is crashing in qatar if user set timezone automatically and off the 24 hours, but in india there is no crash
(TimeZone.ReferenceType.local)
I have given next build with TimeZone.ReferenceType.default and issue is solved
So, i cant understand what was the issue.
Crash Report
Old Code in which i am getting crash
Note that TimeZone.ReferenceType is basically NSTimeZone.
If you look at the docs for TimeZone and NSTimeZone you'll find out very quickly.
From the NSTimeZone:
The system class property returns the time zone currently used by the system, if known. This value is cached once the property is accessed and doesn't reflect any system time zone changes until you call the resetSystemTimeZone() method. The local class property returns an autoupdating proxy object that always returns the current time zone used by the system.
To summarise, system is cached so won't change when the user changes their time zone. You have to call resetSystemTimeZone to update it. local on the other hand automatically updates when the user changes their time zone.
The same thing is true for TimeZone:
TimeZone provides two static functions to get time zone values: current and autoupdatingCurrent. The autoupdatingCurrent time zone automatically tracks updates made by the user.
current corresponds to system and autoupdatingCurrent corresponds to local.
Local -> An object that tracks the current system time zone. Use this property when you want an object that always reflects the current system time zone. from ios 11, the local class property reflects the current system time zone, whereas previously it reflected the default time zone.
System -> The time zone currently used by the system. If you access the system class property, its value is cached by the app and doesn't update if the user subsequently changes the system time zone. In order for the system property to reflect the new time zone, you must first call the resetSystemTimeZone() method to clear the cached value.
Default -> The default time zone for the current app.If no default time zone has been set, the current system time zone is used. If the current system time zone cannot be determined, the GMT time zone is used instead.The default time zone is used by the app for date and time operations. You can set it to cause the app to run as if it were in a different time zone.
Current -> The time zone currently used by the system.
autoupdatingCurrent -> The time zone currently used by the system, automatically updating to the user’s current preference.
Source -> https://developer.apple.com/documentation/foundation/nstimezone

Getting a NSDate object from a string

Before flagging this question as a duplicate, please read on.
I need to compare two NSDates. A date I get from a server with the current date.
From NSDate.date() I get this date 2014-09-25 12:48:23 +0000 which is wrong (the time part). I needed to add 5 hours to get the current time so I did the following.
let formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd hh:mm:ss ZZZZZ"
let dateString = formatter.stringFromDate(NSDate.date())
The result is the correct date - 2014-09-25 06:21:56 +05:30
But there's a little hitch. This date is a String, not a NSDate. I need it to be a NSDate object to compare it with another date.
I tried converting it back like this,
let date = formatter.dateFromString(dateString)
And I get a wrong result - 2014-09-25 00:55:53 +0000. I tried passing the date string to a new NSDateFormatter to see if that works but again I still I get the wrong date.
My question is, how can I convert this date string to a NSDate object which also retains the correct time.
Thank you.
You are thoroughly confused about NSDate.
An NSDate is a point in time. It has no time zone information. If we both call [NSDate date] right now, we will get the same NSDate, even when you are in India and I'm in the UK. That's intentional. It's the same time. The time displayed on my watch and on your watch is different, but NSDate is the same. You can't convert NSDate to an "Indian" date.
You use calendars and timezones to convert NSDates to strings that you display to a user, in the way your users expect it. That's what you have done. You got a string that makes sense to Indian users. If an Indian user types a time, you take that string and convert it to an NSDate. The NSDate will be in Universal time. If you and I both typed in the time on our watch right now and converted it, you would type a time that looks like 5 1/2 hours earlier than mine. But it's the same time. If you convert it to NSDate, we will both get the exact same NSDate.
So how do you change your NSDate? Quite simple: You don't. NSDate is absolute time, independent of your location on earth.
Upon further Googling, I came across this post. The method described in it does exactly what I want. The original code is in Objective-C and since my question is in Swift, I'm going to post its Swift translation. \
func toLocalTime() -> NSDate {
let timeZone = NSTimeZone.localTimeZone()
let seconds = timeZone.secondsFromGMTForDate(self)
return NSDate(timeInterval: Double(seconds), sinceDate: self)
}
I added these as extension methods of NSDate so you can simply call them like this.
NSDate.date().toLocalTime()
You can compare two dates using any of the following NSDate functions: compare, earlierDate, laterDate, isEqualToDate. You should not compare date strings (oh, goodness, no, think of the nightmare); convert 'date strings' into 'NSDate' as soon as inputed.
In order to compare two dates that arose from strings correctly, you'll need the date strings to be unambiguous. In practice, that requires the date to have a time zone attached. If your server isn't providing a time zone and can't be modified to provide one, then you'll be forced to assume one (which would typically be the time zone where the server is located, assuming one server).

Resources