날짜와 Timestamp 연산
날짜나 시각 열에는 적절한 Date/Timestamp 자료형을 사용하고 문자열 입력은 형식을 지정해 파싱합니다. 아래 함수는 from pyspark.sql import functions as F로 가져옵니다.
날짜 이동과 차이
| 함수 | 의미 |
|---|---|
F.date_add(start, days) | 날짜에 일 수를 더함 |
F.date_sub(start, days) | 날짜에서 일 수를 뺌 |
F.add_months(start, months) | 날짜를 지정한 월 수만큼 이동 |
F.datediff(end, start) | end에서 start를 뺀 일 수 |
F.months_between(date1, date2) | date1에서 date2를 뺀 월 수 |
F.last_day(date) | 해당 월의 마지막 날짜 |
F.next_day(date, dayOfWeek) | 주어진 날짜보다 뒤에 있는 다음 해당 요일 |
months_between은 date1이 더 늦으면 양수입니다. 두 날짜의 일이 같거나 둘 다 월말이면 정수이며, 그 외에는 한 달을 31일로 보고 소수 차이를 계산합니다. 기본값은 소수 8자리 반올림이며 세 번째 인자 roundOff=False로 이를 끌 수 있습니다.
날짜와 시각의 일부 추출
| 함수 | 반환하는 부분 |
|---|---|
F.year(column) | 연도 |
F.month(column) | 월 |
F.dayofmonth(column) | 월 안의 일 |
F.hour(column) | 시 |
F.minute(column) | 분 |
F.second(column) | 초 |
F.quarter(column) | 달력 분기 |
F.dayofyear(column) | 연중 일 번호 |
F.weekofyear(column) | 연중 주 번호 |
회계연도 분기는 조직의 회계 달력에 맞는 별도 규칙이 필요합니다.
파싱과 문자열 형식화
| 함수 | 결과와 역할 |
|---|---|
F.to_date(column, format=None) | 문자열 등을 Date로 변환 |
F.to_timestamp(column, format=None) | 문자열 등을 Timestamp로 변환 |
F.unix_timestamp(timestamp=None, format="yyyy-MM-dd HH:mm:ss") | 시각을 Unix epoch 초로 변환 |
F.date_format(date, format) | 날짜/시각을 지정한 형식의 문자열로 변환 |
F.from_unixtime(timestamp, format="yyyy-MM-dd HH:mm:ss") | epoch 초를 세션 시간대의 문자열로 표현 |
F.to_utc_timestamp(timestamp, tz) | 지정 시간대의 시각을 UTC 기준으로 변환한 Timestamp |
F.from_utc_timestamp(timestamp, tz) | UTC 시각을 지정 시간대 기준으로 변환한 Timestamp |
from_utc_timestamp는 문자열 형식화 함수가 아닙니다. 시간대가 포함된 문자열을 먼저 파싱한 값에 시간대 이동을 다시 적용하는 경우에는 중복 이동이 없는지 확인합니다.
| 형식 | 예시 |
|---|---|
yyyy-MM-dd | 1997-01-31 |
yyyy-MM-dd HH:mm:ss | 1997-01-31 23:59:59 |
Spark 3 계열의 날짜 패턴은 Spark의 datetime pattern 규칙을 따릅니다. Java의 예전 SimpleDateFormat 문법을 모두 같은 의미로 해석하지 않습니다. MM은 월, mm은 분이고 HH는 24시간제 시입니다. S는 초의 소수 부분이며 연속된 S로 정밀도를 지정합니다. Timestamp는 마이크로초 정밀도를 지원하고 더 긴 나노초 부분은 잘릴 수 있습니다.
밀리초 epoch 읽기
epoch 밀리초와 epoch 초를 구분합니다. PySpark 3.5 이상에서는 밀리초를 직접 받는 timestamp_millis()를 사용할 수 있습니다.
from pyspark.sql import functions as F
def parse_epoch_milliseconds(df):
return df.withColumn("timestamp", F.timestamp_millis(F.col("timestamp")))
그보다 앞선 인터페이스의 숫자-to-timestamp 캐스트는 초 단위를 사용하므로 밀리초를 1000으로 나누어 전달합니다.
from pyspark.sql import functions as F
def parse_epoch_by_seconds(df):
return df.withColumn("timestamp", (F.col("timestamp") / 1000).cast("timestamp"))
가상의 epoch 밀리초 1531860192661은 UTC로 2018-07-17 20:43:12.661에 해당합니다. 표시 시각은 세션 시간대에 영향을 받습니다. 부동소수점 나눗셈의 정밀도까지 엄밀하게 보존해야 한다면 밀리초 전용 변환을 사용합니다.
문자열 표현이 목적이면 다음처럼 from_unixtime을 쓸 수 있습니다. 이 경로는 초 단위 함수이며 기본 형식에는 소수 초가 없으므로 밀리초를 보존하는 Timestamp 변환과 동일하지 않습니다.
from pyspark.sql import functions as F
def format_epoch_seconds(df):
return df.withColumn("timestamp", F.from_unixtime(F.col("timestamp") / 1000))
단위 아래 부분 잘라내기
F.trunc(date, format)은 날짜를 지정한 단위로 자르고, F.date_trunc(format, timestamp)는 Timestamp를 지정한 단위로 자릅니다. 두 함수는 인자 순서가 다릅니다.
from pyspark.sql import functions as F
def calendar_boundaries(df):
return df.select(
F.trunc("event_date", "month").alias("month_start"),
F.date_trunc("hour", "event_time").alias("hour_start"),
)