Using time to change theme with swift - ios

I am trying to add in a feature that will change the background of that point twice a day. If it is 6:00 am then the app will show picture 1 and at 6:00 pm the picture will change to 2. If anyone knows how to do this please help.

You could use a timer to make the checks more or less frequent, but if you just want to set the image based on the time you could use something like this...
Swift 3
let hour = Calendar.current.component(.hour, from: Date())
if hour >= 6 || hour <= 17 {
print("use image one")
} else {
print("use image two")
}

Related

dateComponents() from... to in days shows from now to tomorrow as 0 days?

I have datecomponent objects that represent some time in the future. I want to calculate how many dates from now until that date. I'm also including representation of the dates simply as dates. What I'm finding is that when I am trying to show how many there are to a date that is 'tomorrow' it's showing 0. To my mind it should be showing 1. I can try a hacky way of just adding 1 to my count but I'm wondering is it because it's trying to round to the nearest 24 hours or something? If so how can I 'fix' it?
Here is my sample code:
let myPreviousRelevantDate = self.datePickerOutlet.date
let nextDate = Date(timeInterval: Double(86400 * (myDurationInDaysAsInt)), since: myPreviousRelevantDate!)
let daysToNextDate = Calendar.current.dateComponents([.day], from: Date(), to: nextDate).day!
What I'd like to avoid is the number of days to the target date changing during the day also - i.e. regardless of the timestamp of my target date - the number of days to that day remaining constant until midnight is reached.
If your intent is to calculate the number of days using a timeless calendrical calculation what you need is to use noon time. Note that not every day has 24 hours, you should always use calendar method to add days to a date:
extension Date {
var noon: Date {
Calendar(identifier: .iso8601)
.date(
bySettingHour: 12,
minute: 0,
second: 0,
of: self
)!
}
}
let daysToNextDate = Calendar.current.dateComponents([.day], from: Date().noon, to: nextDate.noon).day!

How can I find all the historical offset transition dates for a timezone?

I'm trying to write an app that displays information about a given timezone. It displays which periods of time that timezone is observing DST, and which periods of time it is not. Most importantly, it highlights times where the timezone changes irregularly, such as when Britain observed double DST during WWII, or when Samoa skipped a day in 2011.
For that, I would need to get a list of all the historical timezone offset transitions, as stored in the TZ database (I think there is a copy of the database in every macOS/iOS device). To be more specific, a "transition" (similar to java.time.zone.ZoneOffsetTransition) is modelled by the following 3 things:
the Date when it happened
the GMT offset in seconds before it happened
the GMT offset in seconds after it happened
From what I can see from the TimeZone API docs, there is no built-in method that does this (unlike how java.time does). The closest method I could find is nextDaylightSavingTimeTransition(after:), but that only tells me the transition date of one transition, when given a date, and I'm also not sure what date to give.
How can I get the list of transitions?
Example output for Asia/Ho_Chi_Minh:
Transition at 1906-06-30T16:53:20Z from 25600 to 25590
Transition at 1911-04-30T16:53:30Z from 25590 to 25200
Transition at 1942-12-31T16:00:00Z from 25200 to 28800
Transition at 1945-03-14T15:00:00Z from 28800 to 32400
Transition at 1945-09-01T15:00:00Z from 32400 to 25200
Transition at 1947-03-31T17:00:00Z from 25200 to 28800
Transition at 1955-06-30T16:00:00Z from 28800 to 25200
Transition at 1959-12-31T16:00:00Z from 25200 to 28800
Transition at 1975-06-12T16:00:00Z from 28800 to 25200
One solution I worked out is, start with passing distantPast to nextDaylightSavingTimeTransition:
someTimeZone.nextDaylightSavingTimeTransition(after: .distantPast)
This gets you the first transition date. Then do:
// second transition date
someTimeZone.nextDaylightSavingTimeTransition(after:
someTimeZone.nextDaylightSavingTimeTransition(after: .distantPast)
)
// third transition date
someTimeZone.nextDaylightSavingTimeTransition(after:
someTimeZone.nextDaylightSavingTimeTransition(after:
someTimeZone.nextDaylightSavingTimeTransition(after: .distantPast)
)
)
and so on. Of course, we will put this in a loop. The offset before and after the transition can be found by secondsFromGMT(for:). We will pass a two dates that only differ by something like 1 second.
Also note that although this is named nextDaylightSavingTimeTransition, it also gives you non-DST transitions, which is exactly what you want, so that's great!
import Foundation
struct OffsetTransition {
let instant: Date
let offsetBefore: Int
let offsetAfter: Int
}
var date = Date.distantPast
let timeZone = TimeZone(identifier: "Some Time Zone ID")!
let dateFormatter = ISO8601DateFormatter()
dateFormatter.formatOptions = [.withInternetDateTime]
var transitions = [OffsetTransition]()
while date < Date() {
guard let instant = timeZone.nextDaylightSavingTimeTransition(after: date) else {
break
}
let offsetBefore = timeZone.secondsFromGMT(for: instant.addingTimeInterval(-1))
let offsetAfter = timeZone.secondsFromGMT(for: instant)
if offsetBefore == offsetAfter { continue }
transitions.append(.init(instant: instant, offsetBefore: offsetBefore, offsetAfter: offsetAfter))
print("Transition at \(dateFormatter.string(from: instant)) from \(offsetBefore) to \(offsetAfter)")
date = instant
}
Note the if offsetBefore == offsetAfter { continue } check. I added this check because without it, it will sometimes produce transitions with offsetBefore == offsetAfter. This could be an indication that I am doing something wrong, but this check seems to fix the problem...
The output of this almost matches the output of a similar code using Java's getTransitions. However, there is one other slight problem that I found with this solution. For some timezones, such as Europe/London, the transition from the local mean time to the standardised offset is missing, but for other timezones (e.g. Asia/Hong_Kong), it exists. For example, a similar code using getTransitions in Java would produce a "Transition at 1847-12-01T00:01:15Z from -75 to 0" for Europe/London, but the Swift code's output does not include this line. This is not too big of a problem for me though.

