Reading out the day of the week via Date () for local notifications in SwiftUI - swift

I am trying to send a certain message with local notifications and that depends on the day of the week, now my code has to know what day of the week it is in order to send the notification.
Thank you.

You can get a single component (the day of the week in our case) of the current date like this:
if Calendar.current.component(.weekday, from: Date()) == 1 {
// Yay, it's Sunday!
}
From the docs: "The weekday units are the numbers 1 through N (where for the Gregorian calendar N=7 and 1 is Sunday)."

Looks like you want this (or kind of, for another date)
if let weekDay = Calendar.current.dateComponents([.weekday], from: Date()).weekday {
// do this what's needed
}

Related

Count Days between Dates Swift (Considering what may be tomorrow.)

I have this code:
extension Date {
/// From today to self
/// - Returns: number of days.
func getDaysUntil() -> Int? {
return Calendar.current.dateComponents([.day], from: Date(), to: self).day
}
}
I need everything to be considered in terms of EST. So regardless of which time zone we are in, everything should be regarded as EST.
I am having a problem when comparing today with tomorrow.
So take the following case:
Date() // (now):: June 15.
self (compare to):: June 16.
Regardless the time of day today, I want to say that it's 1 day until the comparison date (self).
So, if it's 11:59pm and the comparison date (self) is 12:01am, I want the result to be 1 day. If it's 12:01am and the comparison date (self) is 11:59pm, I still want the comparison result to be 1.
As it is, no matter what I do, when we get to those extreme edges, the date calculation is off by 1, one way or the other.
Also, this isn't just a today vs. tomorrow issue. The correct count should be the result (considering the today/tomorrow conundrum) for any date.
Is there some fancy trick, or does anyone have any suggestion how we could accomplish this? Thanks!
If you need a default "don't care" time calendrical calculation what you need is to use noon time. Check WWDC session 227 Solutions to Common Date and Time Challenges. Check the "Midnight" part and what is said about why people should NOT use midnight.
extension Calendar {
static let iso8601 = Calendar(identifier: .iso8601)
}
extension Date {
/// From today's noon to self's noon
/// - Returns: number of days.
var daysFromToday: Int {
Calendar.iso8601.dateComponents([.day], from: Date().noon, to: noon).day!
}
/// Noon time
/// - Returns: same date at noon
var noon: Date {
Calendar.iso8601.date(bySettingHour: 12, minute: 0, second: 0, of: self)!
}
}
Usage:
let yesterday = DateComponents(calendar: .iso8601, year: 2022, month: 5, day: 2, hour: 23, minute: 59, second: 59).date!
yesterday.daysFromToday // -1

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?)

Is there an elegant way of determining if two dates are separated by a week of year in Swift?

If I have two dates, and I want to know if one of them falls on a week of year (as defined here) just prior to the other, how can I figure this out in Swift?
Assuming I don't care about time, one approach could be:
let calendar = Calendar.current
let startOfDate1 = calendar.startOfDay(for: date1)
let startOfDate2 = calendar.startOfDay(for: date2)
let date1WeekOfYear = calendar.dateComponents([.weekOfYear], from: startOfDate1).weekOfYear!
let date2WeekOfYear = calendar.dateComponents([.weekOfYear], from: startOfDate2).weekOfYear!
if (date1WeekOfYear - date2WeekOfYear) == 1 {
// do some stuff
}
This works except in the case where date1 falls within the first week of the year, and date2 falls within the last week of the prior year. Do I really have to also add in other logic to check the situation where the year components are different, and account for varying lengths of years in weeks (most have 52 weeks, some have 53), or is there a more elegant way to handle this?
Please note that I'm not interested in checking if the two dates are within 7 days of each other. It's possible that the two days are within 2 days of each other, but fall within different weeks of the year.
Thanks in advance.
Here's a way I found:
You do need to get the year, but Calendar can still do the calculation for you. You just need to call a different overload of the method from the one in Rob Napier's answer. You need the overload that accepts DateComponents:
let calendar = Calendar.current
let start = Date(timeIntervalSince1970: 1577375330) // 2019-12-26
let end = Date(timeIntervalSince1970: 1577893730) // 2020-01-01
// remember it's yearForWeekOfYear, not just "year"
let startDateComponents = calendar.dateComponents([.yearForWeekOfYear, .weekOfYear], from: start)
let endDateComponents = calendar.dateComponents([.yearForWeekOfYear, .weekOfYear], from: end)
let interval = calendar.dateComponents([.weekOfYear], from: startDateComponents, to: endDateComponents).weekOfYear!
print(interval) // 1
My speculation of why this works but the overload taking Dates doesn't:
The overload that takes Dates will first get the difference between the two dates, which represent instants, and then convert that time interval to the specified set of DateComponents. Note that it's probably converting a TimeInterval to DateComponents, which is why it can't calculate week boundaries and such.
The overload that takes DateComponents can calculate week boundaries because that information is given as its parameters.
You can add 7 days to one date (allowing for year roll-over), and determine the difference in week-numbers between the two dates to be zero weeks rather then one week.
Have a look at the 2019 end of year
> var cal = Calendar.current
> let df = DateFormatter(); df.dateFormat = "yyyy-MM-dd"
> var d1 = df.date(from: "2019-12-28")!;
> var w1=cal.component(.weekOfYear, from:d1)
w1: Int = 52
This tells us Dec 28 still fell in week 52.
> var w2=cal.component(.weekOfYear, from: df.date(from: "2019-12-29")!)
w2: Int = 1
And this tells us Dec 29 fell in week 1 of 2020. These two dates are "1 week apart", as humans can easily tell. Determining this by calculation can be a bit harder, even if you use modulo arithmetic: the wrap-around is irregular, at 52 for some years, and 53 for others, as the OP hinted at. (2006, 2012, 2017 and 2023 are all 53-week years)
To determine that they are 1 week apart by calculation, first move up the earlier date by 7 days, i.e. 2019-12-28 plus 7 days:
> var d1_7 = cal.date(byAdding: .day, value:7, to:d1)!;
d1_7: Date = 2020-01-04 08:00:00 UTC
> var w1_7 = cal.component(.weekOfYear,from:d1_7)
w1_7: Int = 1
Its week number is 1, equalling that of 2019-12-29. We conclude that 2019-12-28 and 2019-12-29 are 1 week apart.

