트랙
/
Julia
Julia
/
연습 문제
/
미용실 예약하기
미용실 예약하기

미용실 예약하기

학습 연습 문제

소개

"날짜와 시간은 어린아이들에게도 가르치는 내용이에요. 그게 얼마나 어렵겠어요?"

많은 프로그래머가 그 실수를 저질렀고, 그 뒤에 겪는 일은 건강과 행복에 좋지 않은 영향을 주곤 해요.

날짜와 시간을 다루는 간단하지 않은 프로그래밍을 하는 사람이라면, 누구든 잠재적인 문제를 이해하고 완화할 준비가 되어 있어야 해요.

이 문서는 Julia가 날짜와 시간을 어떻게 다루는지 개괄적으로 살펴보려고 해요. 더 자세한 내용은 설명서를 참고해야 해요. 설명이 더 명확하다고 느끼는 독자도 있을 위키책도 있는데, 타입 계층을 정리한 유용한 다이어그램도 들어 있어요.

Dates 모듈

기본적인 기능의 대부분은 Dates 모듈에 있어요. 이 모듈은 기본 설치에 포함되어 있지만 표준 라이브러리의 일부는 아니에요.

모듈을 사용하는 방법은 두 가지가 있어요:

  1. import Dates를 추가하고, 모든 함수 호출 앞에 Dates.를 붙여요.
  2. using Dates를 추가하면 모듈 전체가 현재 네임스페이스로 들어와요 (몇 가지 문제가 되는 이름은 제외하고요).
# option 1
julia> import Dates

julia> Dates.now()
2025-06-21T16:02:39.080

julia> now()  # wrong: need to include `Dates.` after an import
ERROR: UndefVarError: `now` not defined in `Main`


# option 2
julia> using Dates

julia> now()  # functions are now in the namespace
2025-06-21T16:03:04.161

Dates 모듈은 크고 복잡하지만, 크게 네 가지 기능을 제공해요:

  • Dates.Date는 일-월-년을 나타내지만 하루 중 시각은 포함하지 않아요.
  • Dates.Time은 하루 중 시각을 나타내지만 날짜는 포함하지 않아요.
  • Dates.DateTime은 날짜와 시간을 함께 나타내요.
  • Dates.Period는 시간/날짜 간격을 다뤄요.

DateTime은 일반적으로 시간대 정보를 포함하지 않아요 (Python에서는 이런 것을 "naive" datetime이라고 불러요). 예외가 하나 있는데, now()는 시스템 시계에서 현지 시간을 가져오고, 필요하면 이를 UTC로 변환할 수 있어요.

아마도 가장 자주 필요한 작업은 다음과 같아요:

  • 적절한 입력 형식을 파싱해서 Dates 타입을 만들어요.
  • Dates 타입에서 필요한 숫자나 문자열 형식을 얻어요.
  • Date, Time, DateTime 값에 오프셋을 적용해요.
  • 두 값 사이의 간격을 계산해요.
  • 현재 날짜(today())와 시간(now())을 가져와요.
Note

시각적인 산만함을 줄이기 위해, 이 문서의 나머지 예제 코드 대부분은 using Dates를 전제로 하고, 함수 호출에 모듈 이름 Dates.를 붙이지 않아요.

날짜와 시간 형식

날짜와 시간을 쓰는 방법은 다양하고, 대개 문화권에 따라 달라요. "7/6/23"처럼 숫자만으로 된 날짜는 모호하고 헷갈리며, 다국적 기업에서 값비싼 실수를 많이 불러왔어요 (저자는 이 말을 씁쓸한 개인적 경험에서 우러나와 해요).

국제 표준은 ISO 8601에 정의되어 있고, 크게 두 가지 장점이 있어요:

  • 파싱이 빠르고 모호하지 않아요.
  • 날짜/시간을 일반 텍스트처럼 다뤄 사전순으로 정렬할 수 있어서 정렬이 쉬워요.

앞선 예제에서 Date.now()가 2025-06-21T16:03:04.161을 반환한 것을 봤어요.

이 값은 여러 부분으로 이루어져 있어요:

  • 날짜 부분은 YYYY-MM-DD.
  • 시간 부분은 hh:mm:ss.
  • 선택적으로 소수점 뒤에 밀리초(또는 그보다 더 작은 단위)가 붙어요.

