Get 7 days of current date in swift [duplicate] - ios

I am trying to fill an array of type Date with 15 values, today, the 7 days prior, and the next 7 days. I'm having a hard time figuring out how to get the date. I tried implementing it like this:
func setupDates(){
//get date of 7 days prior to right now
for i in 1...15 {
//add a day per iteration
//append date to date array
}
}

I would suggest having a look at Calendar
It can be a little cumbersome, but generally has a lot of power to it
So you might do something like...
let anchor = Date()
let calendar = Calendar.current
let formatter = DateFormatter()
formatter.dateStyle = .long
formatter.timeStyle = .long
for dayOffset in -7...7 {
if let date = calendar.date(byAdding: .day, value: dayOffset, to: anchor) {
print(formatter.string(from: date))
}
}
nb: This was a simple playground test
Which will print something like...
October 1, 2021 at 10:22:05 AM GMT+10
October 2, 2021 at 10:22:05 AM GMT+10
October 3, 2021 at 10:22:05 AM GMT+11
October 4, 2021 at 10:22:05 AM GMT+11
October 5, 2021 at 10:22:05 AM GMT+11
October 6, 2021 at 10:22:05 AM GMT+11
October 7, 2021 at 10:22:05 AM GMT+11
October 8, 2021 at 10:22:05 AM GMT+11
October 9, 2021 at 10:22:05 AM GMT+11
October 10, 2021 at 10:22:05 AM GMT+11
October 11, 2021 at 10:22:05 AM GMT+11
October 12, 2021 at 10:22:05 AM GMT+11
October 13, 2021 at 10:22:05 AM GMT+11
October 14, 2021 at 10:22:05 AM GMT+11
October 15, 2021 at 10:22:05 AM GMT+11
nb: Today is the 8th
nbb: Your question title says "date format", but you're just trying to fill an array with Dates. The basic concept will work either way

Related

How to use DateComponents to represent the extra 1 hour period at the end of day light saving?

