Date
날짜를 처리하는 다양한 자료형이 존재한다.
Class | Strcture |
NSDate NSCalendar NSDateComponents NSTimeZone NSLocale |
Date Calendat DateComponents TimeZone Locale |
예전엔 클래스로만 제공했지만 현행 코코아터치프레임워크는 구조체로도 제공하고 있다.
또한 이러한 자료형들은 클래스 자료형의 이름에서 NS를 제외한 이름을 가지고 있다.
이 둘은 이름과 구현 방식만 다를 뿐, 사용법과 동작 방식은 동일하거나 유사하고,
대부분의 자료형들이 브릿징을 지원하기때문에 타입캐스팅을 활용해 자유롭게 전환할 수 있다.
Date()
결과
"Aug 27, 2021 at 12:47 PM"
Date 생성자를 사용하면 위와 같은 날짜를 얻을 수 있다.
let date = Date()
print(date)
결과
2021-08-27 03:49:01 +0000
이것을 상수에 저장하고 출력하면 위와 같은 결과를 확인 할 수 있다.
시뮬레이터의 기본 언어 설정은 영어이고, 따라서 Date 생성자의 결과또한 시뮬레이터의 설정에 따라 출력된다.
하지만 print로 출력된 결과는 조금 다른데,
지역 설정에 관계 없이 UTC기준시에 따라 출력된다.
출력되는 것 외에도 여러 값들을 표현하고있으며, 이러한 값들은 특정한 기준시나 달력과는 독립적인 값이다.
이때 기준이 되는 날짜를 ReferenceDate라고 한다.
Reference Date
2001-01-01 00:00:00 / UTC
ReferenceDate에 숫자를 더하면 이후의 날짜가 되고, 빼면 이전의 날짜가 된다.
var dt = Date(timeIntervalSinceReferenceDate: 3600)
print(dt)
결과
"Jan 1, 2001 at 10:00 AM"
"2001-01-01 01:00:00 +0000\n"
Date생성자의 timeIntervalSinceReferenceDate속성에 초단위의 숫자를 전달하면
DeferenceDate기준에서 그 만큼 지난 시간을 반환해 준다.
3600초는 1시간이므로 ReferenceDate기준 1시간이 지난 '2001년 1월 1일 1시'가 출력된다.
이전 날짜는 반대로 음수를 전달한다.
TimeInterval
위에서 한 시간을 전달할 때 '1'이 아닌 '3600'을 전달한 이유는 TimeInterval을 사용하기 때문이다.
let onesec = TimeInterval(1)
결과
1
timeInterval의 기본 단위는 '초'이고, 1을 전달하면 1초가 된다.
public typealias TimeInterval = Double
하지만 실제 선언은 Double 형식의 typalias로 선언되어있다.
따라서 초보다 작은 단위를 표현하는 것이 가능하다.
let oneMsec = TimeInterval(0.001)
let oneMin = TimeInterval(60)
let oneHour1 = TimeInterval(oneMin * 60)
let oneHour2 = TimeInterval(60 * 60)
let oneHour3 = TimeInterval(3600)
let oneDay = TimeInterval(oneHour1 * 24)
결과
0.001
60
3600
3600
3600
86400
위처럼 여러 응용을 통해 단위 시간을 표현할 수 있다.
- Date()
현재 날짜를 생성할 때 사용한다. - Date(timeInterval:since:)
기준이 되는 날짜를 직접 지정할 때 사용한다. - Date(timeIntervalSince1970:)
'1970년 1월 1일 00시 00분 00초'를 기준으로 새 시간을 생성할 때 사용한다.
UNIX timestamp로 날짜를 만들어야 하는 경우 사용한다.
API서버에서 전달한 날짜를 parsing할 때 주로 사용한다. - Date(timeIntervalSinceNow:)
지금 시간을 기준으로 새 시간을 생성할 때 사용한다. - Date(timeIntervalSinceReferenceDate:)
Referencetime 기준으로 새 시간을 생성할 때 사용한다.
지금을 기준으로 얼마간 지난 시간을 표현하기 위해선 Date(timeIntercalSinceNow) 생성자를 사용한다.
let onesec = TimeInterval(1)
let oneMsec = TimeInterval(0.001)
let oneMin = TimeInterval(60)
let oneHour1 = TimeInterval(oneMin * 60)
let oneHour2 = TimeInterval(60 * 60)
let oneHour3 = TimeInterval(3600)
let oneDay = TimeInterval(oneHour1 * 24)
Date(timeIntervalSinceNow: oneDay)
결과
"Aug 28, 2021 at 3:16 PM"
위처럼 원하는 timeInterval을 전달해 주면 현재 시간에서 전달된 시간 만큼 지난 시간을 반환하게 된다.
Calendar and Date Components
한국만 해도 양력과 음력 달력 두가지를 사용하고,
전 세계적으로 다양한 달력이 존재한다.
따라서 Date에 저장되는 값으 특정 달력과 연관있는 값이 아닌 독립적인 값이다.
따라서 이를 계산하거나 표시하고 싶다면 특정 달력과 연관지어 표현해야한다.
달려은 Calendar 구조체로 구현되어있고, 'Calendar.identifier' 열거형 안에 선언되어있다.
public enum Identifier {
case gregorian
case buddhist
case chinese
case coptic
case ethiopicAmeteMihret
case ethiopicAmeteAlem
case hebrew
case iso8601
case indian
case islamic
case islamicCivil
case japanese
case persian
case republicOfChina
@available(macOS 10.10, iOS 8.0, *)
case islamicTabular
@available(macOS 10.10, iOS 8.0, *)
case islamicUmmAlQura
public static func == (a: Calendar.Identifier, b: Calendar.Identifier) -> Bool
public func hash(into hasher: inout Hasher)
public var hashValue: Int { get }
}
위와 같이 여러 종류의 달력이 선언되어있다.
Calendar.Identifier.gregorian
Calendar.current
Calendar.autoupdatingCurrent
선언되어 있는 달력을 명시적으로 사용해도 되고,
current 속성이나 autoupdatingCurrent 속성을 사용해 사용자의 설정 그대로 사용하는 것도 가능하다.
이름 그대로 autoupdatinfCurrent 속성은 유저가 달력을 바꾸면 자동으로 업데이트 한다는 차이점이 있다.
단, 유저가 달력을 자주 바꾸는 경우가 드믈기 때문에 current 속성이 더 자주 이용된다.
DateComponents
let now = Date()
let calendar = Calendar.current
calendar.dateComponents(Set<Calendar.Component>, from: now)
다시 말하지만 now에 저장된 Date값은 독립적인 값이기 때문에 calendar의 도움을 받아 속성에 접근해야한다.
calendar의 dateComponents 메소드를 사용해 접근할 component와 Date값을 전달한다.
public enum Component {
case era
case year
case month
case day
case hour
case minute
case second
case weekday
case weekdayOrdinal
case quarter
case weekOfMonth
case weekOfYear
case yearForWeekOfYear
case nanosecond
case calendar
case timeZone
public static func == (a: Calendar.Component, b: Calendar.Component) -> Bool
public func hash(into hasher: inout Hasher)
public var hashValue: Int { get }
}
dateComponents에는 위와 같이 연, 월, 일을 포함한 많은 컴포넌트가 선언되어있다.
let now = Date()
let calendar = Calendar.current
let components = calendar.dateComponents([.year, .month, .day], from: now)
components.year
components.month
components.day
결과
2021
8
27
여러개의 컴포넌트를 확인한다면 위처럼 dateComponents에 셋의 형태로 확인할 컴포넌트를 전달하면 되지만,
let year = calendar.component(.year, from: now)
year
결과
2021
굳이 그럴 필요가 없다면 componet(from:) 메소드를 사용해 접근한다.
timeInterval은 초단위로 값을 생성하기 때문에 특정 날짜를 만드는 것은 상당히 번거로운 일이다.
따라서 dateComponents를 원하는 값으로 채우고, Calendar가 제공하는 메소드를 사용해 만든다.
let calendar = Calendar.current
var customComponents = DateComponents()
customComponents.year = 2014
customComponents.month = 11
customComponents.day = 30
let custom = calendar.date(from: customComponents)
결과
"Nov 30, 2014 at 12:00 AM"
calendar와 새로 만들 component를 생성하고,
component에는 원하는 날짜를 저장한다.
이후 calendar에 존재하는 date(from:) 메소드를 사용해 날짜를 만들어 주면 끝이다.
Date Calculation
이번엔 calendar를 사용해 날짜계산을 해 본다.
extension Date {
init?(year: Int, month: Int, day: Int, hour: Int = 0, minute: Int = 0, second: Int = 0, calendar: Calendar = .current) {
var components = DateComponents()
components.year = year
components.month = month
components.day = day
components.hour = hour
components.minute = minute
components.day = day
guard let date = calendar.date(from: components) else {
return nil
}
self = date
}
}
let calendar = Calendar.current
let worldCup2002 = Date(year: 2002, month: 5, day: 31)!
2002년 월드컵 부터의 날짜를 계산하기 위해 월드컵 날짜를 저장한 데이터를 만든다.
extension Date {
init?(year: Int, month: Int, day: Int, hour: Int = 0, minute: Int = 0, second: Int = 0, calendar: Calendar = .current) {
var components = DateComponents()
components.year = year
components.month = month
components.day = day
components.hour = hour
components.minute = minute
components.day = day
guard let date = calendar.date(from: components) else {
return nil
}
self = date
}
}
let calendar = Calendar.current
let worldCup2002 = Date(year: 2002, month: 5, day: 31)!
let now = Date()
계산할 날짜는 오늘까지 이므로, Date 생성자를 사용해 현재의 날짜를 만든다.
이렇게 생성한 날짜는 시간을 포함하고 있는데, 시간을 포함한 경우와 포함하지 않는 경우의 계산 결과가 달라지게 된다.
따라서 시간을 포함할 것인지, 제외할 것인지를 결정해야한다.
extension Date {
init?(year: Int, month: Int, day: Int, hour: Int = 0, minute: Int = 0, second: Int = 0, calendar: Calendar = .current) {
var components = DateComponents()
components.year = year
components.month = month
components.day = day
components.hour = hour
components.minute = minute
components.day = day
guard let date = calendar.date(from: components) else {
return nil
}
self = date
}
}
let calendar = Calendar.current
let worldCup2002 = Date(year: 2002, month: 5, day: 31)!
let now = Date()
let today = calendar.startOfDay(for: now)
결과
"Aug 27, 2021 at 4:35 PM"
"Aug 27, 2021 at 12:00 AM"
만약 오늘을 기준으로 시간을 제외한다면 calendar의 startOfDay 메소드를 사용해 오늘의 시작 시간을 받아와야한다.
extension Date {
init?(year: Int, month: Int, day: Int, hour: Int = 0, minute: Int = 0, second: Int = 0, calendar: Calendar = .current) {
var components = DateComponents()
components.year = year
components.month = month
components.day = day
components.hour = hour
components.minute = minute
components.day = day
guard let date = calendar.date(from: components) else {
return nil
}
self = date
}
}
let calendar = Calendar.current
let worldCup2002 = Date(year: 2002, month: 5, day: 31)!
let now = Date()
let today = calendar.startOfDay(for: now)
var customD = DateComponents()
customD.day = 100
다시 새로운 components를 만들고 해당 컴포넌트에 계산할 날짜를 저장한다.
extension Date {
init?(year: Int, month: Int, day: Int, hour: Int = 0, minute: Int = 0, second: Int = 0, calendar: Calendar = .current) {
var components = DateComponents()
components.year = year
components.month = month
components.day = day
components.hour = hour
components.minute = minute
components.day = day
guard let date = calendar.date(from: components) else {
return nil
}
self = date
}
}
let calendar = Calendar.current
let worldCup2002 = Date(year: 2002, month: 5, day: 31)!
let now = Date()
let today = calendar.startOfDay(for: now)
var customD = DateComponents()
customD.day = 100
calendar.date(byAdding: customD, to: now)
calendar.date(byAdding: customD, to: today)
결과
"Dec 5, 2021 at 6:07 PM"
"Dec 5, 2021 at 12:00 AM"
이후엔 calendar의 date(byAdding:to:) 메소드를 사용해 날짜를 계산한다.
또한, 앞서 말한 것과 같이 두 계산의 결과가 다른 것을 확인할 수 있다.
이 차이는 day가 아닌 다른 컴포넌트를 포함할 시에 더 명확히 확인할 수 있다.
extension Date {
init?(year: Int, month: Int, day: Int, hour: Int = 0, minute: Int = 0, second: Int = 0, calendar: Calendar = .current) {
var components = DateComponents()
components.year = year
components.month = month
components.day = day
components.hour = hour
components.minute = minute
components.day = day
guard let date = calendar.date(from: components) else {
return nil
}
self = date
}
}
let calendar = Calendar.current
let worldCup2002 = Date(year: 2002, month: 5, day: 31)!
let now = Date()
let today = calendar.startOfDay(for: now)
var customD = DateComponents()
customD.day = 100
customD.hour = 13
calendar.date(byAdding: customD, to: now)
calendar.date(byAdding: customD, to: today)
결과
"Dec 6, 2021 at 7:12 AM"
"Dec 5, 2021 at 1:00 PM"
위와 같이 영 다른 결과가 나타나게 된다.
이는 기준시에 따른 차이이므로 주의해야 할 필요가 있다.
extension Date {
init?(year: Int, month: Int, day: Int, hour: Int = 0, minute: Int = 0, second: Int = 0, calendar: Calendar = .current) {
var components = DateComponents()
components.year = year
components.month = month
components.day = day
components.hour = hour
components.minute = minute
components.day = day
guard let date = calendar.date(from: components) else {
return nil
}
self = date
}
}
let calendar = Calendar.current
let worldCup2002 = Date(year: 2002, month: 5, day: 31)!
let today = calendar.startOfDay(for: now)
var customD = DateComponents()
customD = calendar.dateComponents([.day], from: worldCup2002, to: today)
cusromD.day
결과
7028
월드컵 개최일은 시간에 해당하는 정보가 없으므로, 계산을 할 날짜도 시간아 없는 startOfDay메소드를 적용한 날짜를 사용한다.
두 날짜를 비교해 결과를 확인하기 위해서는 calendar의 dateComponents(from:to:)메소드를 사용하는데,
확인할 컴포넌트는 위와같이 셋으로 전달한다.
TimeZone
Date 형식은 기본 상태에서 UTC 기준시에 따라 처리된다.
한국 기준시는 Korean Standard Time으로 KST라고 부른다.
이 둘은 9시간의 차이가 발생한다.
따라서 이를 그대로 사용하는 것은 불편함을 초례할 수 있다.
print(TimeZone.knownTimeZoneIdentifiers.count)
결과
439
iOS에서 지원하는 시간대는 총 439개로,
한국 기준시의 이름은 Asia/Seoul 이다.
또한, 이를 별도로 설정하지 않는다면 iOS의 기본시를 사용한다.
let calendar = Calendar.current
var components = DateComponents()
components.year = 2014
components.month = 4
components.day = 16
이번엔 위처럼 이미 만들어진 Date를 한국 기준시로 바꿔보고 비교해 보도록 한다.
let calendar = Calendar.current
var components = DateComponents()
components.year = 2014
components.month = 4
components.day = 16
components.timeZone = TimeZone(identifier: "Asia/Seoul")
calendar.date(from: components)
components.timeZone = TimeZone(identifier: "America/Los_Angeles")
calendar.date(from: components)
결과
"Apr 16, 2014 at 12:00 AM"
"Apr 16, 2014 at 4:00 PM"
DateComponents의 timeZone 속성에 시간대를 할당하면 해당 시간대가 적용된 시간을 얻을 수 있다.
Date Picker
iOS 내에서 날짜를 선택할 때는 DatePicker를 사용한다.
비슷한 이름의 PickerView와 달리 데이터를 입력하는 코드를 직접 작성할 필요는 없다.
대신 DatePickerMode 라는 속성으로 표시할 데이터를 선택하고, 선택 이벤트는 TargetAction 방식으로 구현한다.
//
// DatePickerViewController.swift
// HandlingDate
//
// Created by Martin.Q on 2021/08/27.
//
import UIKit
class DatePickerViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
}
사용할 씬과 코드는 위와 같다.
라이브러리에서 Date Picker를 선택에 씬에 추가한다.
DatePicker는 사이즈를 조절할 수는 있지만 보통 너비는 화면에 꽉 채우고,
높이는 기본 높이를 사용한다.
DatePicker의 attribute inspector는 위와 같다.
가장 첫번째인 Preffered Style은 iOS 13.4에서 새롭게 추가됐고,
Automatic으로 설정하는 경우 Mode 속성에 따라 자동으로 레이아웃을 표시한다.
iOS 13.3 까지는 씬에 표시되는 것과 같이 Wheel 방식만 제공하지만,
iOS14 시뮬레이터에서는 다른 레이아웃을 보여주는 것을 확인 할 수 있다.
해당 레이아웃은 Compact Style이다.
단, Compact Style은 앱의 너비를 전부 채우지 못하기 때문에 제약오류가 발생할 수도 있어 주의해야 한다.
Inline Style은 달력과 함께 시간을 선택할 수 있는 레이아웃을 표시한다.
Deployment target이 iOS 13.4 버전 이상이라면 원하는 레이아웃을 선택해 사용해도 괜찮지만,
그 이하의 버전까지 지원해야 한다면 Wheel 스타일을 선택한다.
//
// DatePickerViewController.swift
// HandlingDate
//
// Created by Martin.Q on 2021/08/27.
//
import UIKit
class DatePickerViewController: UIViewController {
@IBOutlet weak var datePicker: UIDatePicker!
override func viewDidLoad() {
super.viewDidLoad()
}
}
코드로 스타일을 지정하기 위해서는 코드에 outlet으로 연결해야한다.
override func viewDidLoad() {
super.viewDidLoad()
datePicker.preferredDatePickerStyle = .wheels
}
datePicker의 스타일을 설정하기 위해선 preferredDatePickerStyle 속성에 접근해야한다.
하지만 해당 속성 자체가 iOS 13.4 이상에서나 지원하는 속성이기 때문에 버전에 따라 분기해 줄 필요가 있다.
override func viewDidLoad() {
super.viewDidLoad()
if #available(iOS 13.4, *) {
datePicker.preferredDatePickerStyle = .wheels
} else {
// Fallback on earlier versions
}
}
이렇게 수정하면 컴파일 에러는 사라진다.
Mode 속성은 DatePicker가 동작할 방식을 결정한다.
결과
각각의 Mode에 따른 레이아웃 변화는 위와 같다.
override func viewDidLoad() {
super.viewDidLoad()
if #available(iOS 13.4, *) {
datePicker.preferredDatePickerStyle = .wheels
} else {
// Fallback on earlier versions
}
datePicker.datePickerMode = .dateAndTime
}
코드로 설정할 때는 datePickerMode 속성으로 설정한다.
Locale 설정이 Default로 되어있으면 디바이스의 언어 설정을 따른다.
override func viewDidLoad() {
super.viewDidLoad()
if #available(iOS 13.4, *) {
datePicker.preferredDatePickerStyle = .wheels
} else {
// Fallback on earlier versions
}
datePicker.datePickerMode = .dateAndTime
datePicker.locale = Locale(identifier: "ko_kr")
}
코드로 설정할 때는 locale 속성으로 설정한다.
전달하는 값은 Locale(identifier:) 생성자로 ko_kr과 같이 해당하는 locale을 생성해 전달한다.
결과
Interval 속성은 항목간의 간격을 설정한다.
override func viewDidLoad() {
super.viewDidLoad()
if #available(iOS 13.4, *) {
datePicker.preferredDatePickerStyle = .wheels
} else {
// Fallback on earlier versions
}
datePicker.datePickerMode = .dateAndTime
datePicker.locale = Locale(identifier: "ko_kr")
datePicker.minuteInterval = 3
}
코드로는 minuteInterval 속성으로 설정하며, 1 ~ 30 사이의 60의 약수인 정수형태로 설정할 수 있다.
만약 60의 약수가 아니라면 1분으로 대체되어 사용된다.
결과
Date는 처음에 표시할 날짜와 시간을 선택한다.
기본값인 Current Date는 현재의 날짜와 시간을 사용하고,
Custom을 사용하면 별도의 날짜와 시간으로 설정할 수 있다.
함께 있는 Minimum Date와 Maximum Date는 선택 범위를 설정한다.
이 때 Minimum Date는 반드시 Maximum Date보다 작아야한다.
Date와 관련된 속성들은 timer mode일 때는 사용되지 않는다.
override func viewDidLoad() {
super.viewDidLoad()
if #available(iOS 13.4, *) {
datePicker.preferredDatePickerStyle = .wheels
} else {
// Fallback on earlier versions
}
datePicker.datePickerMode = .dateAndTime
datePicker.locale = Locale(identifier: "ko_kr")
datePicker.minuteInterval = 3
datePicker.date = Date()
}
datePicker의 date 속성은 Date 형식의 데이터를 전달해 설정한다.
datePicker.setDate(Date(), animated: true)
애니메이션을 적용하고 싶다면 위와 같은 형태로 설정한다.
datePicker.minimumDate = Date()
datePicker.maximumDate = Date()
범위는 minimumDate와 maximumDate 속성으로 설정할 수 있다.
이 외에도 DatePicker가 사용할 시간대와 캘린더를 설정할 수 있는데,
이는 코드로만 설정할 수 있다.
datePicker.calendar = Calendar.current
datePicker.timeZone = TimeZone.current
이 둘은 DatePicker 내의 같은 이름의 속성으로 설정한다.
DatePicker에서 원하는 항목을 선택하면 ValueChanged 이벤트가 발생하고,
이 이벤트를 처리하고자 한다면 Action을 연결해야 한다.
@IBAction func datePickerAction(_ sender: UIDatePicker) {
print(sender.date)
}
Action으로 연결하고 sender는 UIDatePicker를 선택한다.
UIDatePicker가 반환하는 날짜를 받기 위해 sender의 date속성에 접근해 이를 출력하도록 했다.
결과
값을 잘 받아와 출력하는 것을 볼 수 있다.
DatePicker가 ValueChanged 이벤트를 호출하는 것은, 움직임을 멈추고 하나의 항목을 선택했을 시점이다.
또한 출력되는 데이터는 사용자에게 불친절한 데이터이기 때문에 DateFormatter를 사용해 친숙하게 바꿔 사용하게 된다.
Countdown Timer
//
// CountDownTimerViewController.swift
// HandlingDate
//
// Created by Martin.Q on 2021/08/27.
//
import UIKit
class CountDownTimerViewController: UIViewController {
@IBOutlet weak var label: UILabel!
@IBOutlet weak var datePicker: UIDatePicker!
@IBAction func datePickerAction(_ sender: UIDatePicker) {
}
@IBAction func StartAction(_ sender: Any) {
}
override func viewDidLoad() {
super.viewDidLoad()
if #available(iOS 13.4, *) {
datePicker.preferredDatePickerStyle = .wheels
} else {
// Fallback on earlier versions
}
datePicker.datePickerMode = .countDownTimer
}
}
사용할 씬과 연결된 코드는 위와 같다.
datePicker의 스타일은 wheel로 고정하고, Mode는 countDownTimer로 설정했다.
결과
그리고 시뮬레이터를 확인해 보면 초기값이 0분으로 되어있고, 0분으로 설정하려 해도 선택되지 않는다.
countDownTimer의 최솟값은 1분이고, 사용할 수 있는 최대값은 23시간 59분이다.
override func viewDidLoad() {
super.viewDidLoad()
if #available(iOS 13.4, *) {
datePicker.preferredDatePickerStyle = .wheels
} else {
// Fallback on earlier versions
}
datePicker.datePickerMode = .countDownTimer
datePicker.countDownDuration = 300
}
초기값을 변경하고 싶다면 countDownDuration 속성에 초단위로 전달한다.
결과
다시말해 위에서 코드로 설정한 300은 5분이 된다.
@IBAction func StartAction(_ sender: Any) {
label.text = "\(Int(datePicker.countDownDuration))"
}
이제는 DatePicker에서 선택한 값을 label에 표시한다.
countDownTimer는 이름과는 다르게 카운트다운을 직접 처리하지는 못한다.
따라서 기능 자체는 timer를 사용해 직접 구현해야한다.
@IBAction func StartAction(_ sender: Any) {
label.text = "\(Int(datePicker.countDownDuration))"
remain = Int(datePicker.countDownDuration)
}
var remain = 0
남은 시간을 저장할 변수를 만든 뒤, 시작 버튼을 누르면 countDownPicker의 값을 해당 변수에 저장한다.
@IBAction func StartAction(_ sender: Any) {
label.text = "\(Int(datePicker.countDownDuration))"
remain = Int(datePicker.countDownDuration)
Timer.scheduledTimer(withTimeInterval: TimeInterval, repeats: Bool, block: (Timer) -> Void)
}
또한 타이머를 구현하기 위해 Timer 클래스의 scheduledTimer(withTimeInterval:repats:block:)메소드를 사용한다.
- withTimerInterval
반복 주기를 설정한다. - repeats
반복 여부를 결정한다. - blcok
실행할 코드를 전달한다.
@IBAction func StartAction(_ sender: Any) {
label.text = "\(Int(datePicker.countDownDuration))"
remain = Int(datePicker.countDownDuration)
Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { (timer) in
self.remain -= 1
self.label.text = "\(self.remain)"
}
}
따라서 1초마다 반복하며 남은 시간을 1씩 줄이도록 구현했다.
@IBAction func StartAction(_ sender: Any) {
label.text = "\(Int(datePicker.countDownDuration))"
remain = Int(datePicker.countDownDuration)
Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { (timer) in
self.remain -= 1
self.label.text = "\(self.remain)"
if self.remain == 0 {
timer.invalidate()
AudioServicesPlaySystemSound(1315)
}
}
}
그렇게 반복하다가 남은 시간이 0이 되면,
invalidate() 메소드로 타이머를 종료하고,
AudioServicesPlaySystemSound 메소드를 통해 알림음을 재생한다.
알림음 재생을 위해서는
import AudioToolbox
AudioToolbox를 반드시 import 해 줘야한다.
결과
Date Formatter
let now = Date()
print(now)
결과
2021-08-29 09:31:12 +0000
Date형식의 데이터를 그대로 출력하게 되면 위와 같은 형태로 출력된다.
이는 충분한 양의 데이터를 가지고 있지만, 실제 사용자에게 제공할 만한 형태는 아니다.
따라서 제공할 만한 형식의 문자열로 바꾸어야 하는데, 이때 사용하는 것이 DateFormatter이다.
let formatter = DateFormatter()
formatter.dateStyle = .full
formatter.timeStyle = .medium
DateFormatter는 새로운 인스턴스를 만든 후 이미 선언되어있는 형식을 사용하거나,
원하는 형식을 직접 작성하여 적용할 수 있다.
이미 선언되어있는 형식을 사용하는 경우 날짜와 시간의 형식을 별도로 설정해 줘야한다.
full, long, medium, short, none의 다섯가지 선택지를 제공한다.
none을 사용할 경우 해당 부분은 문자열에 포함되지 않는다.
dateStyle과 timeStyle 모두 기본값이 none이기 때문에 둘 중 하나는 반드시 none이 아닌 값으로 설정해야한다.
var result = formatter.string(from: now)
print(result)
결과
Sunday, August 29, 2021 at 6:38:45 PM
이렇게 설정한 formatter의 string 메소드를 사용해 해당 형식의 문자열로 변환해 출력하면,
사용자에게 제공하기 적절한 형태의 데이터가 출력된다.
let now = Date()
let formatter = DateFormatter()
formatter.dateStyle = .full
formatter.timeStyle = .medium
formatter.locale = Locale(identifier: "ko_kr")
var result = formatter.string(from: now)
print(result)
결과
2021년 8월 29일 일요일 오후 6:42:02
formatter의 언어설정을 해주지 않으면 기본 설정인 영문으로 변환된다.
적절한 언어를 locale 속성에 전달해 해당 언어로 변환하도록 할 수 있다.
formatter.string(for: now)
만약 formatter가 전달받는 파라미터가 optional이라면 string(from:)이 아닌 string(for:)메소드를 사용해야한다.
DateFormatter.localizedString(from: now, dateStyle: .full, timeStyle: .medium)
만약 DateFormatter를 반복적으로 사용할 필요가 없는 경우,
인스턴스를 생성하지 않고, 위와 같이 Class 함수를 사용할 수 있다.
Custom Format
직접 형식을 지정할 때는 UnicodeDateFormatPattern에 선언되어있는 문자를 사용해야한다.
Era
== en_US ==============
G AD
GG AD
GGG AD
GGGG Anno Domini
GGGGG A
== ko_KR ==============
G AD
GG AD
GGG AD
GGGG 서기
GGGGG AD
Year
== en_US ==============
y 2021
yy 21
yyy 2021
yyyy 2021
yyyyy 02021
Y 2021
YY 21
YYY 2021
YYYY 2021
YYYYY 02021
u 2021
uu 21
uuu 2021
uuuu 2021
uuuuu 02021
U 2021
UU 21
UUU 2021
UUUU 2021
UUUUU 02021
== ko_KR ==============
y 2021년
yy 21년
yyy 2021년
yyyy 2021년
yyyyy 02021년
Y 2021년
YY 21년
YYY 2021년
YYYY 2021년
YYYYY 02021년
u 2021년
uu 21년
uuu 2021년
uuuu 2021년
uuuuu 02021년
U 2021년
UU 21년
UUU 2021년
UUUU 2021년
UUUUU 02021년
Quarter
== en_US ==============
q 3
qq 03
qqq Q3
qqqq 3rd quarter
Q 3
QQ 03
QQQ Q3
QQQQ 3rd quarter
== ko_KR ==============
q 3
qq 03
qqq 3분기
qqqq 제 3/4분기
Q 3
QQ 03
QQQ 3분기
QQQQ 제 3/4분기
Month
== en_US ==============
M 8
MM 08
MMM Aug
MMMM August
MMMMM A
L 8
LL 08
LLL Aug
LLLLL A
LLLLL A
== ko_KR ==============
M 8월
MM 08월
MMM 8월
MMMM 8월
MMMMM 8월
L 8월
LL 08월
LLL 8월
LLLLL 8월
LLLLL 8월
Day
== en_US ==============
d 29
dd 29
D 241
DD 241
DDD 241
F 5
== ko_KR ==============
d 29일
dd 29일
D 241
DD 241
DDD 241
F 5
Week Day
== en_US ==============
E Sun
EE Sun
EEE Sun
EEEE Sunday
EEEEE S
e Sun
ee 1
eee Sun
eeee Sunday
eeeee S
c Sun
cc 1
ccc Sun
cccc Sunday
ccccc S
== ko_KR ==============
E 일
EE 일
EEE 일
EEEE 일요일
EEEEE 일
e 일
ee 1
eee 일
eeee 일요일
eeeee 일
c 일
cc 1
ccc 일
cccc 일요일
ccccc 일
Week
== en_US ==============
w 36
ww 36
W 5
== ko_KR ==============
w 36
ww 36
W 5
Period
== en_US ==============
a PM
== ko_KR ==============
a 오후
Hour
== en_US ==============
h 6 PM
hh 6 PM
H 18
HH 18
== ko_KR ==============
h 오후 6시
hh 오후 6시
H 18시
HH 18시
Minute
== en_US ==============
m 56
mm 56
== ko_KR ==============
m 56
mm 56
Second
== en_US ==============
s 19
ss 19
S 4
SS 44
SSS 446
SSSS 4460
SSSSS 44600
A 68239446
AA 68239446
AAA 68239446
AAAA 68239446
AAAAA 68239446
== ko_KR ==============
s 19
ss 19
S 4
SS 44
SSS 446
SSSS 4460
SSSSS 44600
A 68239446
AA 68239446
AAA 68239446
AAAA 68239446
AAAAA 68239446
Zone
== en_US ==============
z GMT+9
zz GMT+9
zzz GMT+9
zzzz Korean Standard Time
Z +0900
ZZ +0900
ZZZ +0900
ZZZZ GMT+09:00
ZZZZZ +09:00
v South Korea Time
vvvv Korean Standard Time
V krsel
VVVV South Korea Time
== ko_KR ==============
z GMT+9
zz GMT+9
zzz GMT+9
zzzz 대한민국 표준시
Z +0900
ZZ +0900
ZZZ +0900
ZZZZ GMT+09:00
ZZZZZ +09:00
v 대한민국 시간
vvvv 대한민국 표준시
V krsel
VVVV 대한민국 시간
문자의 종류와 결과는 위와 같다.
formatter.setLocalizedDateFormatFromTemplate("yyyyMMMMdE")
DateFormatter에 지역화되는 Date 양식을 만들기 위해서는 setLocalizedDateFormatFromTemplate 메소드를 사용한다.
let now = Date()
let formatter = DateFormatter()
formatter.setLocalizedDateFormatFromTemplate("yyyyMMMMdE")
formatter.locale = Locale(identifier: "ko-kr")
var result = formatter.string(from: now)
print(result)
formatter.locale = Locale(identifier: "en-us")
result = formatter.string(from: now)
print(result)
결과
일, 8월 29, 2021
Sun, August 29, 2021
변화를 보기 위해 한국과 미국으로 각각 변환하고, 이를 출력하면
언어만 다르게 나올 뿐, 출력 형식 자체는 동일하다.
이는 Date 형식이 Locale에 맞게 업데이트 되지 않았기 때문으로,
사용한 메소드는 단순히 전달 된 문자열을 현재 Locale에 적합한 포맷 문자열로 바꾸어 인스턴스에 저장한다.
따라서 Locale을 바꿨다고 저장되어있는 포맷문자열이 업데이트 되지는 않는다.
따라서 Locale을 바꾼 후 해당 메소드를 다시 호출해야할 필요가 있다.
let now = Date()
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "ko-kr")
formatter.setLocalizedDateFormatFromTemplate("yyyyMMMMdE")
var result = formatter.string(from: now)
print(result)
formatter.locale = Locale(identifier: "en-us")
formatter.setLocalizedDateFormatFromTemplate("yyyyMMMMdE")
result = formatter.string(from: now)
print(result)
결과
2021년 8월 29일 (일)
Sun, August 29, 2021
이제는 Locale 설정에 맞는 형식으로 변환됐다.
print(formatter.dateFormat)
결과
Optional("EEE, MMMM d, yyyy")
실제 사용하는 문자열은 DateFormat 속성을 통해 확인할 수 있다.
formatter.dateFormat = "yyyyMMMMde"
print(formatter.string(from: now))
결과
2021August291
또한 해당 속성에 원하는 문자열을 설정할 수도 있다.
이는 Locale에 따르지 않고 고정된 형식으로 사용해야 하는 겨우 사용된다.
Relative Date Formatting
날짜는 기본적으로 년, 월, 일로 출력되는데, 현재를 기준으로 상대적인 표현으로 출력하는 방법또한 존재한다.
let now = Date()
let yesterday = now.addingTimeInterval(3600 * -24)
let tomorrow = now.addingTimeInterval(3600 * 24)
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "ko_KR")
formatter.dateStyle = .full
formatter.timeStyle = .none
print(formatter.string(from: now))
print(formatter.string(from: yesterday))
print(formatter.string(from: tomorrow))
결과
2021년 8월 29일 일요일
2021년 8월 28일 토요일
2021년 8월 30일 월요일
위와 같이 일반적인 형태로 출력되던 날짜들이
let now = Date()
let yesterday = now.addingTimeInterval(3600 * -24)
let tomorrow = now.addingTimeInterval(3600 * 24)
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "ko_KR")
formatter.dateStyle = .full
formatter.timeStyle = .none
formatter.doesRelativeDateFormatting = true
print(formatter.string(from: now))
print(formatter.string(from: yesterday))
print(formatter.string(from: tomorrow))
결과
오늘
어제
내일
doesRelativeDateFormatting 속성을 참으로 설정하면
위와 같이 상대적인 형태로 날짜를 표시한다.
해당 속성은 48시간 이내의 날짜를 그저께, 어제, 오늘, 내일, 모레로 변환해 표현한다.
Symbols
DateFormatter는 변환 과정에서 지정된 심볼을 사용한다.
기본 심볼을 주로 사용하지만 직접 지정하는 것이 가능하다.
let now = Date()
let weekdaySymbols = ["☀️", "🌕", "🔥", "💧", "🌲", "🥇", "🌏"]
let am = "🌅"
let pm = "🌇"
let formatter = DateFormatter()
formatter.dateStyle = .full
formatter.timeStyle = .full
print(formatter.string(from: now))
formatter.amSymbol = am
formatter.pmSymbol = pm
print(formatter.string(from: now))
결과
Sunday, August 29, 2021 at 7:23:41 PM Korean Standard Time
Sunday, August 29, 2021 at 7:23:41 🌇 Korean Standard Time
사용할 이미지를 불러와 해당 심볼로 지정해주면 된다.
DateFormatter에서는 위와 같이 많은 항목에 심볼을 사용할 수 있도록 제공하고있다.
let now = Date()
let weekdaySymbols = ["☀️", "🌕", "🔥", "💧", "🌲", "🥇", "🌏"]
let am = "🌅"
let pm = "🌇"
let formatter = DateFormatter()
formatter.dateStyle = .full
formatter.timeStyle = .full
print(formatter.string(from: now))
formatter.amSymbol = am
formatter.pmSymbol = pm
print(formatter.string(from: now))
formatter.weekdaySymbols = weekdaySymbols
print(formatter.string(from: now))
결과
Sunday, August 29, 2021 at 7:23:41 PM Korean Standard Time
Sunday, August 29, 2021 at 7:23:41 🌇 Korean Standard Time
☀️, August 29, 2021 at 7:23:41 🌇 Korean Standard Time
여러 속성들도 동일하게 작동한다.
Date String Parsing
문자열로 저장되어있는 날짜를 Date 형식으로 parsing해 본다.
이 때는 DateFormatter의 dateFormat 형식으로 날짜의 형식을 정확히 지정해야한다.
let str = "2017-09-02T09:30:00Z"
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-ddTHH:mm:ssZ"
if let date = formatter.date(from: str) {
formatter.dateStyle = .full
formatter.timeStyle = .full
print(formatter.string(from: date))
} else {
print("Invalid")
}
결과
Invalid
date(from:)메소드를 통해 문자열을 date형식으로 바꾸는 경우 optional에 대비해 value binding 형식으로 구현한다.
DateFormatter에 문자열의 date 형식을 정확히 전달했지만 조건문에 의해 Invalid를 출력하고 있다.
문자열 str에 저장된 날짜는 ISO8601 표준 문자열에 해당한다.
해당 문자열엔 T와 Z같은 구분 문자가 포함되는데, 해당 구분문자가 dateFormat에 구분 없이 저장되었다.
이러한 구분문자는 작은따옴표로 감싸 표현해야한다.
let str = "2017-09-02T09:30:00Z"
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss'Z'"
if let date = formatter.date(from: str) {
formatter.dateStyle = .full
formatter.timeStyle = .full
print(formatter.string(from: date))
} else {
print("Invalid")
}
결과
Saturday, September 2, 2017 at 9:30:00 AM Korean Standard Time
따라서 형식을 위와 같이 수정해 주면 정상적으로 변환된다.
이렇게 Date 형식을 정확히 하고, 오탈자가 없도록 주의해서 작성해야한다.
ISO8601 DateFormatter
ISO8601 DateFormatter는 iOS에서 날씨를 parsing할 때 주로 사용한다.
날짜를 문자열로 바꿀 때는 string(from:)메소드를, 문자열을 날짜로 바꿀 때는 date(from:)메소드를 사용한다.
let str = "2017-09-02T09:30:00Z"
let formatter = ISO8601DateFormatter()
if let date = formatter.date(from: str) {
print(formatter.string(from: date))
} else {
print("invalid")
}
결과
2017-09-02T09:30:00Z
이전에 일반 dateFormatter를 사용했던 것과 달리,
ISO8601형식의 문자열을 받았음에도 정상적으로 데이터를 parsing하고있다.
let str = "2017-09-02T"
let formatter = ISO8601DateFormatter()
if let date = formatter.date(from: str) {
print(formatter.string(from: date))
} else {
print("invalid")
}
결과
invalid
하지만 문자열에서 시간 부분을 지우면 정상적으로 parsing하지 못한다.
이렇게 같은 ISO8601 형식의 문자열이라도 정보가 누락되어있으면 별도로 형식을 지정해 줄 필요가있다.
let str = "2017-09-02T"
let formatter = ISO8601DateFormatter()
formatter.formatOptions = [.withYear, .withMonth, .withDay]
if let date = formatter.date(from: str) {
print(formatter.string(from: date))
} else {
print("invalid")
}
결과
00020107
포멧옵션은 formatOptions 속성에서 지정할 수 있다.
formatOptions 속성은 ISO8601 dateFormatter.Options 구조체이며, optionset 프로토콜을 채용한다.
이 안에는 with로 시작하는 옵션들이 선언되어있고, 원하는 옵션을 선택하면 된다.
위처럼 연, 월, 일을 fotmatOptions에서 지정해 주면 parsing은 되지만 의미를 알 수 없는 결과가 출력된다.
이렇게 된 이유는 str저장된 문자열에 포함된 '-'을 인식할 수 없고, 따라서 가장 앞의 2017만 parsing되고 나머지는 누락된다.
let str = "2017-09-02T"
let formatter = ISO8601DateFormatter()
formatter.formatOptions = [.withYear, .withMonth, .withDay, .withDashSeparatorInDate]
if let date = formatter.date(from: str) {
print(formatter.string(from: date))
} else {
print("invalid")
}
결과
2017-09-02
추가적으로 withDashSeparatorInDate 옵션을 추가해 주면, '-'을 인식하게 되고, 정상적으로 parsing한다.
let str = "2017-09-02T"
let formatter = ISO8601DateFormatter()
formatter.formatOptions = [.withFullDate]
if let date = formatter.date(from: str) {
print(formatter.string(from: date))
} else {
print("invalid")
}
결과
2017-09-02
위에서 적용한 네가지 옵션은 withFullDate로 치환할 수도 있다.
let str = "2017-09-02T"
let formatter = ISO8601DateFormatter()
formatter.formatOptions = [.withFullDate]
if let date = formatter.date(from: str) {
formatter.formatOptions = [.withInternetDateTime]
print(formatter.string(from: date))
} else {
print("invalid")
}
결과
2017-09-02T00:00:00Z
또한 웹서버와 통신할 때에는 withInternetDateTime 옵션을 사용해
ISO8601과 RFC3339 표준을 사용하는 웹서버와 오류없이 날짜를 주고받을 수 있다.
출력하기 직전 해당 옵션을 formatter에 적용하게되면 자동으로 시간을 추가하게 된다.
DateIntervalFormatter
let startDate = Date()
let endDate = startDate.addingTimeInterval(3600 * 24 * 30)
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "ko_KR")
formatter.dateStyle = .long
formatter.timeStyle = .short
print("\(formatter.string(from: startDate)) - \(formatter.string(from: endDate))")
결과
2021년 8월 29일 오후 10:19 - 2021년 9월 28일 오후 10:19
위의 코드는 날짜의 범위를 출력하는 코드이다.
지금도 잘 작동하고, 결과에도 문제가 없지만 DateIntervalFormatter를 사용한다면 조금 더 간단하게 구현할 수 있다.
let startDate = Date()
let endDate = startDate.addingTimeInterval(3600 * 24 * 30)
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "ko_KR")
formatter.dateStyle = .long
formatter.timeStyle = .short
print("\(formatter.string(from: startDate)) - \(formatter.string(from: endDate))")
let intervalformatter = DateIntervalFormatter()
intervalformatter.locale = Locale(identifier: "ko_KR")
intervalformatter.dateStyle = .long
intervalformatter.timeStyle = .short
print(intervalformatter.string(from: startDate, to: endDate))
결과
2021년 8월 29일 오후 10:19 - 2021년 9월 28일 오후 10:19
2021. 8. 29. 오후 10:19 ~ 2021. 9. 28. 오후 10:19
dateIntervalFormatter를 사용하고,
string(from:to:)메소드를 사용해 date를 문자열로 바꾸어 출력했다.
출력부가 상당히 단순화 됐다.
출력된 날짜에서 '~'은 Locale 설정에 따라 가장 적합한 문자로 사용된다.
동일한 옵션을 적용했음에도 결과는 사뭇 다른 것이 확인된다.
이번엔 포맷 문자열을 전달해 보도록한다.
let startDate = Date()
let endDate = startDate.addingTimeInterval(3600 * 24 * 30)
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "ko_KR")
formatter.dateStyle = .long
formatter.timeStyle = .short
print("\(formatter.string(from: startDate)) - \(formatter.string(from: endDate))")
let intervalformatter = DateIntervalFormatter()
intervalformatter.locale = Locale(identifier: "ko_KR")
//intervalformatter.dateStyle = .long
//intervalformatter.timeStyle = .short
intervalformatter.dateTemplate = "yyyyMMMdE"
print(intervalformatter.string(from: startDate, to: endDate))
결과
2021년 8월 29일 오후 10:27 - 2021년 9월 28일 오후 10:27
2021년 8월 29일 (일) ~ 9월 28일 (화)
지정한 포맷문자열 또한 Locale 설정에 맞게 자동으로 적용된다.
또한 이렇게 사용했을 경우 중복되는 날짜는 자동으로 생략된다.
DateComponentsFormatter
DateComponentsFormatter는 날짜와 시간 사이의 간격을 문자열로 바꿀 때 사용한다.
사용법은 다른 Formatter와 크게 다르지 않다.
let startDate = Date()
let endDate = startDate.addingTimeInterval(3600 * 24 * 30)
let formatter = DateComponentsFormatter()
formatter.unitsStyle = .full
if let date = formatter.string(from: startDate, to: endDate) {
print(date)
}
결과
4 weeks, 2 days
DateComponentsFormatter는 옵션을 선택할 때 unitStyle속성을 사용한다.
해당 속성은 열거형이다.
Full로 설정하고 결과를 확인해보면 두 날짜 사이의 기간을 계산해 출력하고있다.
var component = DateComponents()
component.hour = 1
component.minute = 30
if let result = formatter.string(from: component) {
print(result)
}
결과
1 hour, 30 minutes
컴포넌트를 생성해 전달한 시간도 자동으로 변환해 출력한다.
이번엔 '분'만 표현하도록 수정해 본다.
var component = DateComponents()
component.hour = 1
component.minute = 30
formatter.allowedUnits = [.minute]
if let result = formatter.string(from: component) {
print(result)
}
결과
90 minutes
allowedUnits 속성에 minute를 지정한 후 출력하면 분단위로 변환된 시간이 출력된다.
var component = DateComponents()
component.hour = 1
component.minute = 30
formatter.maximumUnitCount = 1
if let result = formatter.string(from: component) {
print(result)
}
결과
2 hours
maximumUnitCount 속성은 사용할 수 있는 유닛의 수를 제한한다.
위와 같이 1을 사용할 경우 가장 작은 단위의 유닛들부터 삭제되고, 이 때 반올림 한다.
var component = DateComponents()
component.hour = 1
component.minute = 30
formatter.includesTimeRemainingPhrase = true
if let result = formatter.string(from: component) {
print(result)
}
결과
1 hour, 30 minutes remaining
includesTimeRemainingPhrase속성은 남은 시간의 형태로 표현한다.
var component = DateComponents()
component.hour = 1
component.minute = 30
formatter.includesTimeRemainingPhrase = true
formatter.includesApproximationPhrase = true
if let result = formatter.string(from: component) {
print(result)
}
결과
About 1 hour, 30 minutes remaining
includesApproximationPhrase 속성을 true로 설정하면 시간 앞에 'About'이 추가된다.
이렇게 두개의 속성을 활용하면 네비게이션 등에서 도착 예정 시간을 쉽게 구성할 수 있다.
단, Locale 설정에 영향받지 않고 항상 영어로만 표시된다는 단점이 존재한다.
var component = DateComponents()
component.day = 0
component.hour = 1
component.minute = 0
component.second = 7
formatter.unitsStyle = .positional
if let result = formatter.string(from: component) {
print(result)
}
결과
1:00:07
이번엔 component의 속성을 추가하고, formatter의 unitStyle 속성을 positional로 변경했다.
출력 결과를 확인하면 값이 0인 day는 출력되지 않았다. 반면 같은 0인 minute은 출력되었다.
0을 취급하는 방식은 zeroFormattingBehavior 속성으로 설정한다.
별도로 설정하지 않은 기본값인 상태에선 가장 앞의 0은 삭제하고 앞뒤로 0이 아닌 값이 존재하는 경우엔 유지한다.
var component = DateComponents()
component.day = 0
component.hour = 1
component.minute = 0
component.second = 7
formatter.unitsStyle = .positional
formatter.zeroFormattingBehavior = .pad
if let result = formatter.string(from: component) {
print(result)
}
결과
0d 01:00:07
해당 속성을 pad로 변경하자 0으로 설정된 day도 삭제되지 않고 출력된다.
var component = DateComponents()
component.day = 0
component.hour = 1
component.minute = 0
component.second = 7
formatter.unitsStyle = .positional
formatter.zeroFormattingBehavior = .dropAll
if let result = formatter.string(from: component) {
print(result)
}
결과
1h 7s
dropAll로 설정하자 0으로 설정된 모든 값이 삭제되고, 이에 따라 각각의 컴포넌트를 구별해 표시하게된다.
'학습 노트 > iOS (2021)' 카테고리의 다른 글
076 ~ 080. Accessory View, Self Sizing and Custom Cell (0) | 2021.09.08 |
---|---|
070 ~ 075. Table View, Multi Section, Separator and Table View Cell (0) | 2021.09.07 |
053 ~ 061. Software Keyboard, Text Delegate, Input View & Input Accessory View and Password Auto Fill (0) | 2021.08.27 |
043 ~ 052. Label, Text Field, Text View and Text Input (0) | 2021.08.23 |
036 ~ 042. Image and Color (0) | 2021.08.19 |