Picking a date with swift UI automation - swift

In the app I'm testing there is a date picker I'm trying to automate. The wheel defaults to tomorrow and I'm attempting to change it to today's date but 2 minutes from now. Below is the code I'm using to attempt this.
app.pickerWheels.element(boundBy: 0).adjust(toPickerWheelValue: "Today")
app.pickerWheels.element(boundBy: 1).adjust(toPickerWheelValue: "1")
app.pickerWheels.element(boundBy: 2).adjust(toPickerWheelValue: "00")
(In the actual code I'm using variables and not hard coding these string)
This code works for the second and third wheel (hours and minutes) but for the first wheel it won't set the value. The test will fail and not continue past that point.
I have also tried passing today's date instead of just "Today" with the same results.

You can use the DateFormatter class with Date to accomplish this.
// Initialize the date formatter. Set the timeZone and format. I chose hours and minutes.
let dateFormatter: DateFormatter = DateFormatter()
dateFormatter.timeZone = NSTimeZone.local
dateFormatter.dateFormat = "HH:mm"
// Initialize the Date instance using a time interval since now.
let d: Date = Date(timeIntervalSinceNow: 2 * 60)
print("Current Time = \(dateFormatter.string(from: Date())), Two-Minutes-From-Now = \(dateFormatter.string(from: d))")
Output: Current Time = 23:57, Two-Minutes-From-Now = 23:59
A Date is stored as a time interval since January 1st, 1970. You can manipulate the date by adding or subtracting seconds from it. Here, I added 2 * 60 or two 60-second minutes to the current time interval (a large value represented in a double). This points to two minutes in the future.
Now, if you print the date without the formatter, it will just display the current time with no regard to your time zone. So if you want it to be accurate to your time zone, you need to set that in the formatter first. Note that it doesn't change the time, just its representation to you.

Related

DateFormatter returns previous day

I've looked around and people have had problems with different years, random and changing results, and nil dates, but nothing like what I have, so I am asking here. Note I am in Playground right now.
I am taking strings in the format of "yyyy-mm-dd" and converting them to a different date format. Here is the code:
let example = "2001-11-03"
let dateFormatterInput = ISO8601DateFormatter()
dateFormatterInput.formatOptions = [.withFullDate, .withDashSeparatorInDate]
let date = dateFormatterInput.date(from: example)
let dateFormatterOutput = DateFormatter()
dateFormatterOutput.dateFormat = "MMMM dd, yyyy"
let output = dateFormatterOutput.string(from: date!)
The sidebar in Playground shows that the first reference to the previous day's date happens on the let date line. Also, this behavior happens on every date I've tried. In this example, it returns "November 2, 2001." I've tried different months, days, and years (1900s and 2000s) and it gives me the same result every time.
What am I doing wrong?
The key thing here is that ISO8601DateFormatter by default thinks that the time zone of your date string is GMT:
ISO8601DateFormatter.timeZone:
The time zone used to create and parse date representations. When unspecified, GMT is used.
However, the timeZone of DateFormatter by default (and also the side bar of the playground) assumes your device's local time zone:
DateFormatter.timeZone
The time zone for the receiver. If unspecified, the system time zone is used.
If your system time zone has a negative UTC offset on the start of the day 2001-11-03 UTC, then when seen from your time zone, that moment is actually in the day 2001-11-02. Hence the output you see.
Assuming you don't care about the actual value of date, and just care about the final string output, you can just set the timeZone of DateFormatter to GMT:
dateFormatterOutput.timeZone = TimeZone(identifier: "GMT")
Side note: You should also set locale when using a fixed format to avoid localisation issues:
dateFormatterOutput.locale = Locale(identifier: "en_US_POSIX")
Or better, just use one of the built-in, locale sensitive formats instead:
dateFormatterOutput.dateStyle = .medium
dateFormatterOutput.timeStyle = .none

Why my Cloud records Time isn't the same when I load it into my app

In a training project to learn the cloudKit capacity I record a date via a Datepicker and I save it into a cloudKit data base. I use the French format "DD/MM/YYYY HH:MM". Everything work fine and the date which is entered by the user is the same format in the data base.
Now I would like to work with this date in an other view in my app. So I load it into an array from cloudKit and I would like to compare it with the current time.
let recordTime = LastMealRecords[LastMealRecords.count - 1]
let currentSavedTime = (recordTime.object(forKey: "Timming"))
let diffComponents = Calendar.current.dateComponents([.hour], from: currentSavedTime as! Date, to: Now)
let intervals = diffComponents.hour
print(Now)
print(currentSavedTime)
So here the print show :
Now : DD/MM/YYYY HH:MM (which is the correct local time !)
currentSavedTime : DD/MM/YYY HH:MM (but HH:MM is not the same value as the one which is save on the Cloud data base. In fact it seem to be the UTC time cause there is 2h difference in less like the Local and UTC time in France... )
Question : How could I fixe this matter ? I'm trying to find the same value which is saved on the cloud..
Thanks for your help !
You can't make changes to the time saved at server end, all you can do is manipulate your current time accordingly
// Return time zone used by the system right away
let timeZone = NSTimeZone.system
// Returns the difference in seconds between the server and GMT at a given date.
let timeZoneOffset = timeZone.secondsFromGMT(for: currentDate) / 3600
print(timeZoneOffset, "hours offset for timezone", timeZone)

Swift - How to create a date object containing just the time

I trying to create a date object just containing the time of 1 second past midnight.
I believe the following should work but it just keeps returning nil.
let dateTime = Date()
let timeFormatter = DateFormatter()
timeFormatter.dateFormat = "HH:mm:ss"
let time = timeFormatter.date(from: "00:00:01")
print("Time: \(time!)")
Can someone tell me what i'm doing wrong!
Thanks
Let Calendar do the math, this is more reliable, you aren't using the current date (dateTime) anyway.
let midnight = Calendar.current.startOfDay(for: Date())
let oneSecondAfterMidnight = Calendar.current.date(byAdding: .second, value: 1, to: midnight)
This works even if midnight doesn't exist due to daylight saving change.
Date is not a "date" in any meaningful way. It's a specific point in time, independent of any calendar or location. What you want to express is a point on a calendar: "one second" past an arbitrary calendar point we call "midnight." That's done with DateComponents.
var dc = DateComponents()
dc.hour = 0
dc.minute = 0
dc.second = 1
This is the second second of the first minute of the first hour (00:00:01) of an arbitrary day on an arbitrary calendar, which is what you've described.
More precisely, it's "zero hours, zero minutes, and one second," which is only "one second after midnight" if you add it to some "midnight." But beyond that, there is no independent "time" type. Those things only have meaning when applied to a Calendar.
(Keep in mind that due to DST change in some parts of world, such as Iran, there are sometimes two midnights in the same day. So when you ask for this kind of thing, you need to be very clear what you mean. Do you want every second after midnight or just the first one on a given day?)

Absolute UTC offset in Swift

My task is to create a string containing UTC offset during DST and during summer time (example: UTC+1UTC+2 or UTC+1UTC+1 if there is no DST for a region). My function looks the following:
extension TimeZone {
public func utcOffset(for date: Date = Date()) -> String {
var currentTimeOffest = self.secondsFromGMT(for: date)
if isDaylightSavingTime() {
currentTimeOffest -= Int(daylightSavingTimeOffset(for: date))
}
let currentInHours = Int(currentTimeOffest / 3_600)
let hoursSymbol: String = currentInHours > 0 ? "+" : ""
let daylightOffset = TimeInterval(currentTimeOffest) + self.daylightSavingTimeOffset(for: date)
let daylightInHours = Int(daylightOffset / 3_600)
let daylightSymbol: String = daylightInHours > 0 ? "+" : ""
return "UTC\(hoursSymbol)\(currentInHours)UTC\(daylightSymbol)\(daylightInHours)"
}
}
It works well and I've written tests for it. All is good but after recent DST changes in multiple countries the tests started failing, even though I pass a specific date to calculate the offset for:
func testUtcOffset() {
let date: Date = Date(timeIntervalSince1970: 1_557_482_400) //May 10, 2019 10:00:00 AM
let warsaw = TimeZone.init(identifier: "Europe/Warsaw")! //eastern hemisphere, with DST
XCTAssertEqual(warsaw.utcOffset(for: date), "UTC+2UTC+3")
let shanghai = TimeZone.init(identifier: "Asia/Shanghai")! //eastern hemisphere, without DST
XCTAssertEqual(shanghai.utcOffset(for: date), "UTC+8UTC+8")
let barbados = TimeZone.init(identifier: "America/Barbados")! //western hemisphere, without DST
XCTAssertEqual(barbados.utcOffset(for: date), "UTC-4UTC-4")
let bermuda = TimeZone.init(identifier: "Atlantic/Bermuda")! //western hemisphere, with DST
XCTAssertEqual(bermuda.utcOffset(for: date), "UTC-4UTC-3")
let gmt = TimeZone.init(identifier: "GMT")! //GMT, without DST
XCTAssertEqual(gmt.utcOffset(for: date), "UTC0UTC0")
let lisbon = TimeZone.init(identifier: "Europe/Lisbon")! //GMT, with DST
XCTAssertEqual(lisbon.utcOffset(for: date), "UTC+1UTC+2")
}
2 weeks ago, the warsaw and lisbon timezones started failing, today bermuda. Any ideas what might be wrong?
A few things:
In your tests, you have the offsets for Warsaw and Lisbon an hour off. Warsaw is UTC+1 during standard time, and UTC+2 during daylight saving time. Lisbon is UTC+0 during standard time, and UTC+1 during daylight time.
From your comment, it seems you're looking for the standard offset and the daylight offset. However, the standard offset isn't necessarily the same as the current offset. The current offset might include daylight saving time, or not.
According to these docs, the secondsFromGMT function returns the difference including the daylight adjustment if one is in effect. Thus you should not be adjusting for that yourself.
It doesn't seem to make sense to be asking the daylightSavingTimeOffset function for the offset on a date when daylight saving time doesn't apply. You might get better results just using secondsFromGMT for two different dates in the current year. A common approach is to get the offsets for January 1st and July 1st. Whichever is smaller is the standard time, the other is the daylight time. Keep in mind they may be the same if DST is not used, and they will be inverted between northern and southern hemisphere time zones.
Even with the above approach, this sort of algorithm ignores a lot of the complexities of time zones. Consider that some time zones have changed their standard time at different points in their history. Such an algorithm might mistake that as a daylight saving time change.
A point of concern: Once you have your string generated, such as "UTC+1UTC+2", how will the external API you know from that alone which set of daylight saving time rules to apply? Since daylight saving time starts and stops at different dates and times in different parts of the world, it's likely that the wrong dates could be used when interpreting the offsets.

NSDate set timezone in swift

how can i return a NSDate in a predefined time zone from a string
let responseString = "2015-8-17 GMT+05:30"
var dFormatter = NSDateFormatter()
dFormatter.dateFormat = "yyyy-M-dd ZZZZ"
var serverTime = dFormatter.dateFromString(responseString)
println("NSDate : \(serverTime!)")
the above code returns the time as
2015-08-16 18:30:00 +0000
The date format has to be assigned to the dateFormat property of the date formatter instead.
let date = NSDate.date()
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let str = dateFormatter.stringFromDate(date)
println(str)
This prints the date using the default time zone on the device. Only if you want the output according to a different time zone then you would add for example
Swift 3.*
dateFormatter.timeZone = NSTimeZone(name: "UTC")
Swift 4.*
dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
also refer link http://www.brianjcoleman.com/tutorial-nsdate-in-swift/
how can i return a NSDate in a predefined time zone?
You can't.
An instance of NSDate does not carry any information about timezone or calendar. It just simply identifies one point in universal time.
You can interpret this NSDate object in whatever calendar you want. Swift's string interpolation (the last line of your example code) uses an NSDateFormatter that uses UTC (that's the "+0000" in the output).
If you want the NSDate's value as a string in the current user's calendar you have to explicitly set up a date formatter for that.
Swift 4.0
dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
If you always have the same time zone for the input string, you can create two date formatters to output the local time zone (or a specified one):
let timeFormatterGet = DateFormatter()
timeFormatterGet.dateFormat = "h:mm a"
timeFormatterGet.timeZone = TimeZone(abbreviation: "PST")
let timeFormatterPrint = DateFormatter()
timeFormatterPrint.dateFormat = "h:mm a"
// timeFormatterPrint.timeZone = TimeZone(abbreviation: "EST") // if you want to specify timezone for output, otherwise leave this line blank and it will default to devices timezone
if let date = timeFormatterGet.date(from: "3:30 PM") {
print(timeFormatterPrint.string(from: date)). // "6:30 PM" if device in EST
} else {
print("There was an error decoding the string")
}
The number 1 means 1 regardless of language. Yet in English it's spelled as one, in Spanish it's una, in Arabic it wahid, etc.
Similarly 123982373 seconds pass 1970 is going to reflect differently in different timezones or calendar formats, but's all still 123982373 seconds passed 1970
The difference between 3 seconds and 7 seconds is 4 seconds. That doesn't require a calendar. Neither you need a calendar/timezone to know the difference in time between these two Epoch times 1585420200 and 1584729000
Dates are just a timeInterval from January 1, 1970 (midnight UTC/GMT). Dates also happen to have a string representation.
Repeating Nikolia's answer, Swift's default string interpolation (2015-08-16 18:30:00 +0000) uses a DateFormatter that uses UTC (that's the "+0000" in the output).
Calendars with the use of timezones give us a contextual representation that is just easier to understand than trying to calculate the difference between two gigantic numbers.
Meaning a single date (think of a single timeInterval since 1970) will have a different string interpretations per calendar. On top of that a calendar will itself vary based on time zones
I highly recommend that you go and play around with this Epoch converter site and see how selecting a different timezone will cause the string representations for the same moment/date/timeInterval to change
I also recommend to see this answer. Mainly this part:
Timezone is just an amendment to the timestamp string, it's not considered by the date formatter.
To consider the time zone you have to set the timeZone of the formatter
dateFormatter.timeZone = TimeZone(secondsFromGMT: -14400)