다른 문자열 형식은 뒤에서 다뤄요.

날짜

Dates.Date는 시간이나 시간대를 전혀 알지 못하는, 비교적 단순한 날짜 전용 타입이에요.

# constructor with year, month, day arguments
julia> date1 = Date(2025, 06, 23)
2025-06-23

# constructor with ISO 8601 string
julia> date2 = Date("2025-06-23")
2025-06-23

julia> date1 == date2
true

julia> typeof(date1)
Date

날짜의 각 부분에 접근하는 함수가 있고, 이들은 대소문자로 구분되는 쌍을 이뤄요.

# lowercase returns an integer
julia> month(date1)
6

julia> typeof(month(date1))
Int64

# Propercase returns a Period type
julia> Month(date1)
6 months

julia> typeof(Month(date1))
Month

조회 함수

달력에 대한 이해를 갖춘 다양한 함수가 있어요. 다음 예제는 그중 몇 가지를 보여줘요.

julia> date1
2025-06-23

julia> dayofweek(date1) # 1 = Monday, 7 = Sunday
1

julia> dayname(date1)
"Monday"

julia> daysinmonth(date1)
30

julia> isleapyear(date1)
false

julia> lastdayofmonth(date1)
2025-06-30

시간

Dates.Time은 기본적인 시간 전용 타입이에요. 날짜를 전혀 알지 못해서, 자정이 지나면 자동으로 Time(0, 0, 0)으로 넘어가요.

전체 생성자 형식은 Time(hour, min, sec, millisec, microsec)이고, ISO 8601 형식도 같은 의미예요.

모든 매개변수는 선택 사항이라 기본값이 0이에요.

julia> Time(14, 57, 25, 142)
14:57:25.142

julia> Time("14:57:25.142")
14:57:25.142

julia> Time(14, 57, 25, 142, 32)
14:57:25.142032

Date와 마찬가지로, 각 부분은 접근 함수로 가져올 수 있어요:

julia> minute(t) # => integer
57

julia> Minute(t) # => Period
57 minutes

날짜/시간

Dates.DateTime은 Date와 Time 타입의 기능 대부분을 합쳐 놓았어요.

julia> dt1 = DateTime(2025, 6, 23, 14, 57, 25, 142)
2025-06-23T14:57:25.142

# date1 and t were defined in previous examples
julia> dt2 = DateTime(date1, t)
2025-06-23T14:57:25.142

년, 월, 일 매개변수의 기본값은 1이고, 시간 관련 매개변수는 모두 기본값이 0이에요.

이 매개변수들을 모두 제대로 기억하기는 어려울 수 있어서, 입력할 때는 ISO 형식이 더 나을 수 있어요.

또는 위 예제처럼 Date와 Time으로부터 DateTime을 만들 수도 있어요.

기간

날짜/시간의 각 구성 요소에는 Year부터 Nanosecond까지 각각의 Period 타입이 있고, 이는 시간 간격을 나타내요. 이런 타입은 산술 연산에 특히 유용해요.

julia> dt1
2025-06-23T14:57:25.142

julia> Year(21)
21 years

julia> Second(61)
61 seconds

julia> dt1 + Year(21) - Second(61)
2046-06-23T14:56:24.142

julia> Date(2025, 07, 03) - Date(2025, 04, 25)
69 days

Period 타입을 다룰 때 Julia는 월별 일수처럼 달력이 불규칙한 부분을 똑똑하게 처리하려고 하고, 필요하면 반올림해요.

# February has fewer days than January
julia> Date(2025, 1, 31) + Month(1) 
2025-02-28

문자열 표현

앞에서 ISO 8601 표준을 언급했는데, Julia가 문자열을 서식화하거나 파싱할 때 기본으로 사용하는 날짜/시간 표현이에요.

물론 다른 형식도 많이 쓰이고, 흔히 문화권마다 다른 방식으로 쓰여요. 이런 형식을 다루기 위해 Julia에는 DateFormat 타입이 있고, 임의로 복잡한 형식 문자열로 만들 수 있어요.

# dateformat"" string syntax
julia> dtfmt = dateformat"d/m/y"
dateformat"d/m/y"

