I am trying to get the month and year of a date so I can generate month sections in a table view. My plan is to create a dictionary of dates that contains the unique months per year (January 2022:[], January 2023:[]) as the keys, and then each item containing an array of all the dates
When I run the below code, it gets the first date of the month for some dates, but it seems to get the last date of the month for others and I cannot for the life of me figure out why.
Code
let dateList = ["2023-01-26 02:30:53 0000",
"2022-12-28 09:42:27 0000",
"2022-11-09 05:48:42 0000",
"2022-09-30 09:08:03 0000",
"2022-08-31 10:22:31 0000",
"2022-07-29 04:15:02 0000",
"2022-06-20 12:57:35 0000",
"2022-05-12 15:36:37 0000",
"2022-04-18 03:14:29 0000",
"2022-03-10 02:40:42 0000",
"2022-02-07 18:03:15 0000",
"2022-01-18 15:18:24 0000"]
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ssZ"
for dates in dateList {
let currentDate = dateFormatter.date(from:dates)!
let components = Calendar.current.dateComponents(
[.month, .year],
from: currentDate
)
let monthName = Calendar.current.monthSymbols[components.month!-1]
let year = components.year!
var dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd MM yyyy"
let month = Calendar.current.date(from: components)
print("\(currentDate) |||||", "\(month!) |||||", "\(components.month!-1) |||||", "\(year) \(monthName)")
}
Output
Original Date First Date of Month monthName
2023-01-26 02:30:53 0000 ||||| 2023-01-01 00:00:00 0000 ||||| 0 ||||| 2023 January
2022-12-28 09:42:27 0000 ||||| 2022-12-01 00:00:00 0000 ||||| 11 ||||| 2022 December
2022-11-09 05:48:42 0000 ||||| 2022-11-01 00:00:00 0000 ||||| 10 ||||| 2022 November
2022-09-30 09:08:03 0000 ||||| 2022-08-31 23:00:00 0000 ||||| 8 ||||| 2022 September
2022-08-31 10:22:31 0000 ||||| 2022-07-31 23:00:00 0000 ||||| 7 ||||| 2022 August
2022-07-29 04:15:02 0000 ||||| 2022-06-30 23:00:00 0000 ||||| 6 ||||| 2022 July
2022-06-20 12:57:35 0000 ||||| 2022-05-31 23:00:00 0000 ||||| 5 ||||| 2022 June
2022-05-12 15:36:37 0000 ||||| 2022-04-30 23:00:00 0000 ||||| 4 ||||| 2022 May
2022-04-18 03:14:29 0000 ||||| 2022-03-31 23:00:00 0000 ||||| 3 ||||| 2022 April
2022-03-10 02:40:42 0000 ||||| 2022-03-01 00:00:00 0000 ||||| 2 ||||| 2022 March
2022-02-07 18:03:15 0000 ||||| 2022-02-01 00:00:00 0000 ||||| 1 ||||| 2022 February
2022-01-18 15:18:24 0000 ||||| 2022-01-01 00:00:00 0000 ||||| 0 ||||| 2022 January
Expected Output
2023-01-26 02:30:53 0000 ||||| 2023-01-01 00:00:00 0000 ||||| 0 ||||| 2023 January
2022-12-28 09:42:27 0000 ||||| 2022-12-01 00:00:00 0000 ||||| 11 ||||| 2022 December
2022-11-09 05:48:42 0000 ||||| 2022-11-01 00:00:00 0000 ||||| 10 ||||| 2022 November
2022-09-30 09:08:03 0000 ||||| 2022-09-01 00:00:00 0000 ||||| 8 ||||| 2022 September
2022-08-31 10:22:31 0000 ||||| 2022-08-01 00:00:00 0000 ||||| 7 ||||| 2022 August
2022-07-29 04:15:02 0000 ||||| 2022-07-01 00:00:00 0000 ||||| 6 ||||| 2022 July
2022-06-20 12:57:35 0000 ||||| 2022-06-01 00:00:00 0000 ||||| 5 ||||| 2022 June
2022-05-12 15:36:37 0000 ||||| 2022-05-01 00:00:00 0000 ||||| 4 ||||| 2022 May
2022-04-18 03:14:29 0000 ||||| 2022-04-01 00:00:00 0000 ||||| 3 ||||| 2022 April
2022-03-10 02:40:42 0000 ||||| 2022-03-01 00:00:00 0000 ||||| 2 ||||| 2022 March
2022-02-07 18:03:15 0000 ||||| 2022-02-01 00:00:00 0000 ||||| 1 ||||| 2022 February
2022-01-18 15:18:24 0000 ||||| 2022-01-01 00:00:00 0000 ||||| 0 ||||| 2022 January
As you can see, September - April seem to have the wrong date created by the let month = Calendar.current.date(from: components)
.
Any ideas?
CodePudding user response:
Your code is perfectly fine.
The odd behaviour occurs because print
displays Date
instances always in UTC.
Either create a string with the DateFormatter
which does consider the current locale (recommended) or to fix the output of this code just replace the print
line with
print("\(currentDate) |||||", "\(month!.description(with: .current)) |||||", "\(components.month!-1) |||||", "\(year) \(monthName)")
.description(with: .current)
displays the Date
in the current locale.
CodePudding user response:
It's the localisation that's wrong. The date itself is correct, but the print outputs the date using your current timezone. Make sure to use the same date formatter in your print to get the same print result:
let dateFormatter = DateFormatter()
let dateList = ["2023-01-26 02:30:53 0000",
"2022-12-28 09:42:27 0000",
"2022-11-09 05:48:42 0000",
"2022-09-30 09:08:03 0000",
"2022-08-31 10:22:31 0000",
"2022-07-29 04:15:02 0000",
"2022-06-20 12:57:35 0000",
"2022-05-12 15:36:37 0000",
"2022-04-18 03:14:29 0000",
"2022-03-10 02:40:42 0000",
"2022-02-07 18:03:15 0000",
"2022-01-18 15:18:24 0000"]
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ssZ"
for dateString in dateList {
let currentDate = dateFormatter.date(from: dateString)!
let components = Calendar.current.dateComponents([.month, .year], from: currentDate)
let monthName = Calendar.current.monthSymbols[components.month!-1]
let year = components.year!
let monthDate = Calendar.current.date(from: components)
print("\(dateFormatter.string(from: currentDate)) |||||", "\(dateFormatter.string(from: monthDate!)) |||||", "\(components.month!-1) |||||", "\(year) \(monthName)")
}
CodePudding user response:
I think I figured out why I was getting the odd behaviour.
Using Calendar.current.date(from: components)
to create a date by only using the month and year creates a date that is the first hour of the month. I think what happens is that daylight savings time is then applied to that new date object, subtracting one hour for the dates that fall with the daylight savings period (March - October).
That explains why only April - September dates were only affected.
Changing the month constant to dateFormatter.date(from: "\(year)-\(components.month!)-01 00:00:00 0000")
gets the expected result that I am after, as you can see by the updated code below.
Code
var dateFormatter = DateFormatter()
let dateList = ["2023-01-26 02:30:53 0000",
"2022-12-28 09:42:27 0000",
"2022-11-09 05:48:42 0000",
"2022-09-30 09:08:03 0000",
"2022-08-31 10:22:31 0000",
"2022-07-29 04:15:02 0000",
"2022-06-20 12:57:35 0000",
"2022-05-12 15:36:37 0000",
"2022-04-18 03:14:29 0000",
"2022-03-10 02:40:42 0000",
"2022-02-07 18:03:15 0000",
"2022-01-18 15:18:24 0000",
"2022-09-30 09:08:03 0000",
"2022-08-31 10:22:31 0000",
"2022-07-29 04:15:02 0000",
"2022-06-20 12:57:35 0000",
"2022-05-12 15:36:37 0000",
"2022-04-18 03:14:29 0000",
"2023-01-26 02:30:53 0000"]
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ssZ"
for dates in dateList {
var calendar = Calendar.current
let currentDate = dateFormatter.date(from:dates)!
var components = calendar.dateComponents(
[.day, .month, .year],
from: currentDate
)
let monthName = calendar.monthSymbols[components.month!-1]
let year = components.year!
let month = dateFormatter.date(from: "\(year)-\(components.month!)-01 00:00:00 0000")
print("\(currentDate) |||||", "\(month!) |||||", "\(year) \(monthName)")
}
Output
2023-01-26 02:30:53 0000 ||||| 2023-01-01 00:00:00 0000 ||||| 2023-1-1 ||||| 2023 January
2022-12-28 09:42:27 0000 ||||| 2022-12-01 00:00:00 0000 ||||| 2022-12-1 ||||| 2022 December
2022-11-09 05:48:42 0000 ||||| 2022-11-01 00:00:00 0000 ||||| 2022-11-1 ||||| 2022 November
2022-09-30 09:08:03 0000 ||||| 2022-09-01 00:00:00 0000 ||||| 2022-9-1 ||||| 2022 September
2022-08-31 10:22:31 0000 ||||| 2022-08-01 00:00:00 0000 ||||| 2022-8-1 ||||| 2022 August
2022-07-29 04:15:02 0000 ||||| 2022-07-01 00:00:00 0000 ||||| 2022-7-1 ||||| 2022 July
2022-06-20 12:57:35 0000 ||||| 2022-06-01 00:00:00 0000 ||||| 2022-6-1 ||||| 2022 June
2022-05-12 15:36:37 0000 ||||| 2022-05-01 00:00:00 0000 ||||| 2022-5-1 ||||| 2022 May
2022-04-18 03:14:29 0000 ||||| 2022-04-01 00:00:00 0000 ||||| 2022-4-1 ||||| 2022 April
2022-03-10 02:40:42 0000 ||||| 2022-03-01 00:00:00 0000 ||||| 2022-3-1 ||||| 2022 March
2022-02-07 18:03:15 0000 ||||| 2022-02-01 00:00:00 0000 ||||| 2022-2-1 ||||| 2022 February
2022-01-18 15:18:24 0000 ||||| 2022-01-01 00:00:00 0000 ||||| 2022-1-1 ||||| 2022 January
2022-09-30 09:08:03 0000 ||||| 2022-09-01 00:00:00 0000 ||||| 2022-9-1 ||||| 2022 September
2022-08-31 10:22:31 0000 ||||| 2022-08-01 00:00:00 0000 ||||| 2022-8-1 ||||| 2022 August
2022-07-29 04:15:02 0000 ||||| 2022-07-01 00:00:00 0000 ||||| 2022-7-1 ||||| 2022 July
2022-06-20 12:57:35 0000 ||||| 2022-06-01 00:00:00 0000 ||||| 2022-6-1 ||||| 2022 June
2022-05-12 15:36:37 0000 ||||| 2022-05-01 00:00:00 0000 ||||| 2022-5-1 ||||| 2022 May
2022-04-18 03:14:29 0000 ||||| 2022-04-01 00:00:00 0000 ||||| 2022-4-1 ||||| 2022 April
2023-01-26 02:30:53 0000 ||||| 2023-01-01 00:00:00 0000 ||||| 2023-1-1 ||||| 2023 January
Thank you everyone for responding, I hope this helps someone else.