Home > Blockchain >  Swift Get First Date of Month not working
Swift Get First Date of Month not working

Time:02-05

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.

  • Related