julia> typeof(dtfmt)
DateFormat{Symbol("d/m/y"), Tuple{Dates.DatePart{'d'}, Dates.Delim{Char, 1}, Dates.DatePart{'m'}, Dates.Delim{Char, 1}, Dates.DatePart{'y'}}}

# DateFormat constructor
julia> DateFormat("d/m/y")
dateformat"d/m/y"

위 예제는 아주 단순한데, 유럽에서 흔한 일/월/년 형식의 날짜일 뿐이에요. 두 가지 문법 형태를 보여줬지만 결과는 같아요.

그런 다음 DateFormat을 적절한 문자열을 파싱하는 데 사용할 수 있어요:

julia> DateTime("14/7/2023", dtfmt)
2023-07-14T00:00:00

DateFormat을 만드는 데는 상당한 부하가 따르므로, (여기서 dtfmt처럼) 이 단계를 한 번만 하는 것이 여러 날짜/시간 문자열을 반복 처리할 때 성능에 도움이 돼요.

형식은 이보다 훨씬 복잡할 수 있으니, 자세한 내용은 설명서를 참고해요.

같은 DateFormat을 Dates.format() 함수와 함께 사용하면 날짜/시간을 원하는 문자열 형식으로 출력할 수도 있어요.

아쉽게도 format과 네임스페이스 충돌이 있는 것 같아서(적어도 Julia 1.11.5 기준으로요), using Dates를 한 뒤에도 Dates. 접두사를 붙이는 게 좋아요.

julia> dt1
2025-06-23T14:57:25.142

julia> Dates.format(dt1, dateformat"e, u d")
"Mon, Jun 23"

문서에 나와 있듯이, "e, u d"는 요일과 월의 축약된 텍스트 표현을 제공해요.

텍스트 표현은 기본값이 영어예요. 다른 언어도 추가할 수 있지만, 현재 이에 대한 지원은 아쉬운 편이에요.

지침

이 연습 문제에서는 2012년 9월 15일에 문을 연 뉴욕의 미용실을 위한 예약 스케줄러를 만들어 봐요.

다섯 개의 과제가 있고, 모두 예약 날짜와 관련되어 있어요. 시간은 24시간 형식으로 표기해요(AM/PM은 쓰지 않아요).

1. 숫자로만 된 예약 날짜 파싱하기

schedule_appointment() 함수를 구현해서 텍스트로 표현된 예약 날짜를 그에 해당하는 DateTime 형식으로 파싱해요.

입력은 미국식 월/일/년 순서라는 점에 유의해요.

julia> schedule_appointment("07/25/2023 13:45:00")
2023-07-25T13:45:00

2. 예약이 이미 지났는지 확인하기

has_passed() 함수를 구현해요. 이 함수는 예약 날짜를 받아서 예약이 과거에 있었는지 확인해요:

julia> has_passed(DateTime(1999, 12, 31, 9, 0, 0))
true

3. 예약이 오후인지 확인하기

is_afternoon_appointment() 함수를 구현해요. 이 함수는 예약 날짜를 받아서 예약이 오후(12:00 이상, 18:00 미만)인지 확인해요:

julia> is_afternoon_appointment(DateTime(2023, 3, 29, 15, 0, 0))
true

4. 예약의 시간과 날짜 설명하기

description() 함수를 구현해요. 이 함수는 예약 날짜를 받아서 그 날짜와 시간에 대한 설명을 반환해요:

julia> describe(DateTime(2023, 3, 29, 15, 0, 0))
"You have an appointment on Wednesday, March 29, 2023 at 15:00"

5. 기념일 날짜 반환하기

anniversary_date() 함수를 구현해요. 이 함수는 올해의 기념일 날짜인 9월 15일을 반환해요:

julia> anniversary_date()  # run during 2025
2025-09-15
GitHub에서 편집 링크가 새 창이나 탭에서 열려요
Julia Exercism

미용실 예약하기 문제를 시작해 볼 준비가 됐나요?

Exercism에 가입하고 Julia 트랙을 개념 35개연습 문제 128개, 그리고 실제 사람의 멘토링과 함께 배우고 익혀 보세요. 모두 무료예요.