Setting up a two week timetable in Swift

NOTE: I am a new Swift programmer, a NOOB if you will.
I am creating a school timetable app just for personal use to practise my coding. However, our school operates on a two week time table system, with 10 days, labeled 1 through to ten. I am wondering if anyone had some ideas as to how I could work out whether the current date is day one or day nine or day 4. I know I could use if statements for the dates, but the would take a long time, and require manual input of the dates. How could I have the app keep count of what day it is, skipping weekends?
EDIT - I could maybe have 14 days, with days 6,7,13 and 14 empty.
FOR EXAMPLE:
The current date is OCT 4, this is day one. I would like the app to be able to work out what day of the timetable the current date is. This would then load the appropriate day (e.g. Subject, Teacher, Classroom). Day One is Monday, Two is Tuesday, Five is Friday, Six is Monday, 10 is Friday. Could I have some sort of rostering system?
I am sorry if the question is vague, please tell me if I need to clarify.
I have been working on a fix for weeks now, so I have decided to turn to help. Any guidance whatsoever would be much appreciated, as I am at a dead end!
Many thanks
The numbers that I'm plugging into this example probably don't match your requirements but consider this as a strategy. (In this case, using a 1-to-14 cycle. If you'd rather get 1-to-10 you can put in a subtraction and a different error to throw on the "bad" days.)
class CyclicDay {
enum CyclicDayError: ErrorType {
case InvalidStartDate
}
lazy var baseline: NSDate? = {
// Set up some start date that matches day 1
var components = NSDateComponents()
components.day = 6
components.month = 9
components.year = 2015
return NSCalendar.currentCalendar().dateFromComponents(components)
}()
func dayOfCycle(testDate: NSDate) throws -> Int {
if let start = baseline {
// Convert difference to days
let interval = testDate.timeIntervalSinceDate(start)
let days = interval / (60 * 60 * 24)
// Convert to value 1..14 to position in a 2-week cycle
return Int(days % 14) + 1
}
throw CyclicDayError.InvalidStartDate
}
}
// Test today
let cd = CyclicDay()
let day = try cd.dayOfCycle(NSDate())

How to check/calculate the week-day count (using Date functions) using Javascript?

I would like to check if a given date is the first, second, third, fourth or last monday, tuesday, wednesday,..., sunday in the dates month.
The function should look like this:
if(checkdate(date, "second", "monday"))
{
alert("This is the second monday of the month");
}
else
{
alert("This is NOT the second monday of the month");
}
I would rather write a function that returns an object telling me the day and the week-number-in-month of the given date. Something like:
function infoDate(date) {
return {
day: date.getDay()+1,
week: (date.getDate()-1)%7+1
}
}
Then I can read the returned object and find out if it's the second monday or whatever:
var info = infoDate(date);
if(info.day==1 && info.week==2) {
// second monday
}
Of course, you can still write another localized function that does exactly what you ask for based on an array of numeral and day names.
use getDate() to get day of the month
then getDay() to get the day of the week
using these two you should be able to accomplish your task. Refer to this http://www.w3schools.com/jsref/jsref_obj_date.asp
It seems to me you only need to divide the date by 7 to know how many full weeks have passed, no matter what day it is. Subtracting one before dividing and adding it after sets the first week from 0 to one.
Date.prototype.weekofMonth= function(){
return Math.floor((this.getDate()-1)/7)+1;
}
alert(new Date().weekofMonth())