Usually, during end of day light saving, we will be gaining extra 1 hours.
Take Tehran timezone as an example.
During 22 September 2021, Tehran will backward by 1 hour from 00:00
AM, to 11:00 PM.
I wrote the following code to demonstrate such.
import UIKit
func date(year: Int, month: Int, day: Int, hour: Int, minute: Int, second: Int) -> Date {
var dateComponents = DateComponents()
dateComponents.year = year
dateComponents.month = month
dateComponents.day = day
dateComponents.hour = hour
dateComponents.minute = minute
dateComponents.second = second
let date = Calendar.current.date(from: dateComponents)!
return date
}
// During 22 September 2021, Tehran will backward by 1 hour from 00:00 AM, to 11:00 PM.
let tehranTimeZone = TimeZone(identifier: "Asia/Tehran")!
let oldDefault = NSTimeZone.default
NSTimeZone.default = tehranTimeZone
defer {
NSTimeZone.default = oldDefault
}
let date1 = date(year: 2021, month: 09, day: 21, hour: 23, minute: 59, second: 59)
let date2 = date(year: 2021, month: 09, day: 22, hour: 00, minute: 00, second: 00)
let date3 = date(year: 2021, month: 09, day: 22, hour: 00, minute: 00, second: 01)
// STEP 1: 2021 Sep 21 23:59:59 => 1632252599.0, Tuesday, September 21, 2021 at 11:59:59 PM Iran Daylight Time
print("STEP 1: 2021 Sep 21 23:59:59 => \(date1.timeIntervalSince1970), \(date1.description(with: .current))")
// STEP 2: 2021 Sep 22 00:00:00 => 1632256200.0, Wednesday, September 22, 2021 at 12:00:00 AM Iran Standard Time
print("STEP 2: 2021 Sep 22 00:00:00 => \(date2.timeIntervalSince1970), \(date2.description(with: .current))")
// STEP 3: 2021 Sep 22 00:00:01 => 1632256201.0, Wednesday, September 22, 2021 at 12:00:01 AM Iran Standard Time
print("STEP 3: 2021 Sep 22 00:00:01 => \(date3.timeIntervalSince1970), \(date3.description(with: .current))")
From STEP 1 transits to STEP 2, instead for their timeIntervalSince1970 different by +1 seconds, their difference are +3601 seconds, due to the extra 1 hour gain.
Now, my question is, how can we use DateComponents to represent the extra 1 hour period at the end of day light saving?
In another, how can I use DateComponents to generate a Date which is capable to print the following?
2021 Sep 21 23:00:00 => 1632252600.0, Tuesday, September 21, 2021 at 11:00:00 PM Iran Standard Time
Now, we understand that, in Tehran, during 2021 Sept 21, there are 2 type of 23:00:00 time
23:00:00 Iran Daylight time (Epoch is 1632249000)
23:00:00 Iran Standard time (Epoch is 1632252600)
23:00:00 Iran Daylight time (Epoch is 1632249000)
I can represent the above using
let date = date(year: 2021, month: 09, day: 21, hour: 23, minute: 00, second: 00)
23:00:00 Iran Standard time (Epoch is 1632252600)
I have no idea how to represent the above. As, I do not find a way in DateComponents, to enable us to specific whether the local time is belong to standard time, or daylight time.
DateComponents do not have a time zone. The time zone comes into it when you convert DateComponents to a Date, using the call Calendar.date(from:). It's the calendar's time zone that determines how those DateComponents are converted to a Date.
Instead of using Calendar.current, create a custom calendar and set it to the IRST time zone. (I couldn't figure out the time zone for Iran Daylight time. I would have expected it to have the abbreviation "IRDT", but that doesn't work.)
Let's say we have a calendar irstCalendar that's set to Iran Standard Time ("IRST").
If you use irstCalendar.date(from: dateComponents) you'll always get the Date based on standard time.
Consider this code:
func date(year: Int, month: Int, day: Int, hour: Int, minute: Int, second: Int, calendar: Calendar = Calendar.current) -> Date {
var dateComponents = DateComponents()
dateComponents.year = year
dateComponents.month = month
dateComponents.day = day
dateComponents.hour = hour
dateComponents.minute = minute
dateComponents.second = second
let date = calendar.date(from: dateComponents)!
return date
}
guard let tehranStandardTimeZone = TimeZone(abbreviation: "IRST") else {
fatalError("Can't create time zones")
}
var tehranSTCalendar = Calendar(identifier: .gregorian)
tehranSTCalendar.timeZone = tehranStandardTimeZone
let tehranDateFormatter = DateFormatter()
tehranDateFormatter.dateStyle = .medium
tehranDateFormatter.timeStyle = .medium
tehranDateFormatter.timeZone = tehranStandardTimeZone
let date1 = date(year: 2021, month: 09, day: 21, hour: 23, minute: 59, second: 59, calendar: tehranSTCalendar)
let date2 = date(year: 2021, month: 09, day: 22, hour: 00, minute: 00, second: 00, calendar: tehranSTCalendar)
let date3 = date(year: 2021, month: 09, day: 22, hour: 00, minute: 00, second: 01, calendar: tehranSTCalendar)
print("STEP 1: 2021 Sep 21 23:59:59 => \(date1.timeIntervalSince1970), \(tehranDateFormatter.string(from:date1))")
print("STEP 2: 2021 Sep 22 00:00:00 => \(date2.timeIntervalSince1970), \(tehranDateFormatter.string(from:date2))")
print("STEP 3: 2021 Sep 22 00:00:01 => \(date3.timeIntervalSince1970), \(tehranDateFormatter.string(from:date3))")
That outputs:
STEP 1: 2021 Sep 21 23:59:59 => 1632252599.0, Sep 21, 2021 at 11:59:59 PM
STEP 2: 2021 Sep 22 00:00:00 => 1632256200.0, Sep 22, 2021 at 12:00:00 AM
STEP 3: 2021 Sep 22 00:00:01 => 1632256201.0, Sep 22, 2021 at 12:00:01 AM

Get last 7 and next 7 days in date format in swift