UISegment Control - Set selected according to day (SWIFT)

Like the title says, I'm trying to set the selected segment control according to day. My segment control includes the days of the week and i also have a date and time label. The proper day has to be selected when the view is open
I know i have to do something with:
segmentControl.selectedSegmentIndex = 0
I'm getting the date with:
showDate.text = "Date: " + DateFormatter.localizedString(from: Date(), dateStyle: DateFormatter.Style.medium, timeStyle: .none)
But I'm not sure how to set the selectedIndex to be dependent on date and show the appropriate day. I'm still new to swift and still learning, any help will be very much appreciated! Thanks
UISegmentedControl indexes start from 0. If you have all the days of the week in it its indexes start from 0 and end in 6.
You can get a day's index in weekdays using this
let day = Calendar.current.component(.weekday, from: Date())
this returns 1 for Sunday, 2 for Monday... 7 for Saturday
So you can assign selectedSegmentIndex as follows
if (2...6).contains(day) {
segmentControl.selectedSegmentIndex = day-2
} else {
segmentControl.selectedSegmentIndex = UISegmentedControlNoSegment
}

Swift: Formatting time string based on number of seconds

There is a NSTimer object in my app that counts elapsed time in seconds.
I want to format an UILabel in my app's interface in the such way it matches the well know standard.
Example
00:01 - one second
01:00 - 60 seconds
01:50:50 - 6650 seconds
I wonder how to do that, do you know any pods/libraries that creates such String based on Int number of seconds?
Obviously I can come with a complicated method myself, but since it's recommended to not reinvent the wheel, I'd prefer to use some ready-to-use solution.
I haven't found anything relevant in Foundation library, nor in HealthKit
Do you have any suggestions how to get it done? If you say "go and write it yourself" - that's ok. But I wanted to be sure I'm not missing any simple, straightforward solution.
thanks in advance
(NS)DateComponentsFormatter can do that:
func timeStringFor(seconds : Int) -> String
{
let formatter = DateComponentsFormatter()
formatter.allowedUnits = [.second, .minute, .hour]
formatter.zeroFormattingBehavior = .pad
let output = formatter.string(from: TimeInterval(seconds))!
return seconds < 3600 ? output.substring(from: output.range(of: ":")!.upperBound) : output
}
print(timeStringFor(seconds:1)) // 00:01
print(timeStringFor(seconds:60)) // 01:00
print(timeStringFor(seconds:6650)) // 1:50:50
Figured it out based on this answer, quite simple!
func createTimeString(seconds: Int)->String
{
var h:Int = seconds / 3600
var m:Int = (seconds/60) % 60
var s:Int = seconds % 60
let a = String(format: "%u:%02u:%02u", h,m,s)
return a
}

Swift: How to display one of the two Images depending of the current time of the day

I have images named open and close, which are displayed according to the store timings. According to Indian Standard time the store timings are 11Am to 11PM, during this time I want to display the open image and closed image in the remaining time. Can someone help me how to do it. Thanks.
First of all, get current time in hours (it is 24 hour format)
let date = NSDate()
let calendar = NSCalendar.currentCalendar()
let components = calendar.components([.Hour], fromDate: date)
let hour = components.hour
Then check for time
if hour >= 11 && hour <= 22 {
// show open image
}
else {
// show close image
}
var component: NSDateComponents = NSCalendar.currentCalendar().components([.Hour, .Minute], fromDate: currentDate)
var strStoreStatus: String = (component.hour() >= 11 && component.hour() <= 22) ? "OPEN" : "CLOSE"

Resources