Sprint code generator using Swift

Sprint code generator using Swift

It's that time of the year again~ yes, the beginning of the year!

In work scope, I'm keeping track of my tickets like this:

## 23.52: 18-29 Dec
List of tickets done
## 23.50: 4-15 Dec
List of tickets done
## 23.48: 20 Nov - 1 Dec
List of tickets done
## 23.02: 2-13 Jan
List of tickets done

23.02 refers to the year 2023 and week 2 and so on until week 52.

There must be a smarter way to generate it using Swift code right! Here's the snippet that I run in Swift playground

import UIKit

var df = DateFormatter()
df.dateFormat = "dd-MMM-yy"

var startDate = df.date(from: "2-Jan-23")!
let endDate = df.date(from: "7-Jan-24")!

var sprints: [String] = []

while startDate <= endDate {
    let startSprint = startDate
    let endSprint = Calendar.current.date(byAdding: .day, value: 11, to: startDate)!

    let start = Calendar.current.dateComponents([.year, .day, .month], from: startSprint)
    let end = Calendar.current.dateComponents([.day, .month, .weekOfYear], from: endSprint)

    let startYear = String(start.year!).suffix(2)
    var output = String(format: "## %@.%02d: ", String(startYear), end.weekOfYear ?? 0)

    if start.month == end.month {
        let monthName = Calendar.current.shortMonthSymbols[end.month!-1]
        output += String(format: "%d-%d %@", start.day ?? 0, end.day ?? 0, monthName)
    } else {
        let startMonth = Calendar.current.shortMonthSymbols[start.month!-1]
        let endMonth = Calendar.current.shortMonthSymbols[end.month!-1]
        output += String(format: "%d %@ - %d %@", start.day ?? 0, startMonth, end.day ?? 0, endMonth)
    }

    startDate = Calendar.current.date(byAdding: .day, value: 14, to: startDate)!
    sprints.append(output)
}

for s in sprints.reversed() {
    print(s)
    print("\n")
}

Here's the code breakdown.

  1. Set a start and end date. I'm using DateFormatter to easily create 2 Date objects

  2. The start of the sprint is set to the startDate while the end of the sprint is 11 days after that. For example, start on Monday, 2 January and end on Friday, 13 January

let startSprint = startDate
let endSprint = Calendar.current.date(byAdding: .day, value: 11, to: startDate)!
  1. I need to split a date's components by year, day, month, and weekOfYear. The weekOfYear is taken from the end of the sprint date so it will be an even number.

  2. For the year, I only need the last 2 characters, which is 23. But because the dateComponents' year is an Int?, I need to convert it to String and use .suffix(2)

  3. I'll begin the String output with format specifiers so it will construct something like ## 23.02:

let start = Calendar.current.dateComponents([.year, .day, .month], from: startSprint)
let end = Calendar.current.dateComponents([.day, .month, .weekOfYear], from: endSprint)

let startYear = String(start.year!).suffix(2)
var output = String(format: "## %@.%02d: ", String(startYear), end.weekOfYear ?? 0)
  1. If a sprint happens in the same month, I want it to be displayed like 2-13 Jan. Otherwise, it should show 30 Jan - 10 Feb

  2. DateComponents for the month returns another Int?, use Calendar.current.shortMonthSymbols[start.month!-1] to get Jan, Feb, Mar, and so on

  3. Append output to the sprints String array

if start.month == end.month {
    let monthName = Calendar.current.shortMonthSymbols[end.month!-1]
    output += String(format: "%d-%d %@", start.day ?? 0, end.day ?? 0, monthName)
} else {
    let startMonth = Calendar.current.shortMonthSymbols[start.month!-1]
    let endMonth = Calendar.current.shortMonthSymbols[end.month!-1]
    output += String(format: "%d %@ - %d %@", start.day ?? 0, startMonth, end.day ?? 0, endMonth)
}

startDate = Calendar.current.date(byAdding: .day, value: 14, to: startDate)!
sprints.append(output)
  1. Finally, I'll print it in reversed for my note's template!
for s in sprints.reversed() {
    print(s)
    print("\n")
}

Phew, that was some good exercise! Playing with Date is always fun and forgetful if you don't juggle with it every day.

Initially, it's easier to think forward but step 9 was added after realising that I should arrange my note in reverse, so that it's easy to add more documentation :)

Looking as the bird view of this year, it feels like I'm already going to end 2023 year again. One year is really fast as you only have 26 sprints!

// not counted, generated in case the sprint crosses another year
## 24.02: 1-12 Jan 
## 23.52: 18-29 Dec
## 23.50: 4-15 Dec
## 23.48: 20 Nov - 1 Dec
## 23.46: 6-17 Nov
## 23.44: 23 Oct - 3 Nov
## 23.42: 9-20 Oct
## 23.40: 25 Sep - 6 Oct
## 23.38: 11-22 Sep
## 23.36: 28 Aug - 8 Sep
## 23.34: 14-25 Aug
## 23.32: 31 Jul - 11 Aug
## 23.30: 17-28 Jul
## 23.28: 3-14 Jul
## 23.26: 19-30 Jun
// mid of the year!
## 23.24: 5-16 Jun
## 23.22: 22 May - 2 Jun
## 23.20: 8-19 May
## 23.18: 24 Apr - 5 May
## 23.16: 10-21 Apr
## 23.14: 27 Mar - 7 Apr
## 23.12: 13-24 Mar
## 23.10: 27 Feb - 10 Mar
## 23.08: 13-24 Feb
## 23.06: 30 Jan - 10 Feb
## 23.04: 16-27 Jan
## 23.02: 2-13 Jan