I am trying to fill an array of type Date with 15 values, today, the 7 days prior, and the next 7 days. I'm having a hard time figuring out how to get the date. I tried implementing it like this:
func setupDates(){
//get date of 7 days prior to right now
for i in 1...15 {
//add a day per iteration
//append date to date array
}
}
I would suggest having a look at Calendar
It can be a little cumbersome, but generally has a lot of power to it
So you might do something like...
let anchor = Date()
let calendar = Calendar.current
let formatter = DateFormatter()
formatter.dateStyle = .long
formatter.timeStyle = .long
for dayOffset in -7...7 {
if let date = calendar.date(byAdding: .day, value: dayOffset, to: anchor) {
print(formatter.string(from: date))
}
}
nb: This was a simple playground test
Which will print something like...
October 1, 2021 at 10:22:05 AM GMT+10
October 2, 2021 at 10:22:05 AM GMT+10
October 3, 2021 at 10:22:05 AM GMT+11
October 4, 2021 at 10:22:05 AM GMT+11
October 5, 2021 at 10:22:05 AM GMT+11
October 6, 2021 at 10:22:05 AM GMT+11
October 7, 2021 at 10:22:05 AM GMT+11
October 8, 2021 at 10:22:05 AM GMT+11
October 9, 2021 at 10:22:05 AM GMT+11
October 10, 2021 at 10:22:05 AM GMT+11
October 11, 2021 at 10:22:05 AM GMT+11
October 12, 2021 at 10:22:05 AM GMT+11
October 13, 2021 at 10:22:05 AM GMT+11
October 14, 2021 at 10:22:05 AM GMT+11
October 15, 2021 at 10:22:05 AM GMT+11
nb: Today is the 8th
nbb: Your question title says "date format", but you're just trying to fill an array with Dates. The basic concept will work either way

Wrong date from components

So this is interesting:
po Calendar.default.date(from: DateComponents(year: 2022, month: 1, hour: 16, minute: 1, second: 1, weekday: 1, weekOfMonth: 1))
▿ Optional<Date>
▿ some : 2021-12-26 23:01:01 +0000
- timeIntervalSinceReferenceDate : 662252461.0
I'm expecting January 1st 2022, but I'm getting December 26th 2021? Why is it doing this? Am I doing something wrong?
It's because the date components you are providing are contradictory. You have weekDay 1 (which will probably be a Sunday or Monday, depending on your locale) but the 1 jan 2022 is a Saturday.
(you also used Calendar.default when I think you meant Calendar.current?)
If you take out the weekDay term you will get the correct answer:
Calendar.current.date(from: DateComponents(year: 2022, month: 1, hour: 16, minute: 1, second: 1, weekOfMonth: 1))
// "Jan 1, 2022 at 4:01 PM"
You could also remove the weekOfMonth term as it is superfluous when you are specifying the actual date.

Swift - Add N month to date

