TIL

TIL #7

wood0203 2023. 12. 24. 01:25

Overview

  1. Calendar 객체를 이용하여 달력 정보 받기
  2. Calendar, DateFormatter Localizaton 대응하기

1. Calendar 객체로 달력 정보 받기

네이버 캘린더의 달력을 보면, 첫째 주와 마지막 주에는 이전달과 다음달의 날짜가 포함되어 있다.
여기서, 이전 달이나 다음 달의 날짜를 선택하면 자동으로 캘린더가 넘어가게 된다.
해당 기능을 구현하기 위해 먼저 저번달과 다음달의 날짜 정보를 받아오도록 ,

Calendar 객체를 이용하여 구현하였다.

네이버 캘린더 화면

1. 먼저, 현재 날짜를 기반으로 이번달의 첫번째 날을 가져온다.

var calendar = Calendar(identifier: .gregorian)
calendar.locale = Locale(identifier: "ko_kr")

func getFirstDayOfMonth(from date: Date) -> Date {
  let todayYearMonthComponents: Set<Calendar.Component> = [
    Calendar.Component.year,
    Calendar.Component.month,
  ]
  let currentDate = date
  let firstDayOfThisMonthComponents = calendar.dateComponents(todayYearMonthComponents, from: currentDate)
  let firstDayOfThisMonth = calendar.date(from: firstDayOfThisMonthComponents)!
  return firstDayOfThisMonth
}

let firstDayOfThisMonth = getFirstDayOfMonth(from: Date.now)

2. 이번달 첫 번째 날의 weekday를 이용하여 첫째주에 포함된 저번달의 날짜를 얻는다.

func getLastMonthDays(from firstDay: Date) -> [Date] {
  let weekdayOfFirstDay = calendar.component(.weekday, from: firstDay)
  var lastMonth: [Date] = []
  let start = -weekdayOfFirstDay + 1

  for value in (start..<0) {
    let dayOfPreviousMonth = calendar.date(byAdding: .day, value: value, to: firstDay)!
    lastMonth.append(dayOfPreviousMonth)
  }

  return lastMonth
}

let lastMonthDays = getLastMonthDays(from: firstDayOfThisMonth)

3. 이번달에 해당하는 모든 날짜를 받는다.

func getThisMonth(from firstDay: Date) -> [Date] {
  let firstDayOfNextMonth = calendar.date(byAdding: .month, value: 1, to: firstDay)!
  let lastDayOfThisMonth = calendar.date(byAdding: .day, value: -1, to: firstDayOfNextMonth)!

  var thisMonth: [Date] = []
  let lastDayNumber = calendar.component(.day, from: lastDayOfThisMonth)
  for value in 0..<lastDayNumber {
    let dayOfThisMonth = calendar.date(byAdding: .day, value: value, to: firstDay)!
    thisMonth.append(dayOfThisMonth)
  }

  return thisMonth
}

let thisMonthDays = getThisMonth(from: firstDayOfThisMonth)

4. 마지막 주에 다음달에 해당하는 날짜를 얻는다.

func getNextMonth(from firstday: Date) -> [Date] {
  let firstDayOfNextMonth = calendar.date(byAdding: .month, value: 1, to: firstday)!
  let lastDayOfThisMonth = calendar.date(byAdding: .day, value: -1, to: firstDayOfNextMonth)!
  let weekdayOfLastMonth = calendar.component(.weekday, from: lastDayOfThisMonth)

  var nextMonth: [Date] = []
  let end = 7 - weekdayOfLastMonth
  for value in 0..<end {
    let dayOfNextMonth = calendar.date(byAdding: .day, value: value, to: firstDayOfNextMonth)!
    nextMonth.append(dayOfNextMonth)
  }

  return nextMonth
}

let nextMonthDays = getNextMonth(from: firstDayOfThisMonth)

5. 각 함수로 부터 받은 날짜들을 모두 합한다.

let currentCalendarMonth = lastMonthDays + thisMonthDays + nextMonthDays
print(currentCalendarMonth.count)
// 숫자가 7로 나누어 떨어지면 제대로 나온것이다!
// 정확환 확인을 위해서 각각의 변수들도 확인하길 추천한다.

2. DateFormatter, Calendar 객체 Localization 대응하기

달력의 종류를 검색해보면 중국력, 힌두력 등 달력이 많이 존재한다.

달력을 보여줄 때, 이러한 정보를 받아오려면 어떻게 해야할까? 고민을 하였다.

처음에는 사용자의 설정값에서 받아와야 하나.. 하고 막막했지만, 좋은 정보를 찾게되었다.

AutoupdatingCurret

공식문서의 설명부분을 보면 내용은 다음과 같다.

The locale is formed from the settings for the current user’s chosen system locale overlaid with any custom settings the user has specified.

Use this property when you want a locale that always reflects the latest configuration settings. When the user changes settings, a locale instance obtained from this property alters its behavior to match. If you need to rely on a locale that does not change, use the locale given by the current property instead.

Although the locale obtained here automatically follows the latest region settings, it provides no indication when the settings change. To receive notification of locale changes, add your object as an observer of currentLocaleDidChangeNotification.

 

요약하자면, 사용자가 설정한 지역정보를 받아와 가져와준다.
autoupdatingCurrent는 Locale의 타입 프로퍼티이며, 쉽게 가져올 수 있다.

 

let locale = Locale.autoupdatingCurrent

// DateFormatter 지역 설정
var dateFormatter = DateFormatter()
dateFormatter.locale = locale

// Calendar 지역 설정
var calendar = Calendar(identifier: .gregorian)
calendar.locale = locale

 

Swift의 Calendar에 유용한 기능들이 많이 존재한다. 이에 대해 자세히 공부할 예정이다.