I have used the following code to generate dates between two dates. It works in all cases where the day of the month is less than 28.
extension Date {
public func addMonth(n: Int) -> Date {
let calendar = Calendar.current
return calendar.date(byAdding: .month, value: n, to: self)!
}
public func addYear(n: Int) -> Date {
let calendar = Calendar.current
return calendar.date(byAdding: .year, value: n, to: self)!
}
public var monthName: String {
let calendar = Calendar.current
let monthInt = calendar.component(.month, from: self)
return calendar.monthSymbols[monthInt-1]
}
}
var date = Date()
repeat {
date = date.addMonth(n: 1)
print("\(date) \(date.monthName) ")
} while date <= Date().addYear(n: 2)
Result
2020-07-30 13:31:14 +0000 July
2020-08-30 13:31:14 +0000 August
2020-09-30 13:31:14 +0000 September
2020-10-30 14:31:14 +0000 October
2020-11-30 14:31:14 +0000 November
2020-12-30 14:31:14 +0000 December
2021-01-30 14:31:14 +0000 January
2021-02-28 14:31:14 +0000 February
2021-03-28 13:31:14 +0000 March
2021-04-28 13:31:14 +0000 April
2021-05-28 13:31:14 +0000 May
2021-06-28 13:31:14 +0000 June
2021-07-28 13:31:14 +0000 July
2021-08-28 13:31:14 +0000 August
2021-09-28 13:31:14 +0000 September
2021-10-28 13:31:14 +0000 October
2021-11-28 14:31:14 +0000 November
2021-12-28 14:31:14 +0000 December
2022-01-28 14:31:14 +0000 January
2022-02-28 14:31:14 +0000 February
2022-03-28 13:31:14 +0000 March
2022-04-28 13:31:14 +0000 April
2022-05-28 13:31:14 +0000 May
2022-06-28 13:31:14 +0000 June
2022-07-28 13:31:14 +0000 July
Expected result
I expect the result to be either 28 or 30.
2020-07-30 13:31:14 +0000 July
2020-08-30 13:31:14 +0000 August
2020-09-30 13:31:14 +0000 September
2020-10-30 14:31:14 +0000 October
2020-11-30 14:31:14 +0000 November
2020-12-30 14:31:14 +0000 December
2021-01-30 14:31:14 +0000 January
2021-02-28 14:31:14 +0000 February
2021-03-30 13:31:14 +0000 March
2021-04-30 13:31:14 +0000 April
2021-05-30 13:31:14 +0000 May
2021-06-30 13:31:14 +0000 June
2021-07-30 13:31:14 +0000 July
2021-08-30 13:31:14 +0000 August
2021-09-30 13:31:14 +0000 September
2021-10-30 13:31:14 +0000 October
2021-11-30 14:31:14 +0000 November
2021-12-30 14:31:14 +0000 December
2022-01-30 14:31:14 +0000 January
2022-02-28 14:31:14 +0000 February
2022-03-30 13:31:14 +0000 March
2022-04-30 13:31:14 +0000 April
2022-05-30 13:31:14 +0000 May
2022-06-30 13:31:14 +0000 June
2022-07-30 13:31:14 +0000 July
Does Calendar has built-in functionality to achieve this?
As you observed, adding 1 month n times is not the same as adding n month. Apparently you want the latter, e.g. like this:
let now = Date()
let finalDate = now.addYear(n: 2)
for n in 1... {
let date = now.addMonth(n: n)
print("\(date) \(date.monthName) ")
if date > finalDate { break }
}
Or this:
let now = Date()
let finalDate = now.addYear(n: 2)
let dates = (1...).lazy.map { now.addMonth(n: $0) }
.prefix(while: { $0 <= finalDate } )
for date in dates {
print("\(date) \(date.monthName)")
}
You can use Calendar method nextDate(after:) passing previousTimePreservingSmallerComponents as the matchingPolicy:
public extension Date {
func noon(using calendar: Calendar = .current) -> Date {
calendar.date(bySettingHour: 12, minute: 0, second: 0, of: self)!
}
func day(using calendar: Calendar = .current) -> Int {
calendar.component(.day, from: self)
}
func adding(_ component: Calendar.Component, value: Int, using calendar: Calendar = .current) -> Date {
calendar.date(byAdding: component, value: value, to: self)!
}
func monthSymbol(using calendar: Calendar = .current) -> String {
calendar.monthSymbols[calendar.component(.month, from: self)-1]
}
}
var date = Date().noon() // "Jun 30, 2020 at 12:00 PM"
let day = date.day()
let endDate = date.adding(.year, value: 2)
repeat {
date = Calendar.current.nextDate(after: date, matching: DateComponents(day: day, hour: 12), matchingPolicy: .previousTimePreservingSmallerComponents)!
print(date.description(with: .current), date.monthSymbol())
} while date <= endDate
this will print:
Thursday, July 30, 2020 at 12:00:00 PM Brasilia Standard Time July
Sunday, August 30, 2020 at 12:00:00 PM Brasilia Standard Time August
Wednesday, September 30, 2020 at 12:00:00 PM Brasilia Standard Time September
Friday, October 30, 2020 at 12:00:00 PM Brasilia Standard Time October
Monday, November 30, 2020 at 12:00:00 PM Brasilia Standard Time November
Wednesday, December 30, 2020 at 12:00:00 PM Brasilia Standard Time December
Saturday, January 30, 2021 at 12:00:00 PM Brasilia Standard Time January
Sunday, February 28, 2021 at 12:00:00 PM Brasilia Standard Time February
Tuesday, March 30, 2021 at 12:00:00 PM Brasilia Standard Time March
Friday, April 30, 2021 at 12:00:00 PM Brasilia Standard Time April
Sunday, May 30, 2021 at 12:00:00 PM Brasilia Standard Time May
Wednesday, June 30, 2021 at 12:00:00 PM Brasilia Standard Time June
Friday, July 30, 2021 at 12:00:00 PM Brasilia Standard Time July
Monday, August 30, 2021 at 12:00:00 PM Brasilia Standard Time August
Thursday, September 30, 2021 at 12:00:00 PM Brasilia Standard Time September
Saturday, October 30, 2021 at 12:00:00 PM Brasilia Standard Time October
Tuesday, November 30, 2021 at 12:00:00 PM Brasilia Standard Time November
Thursday, December 30, 2021 at 12:00:00 PM Brasilia Standard Time December
Sunday, January 30, 2022 at 12:00:00 PM Brasilia Standard Time January
Monday, February 28, 2022 at 12:00:00 PM Brasilia Standard Time February
Wednesday, March 30, 2022 at 12:00:00 PM Brasilia Standard Time March
Saturday, April 30, 2022 at 12:00:00 PM Brasilia Standard Time April
Monday, May 30, 2022 at 12:00:00 PM Brasilia Standard Time May
Thursday, June 30, 2022 at 12:00:00 PM Brasilia Standard Time June
Saturday, July 30, 2022 at 12:00:00 PM Brasilia Standard Time July
edit/update:
If you need every nth month:
var date = Date().noon() // "Jun 30, 2020 at 12:00 PM"
let day = date.day()
let endDate = date.adding(.year, value: 2)
var dates: [Date] = []
let nthMonth = 3
var counter = 0
repeat {
counter += 1
date = Calendar.current.nextDate(after: date, matching: DateComponents(day: day, hour: 12), matchingPolicy: .previousTimePreservingSmallerComponents)!
if counter.isMultiple(of: nthMonth) {
dates.append(date)
print(date.description(with: .current), date.monthSymbol())
}
} while date <= endDate
This will print:
Wednesday, September 30, 2020 at 12:00:00 PM Brasilia Standard Time September
Wednesday, December 30, 2020 at 12:00:00 PM Brasilia Standard Time December
Tuesday, March 30, 2021 at 12:00:00 PM Brasilia Standard Time March
Wednesday, June 30, 2021 at 12:00:00 PM Brasilia Standard Time June
Thursday, September 30, 2021 at 12:00:00 PM Brasilia Standard Time September
Thursday, December 30, 2021 at 12:00:00 PM Brasilia Standard Time December
Wednesday, March 30, 2022 at 12:00:00 PM Brasilia Standard Time March
Thursday, June 30, 2022 at 12:00:00 PM Brasilia Standard Time June

Split last two hours in 10 minutes slices

I am trying to get every 10 minutes of the last hour.
For example, now is 15:46:41
I want [15:40:00, 15:30:00, 15:20:00, 15:10:00, 15:00:00, 14:50:00, 14:40:00, 14:30:00, 14:20:00, 14:10:00, 14:00:00, 13:50:00, 13:40:00]
let calendar = Calendar.current
let now = Date()
var components = DateComponents()
components.hour = -2
if let early = calendar.date(byAdding: components, to: now) {
let nowMin = calendar.component(.minute, from: early)
let diff = 10 - (nowMin % 10)
components.minute = diff
var minutes: [Int] = []
for _ in 0...13 {
// I cant figure out what should I do next.
}
print(minutes)
}
You can get now's minute, get the remainder of this value divided by ten and subtract it from that value. This way you get the last tenth hour minute, then you just need to set it with the same hour component to now to find out the first element of your array. Next you can fill the rest of dates subtracting 10 minutes times the element position from the start date. Try like this:
Xcode 11 • Swift 5.1 (for older versions just add the return statement as usual)
extension Date {
var hour: Int { Calendar.current.component(.hour, from: self) }
var minute: Int { Calendar.current.component(.minute, from: self) }
var previousHourTenth: Date { Calendar.current.date(bySettingHour: hour, minute: minute - minute % 10, second: 0, of: self)! }
func lastNthHourTenth(n: Int) -> [Date] { (0..<n).map { Calendar.current.date(byAdding: .minute, value: -10*$0, to: previousHourTenth)! } }
}
Playground testing
Date() // "Sep 25, 2019 at 10:19 AM"
Date().previousHourTenth // "Sep 25, 2019 at 10:10 AM"
Date().lastNthHourTenth(n: 13) // "Sep 25, 2019 at 10:10 AM", "Sep 25, 2019 at 10:00 AM", "Sep 25, 2019 at 9:50 AM", "Sep 25, 2019 at 9:40 AM", "Sep 25, 2019 at 9:30 AM", "Sep 25, 2019 at 9:20 AM", "Sep 25, 2019 at 9:10 AM", "Sep 25, 2019 at 9:00 AM", "Sep 25, 2019 at 8:50 AM", "Sep 25, 2019 at 8:40 AM", "Sep 25, 2019 at 8:30 AM", "Sep 25, 2019 at 8:20 AM", "Sep 25, 2019 at 8:10 AM"]
Now you just need to use DateFormatter to display those dates as needed to the user.

Resources