ics 파일이란 — 메일 첨부 일정이 캘린더에 들어가는 원리

회의 안내 메일에 붙어 온 .ics 파일을 눌렀더니 캘린더 앱이 열리고 일정이 그대로 들어간 경험이 있으실 겁니다. 결론부터 말하면 .ics는 일정 내용을 정해진 형식으로 적어 둔 평범한 텍스트 파일입니다.
전용 앱이 있어야 열리는 파일이 아니라, 메모장으로 열면 내용이 그대로 보입니다. 형식은 iCalendar라는 인터넷 표준(RFC 5545)이 정해 두었고, 알아야 할 규칙은 몇 가지뿐입니다.
요약 ① .ics는 UTF-8 텍스트 파일이며, 미디어 타입
text/calendar로 등록돼 있어 열면 캘린더 앱으로 연결됩니다. ② 구조는BEGIN:VCALENDAR안에BEGIN:VEVENT가 들어가는 형태이고, 일정 하나가 VEVENT 한 덩어리입니다. ③ 시간이 어긋나 보이면DTSTART표기를 봅니다. 끝에Z가 있으면 UTC,TZID=가 붙으면 지정 시간대, 아무것도 없으면 여는 기기의 현지 시각입니다.
파일을 여는 것만으로 일정이 추가되는 이유
.ics에는 실행되는 코드가 없습니다. 그런데도 더블클릭하면 캘린더가 열리는 이유는, 이 확장자와 text/calendar라는 미디어 타입이 표준으로 등록돼 있고 운영체제와 메일 앱이 그 타입을 캘린더 앱에 연결해 두었기 때문입니다.
즉 파일이 무언가를 실행하는 게 아니라, 캘린더 앱이 파일을 읽어서 일정으로 해석하는 것입니다. 그래서 같은 파일을 메모장으로 열면 아무 일도 일어나지 않고 글자만 보입니다.
문제는 이 해석 과정에서 시간이 어긋나거나 날짜가 하루 밀려 보이는 일이 생긴다는 점입니다. 원인은 거의 항상 파일 안의 두 줄, DTSTART와 DTEND에 적혀 있습니다.
메모장으로 열어 직접 확인하는 방법
특별한 프로그램이 필요 없습니다. 받은 .ics 파일을 마우스 오른쪽 버튼으로 눌러 메모장(윈도우)이나 텍스트편집기(맥)로 열면 됩니다. 확장자가 걸리면 파일 이름을 .txt로 바꿔 열어도 내용은 같습니다.
열어 보면 아래와 같은 모양입니다. 이름과 값이 콜론으로 이어진 줄들이 전부입니다.
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//example//ko
BEGIN:VEVENT
UID:20260813-meeting@example.com
DTSTAMP:20260720T010000Z
DTSTART:20260813T140000
DTEND:20260813T150000
SUMMARY:팀 회의
LOCATION:본사 3층 회의실
END:VEVENT
END:VCALENDAR
줄마다 무슨 뜻인가
| 줄 | 뜻 |
|---|---|
BEGIN:VCALENDAR … END:VCALENDAR | 파일 전체를 감싸는 바깥 상자 |
VERSION · PRODID | iCalendar 객체에 반드시 있어야 하는 두 가지. 버전과 만든 프로그램 이름 |
BEGIN:VEVENT … END:VEVENT | 일정 하나. 여러 개면 이 덩어리가 여러 번 반복됩니다 |
UID · DTSTAMP | VEVENT에 반드시 있어야 하는 두 가지. 일정의 고유 식별자와 작성 시각 |
DTSTART · DTEND | 시작·종료 시각. 표기 형식이 이 글의 핵심입니다 |
SUMMARY | 캘린더에 표시되는 일정 제목 |
LOCATION · DESCRIPTION | 장소와 상세 설명 |
날짜와 시각은 20260813T140000 처럼 붙여 씁니다. 앞 8자리가 연월일, T 뒤 6자리가 시분초입니다. 이 예시는 2026년 8월 13일 14시 00분 00초입니다.
직접 만들어 보고 싶다면 위 내용을 그대로 메모장에 붙여 넣고 UTF-8로 저장하면서 확장자를 .ics로 지정하면 됩니다. 단 손으로 적을 때 UID가 겹치거나 줄 형식이 어긋나면 캘린더 앱이 조용히 무시하는 경우가 있어, 값을 하나씩 확인해야 합니다.
저희 도구로 만들어 보기. 제목과 시작 시각만 넣으면 위와 같은 .ics 텍스트가 화면에 그대로 나오고, 그 자리에서 다운로드하거나 내용을 복사할 수 있습니다.
설치·회원가입 없이 브라우저 안에서 .ics 텍스트가 만들어지며, 입력한 일정 내용은 서버로 전송되지 않습니다.

시간이 몇 시간씩 어긋나 보이는 이유
받은 일정이 9시간 밀려 보이거나, 내가 보낸 일정이 상대방 화면에서 다른 시각으로 뜨는 일이 있습니다. 원인은 DTSTART의 시간대 표기입니다. iCalendar는 날짜·시각을 적는 방법을 세 가지로 정해 두었고, 셋의 의미가 서로 다릅니다.
세 가지 표기와 각각의 의미
| 표기 | 예시 | 의미 |
|---|---|---|
| 뒤에 아무것도 없음 | DTSTART:20260813T140000 | 여는 기기의 현지 시각으로 14:00 |
끝에 Z | DTSTART:20260813T050000Z | UTC 기준 05:00이라는 절대 시각 |
TZID= 파라미터 | DTSTART;TZID=Asia/Seoul:20260813T140000 | 서울 시간대의 14:00 |
첫 번째가 이른바 플로팅 타임입니다. 시간대 정보가 없으므로 서울에서 열면 14:00, 파리에서 열어도 14:00으로 보입니다. "각자 자기 지역 오후 2시"라는 뜻이라, 원격 회의처럼 절대 시각이 중요한 일정에는 맞지 않습니다.
두 번째는 반대입니다. Z가 붙으면 UTC 절대 시각이라, 한국(UTC+9)에서 열면 14:00으로 환산돼 보입니다. 같은 순간을 모두가 각자 지역 시각으로 보게 되므로 참석자가 여러 나라에 있을 때 안전합니다.
세 번째는 시간대를 이름으로 못 박습니다. 서머타임처럼 지역 규칙이 바뀌어도 그 지역 기준으로 다시 계산되므로, 반복 일정에 특히 유리합니다.
그래서 시간이 어긋나 보일 때 확인할 순서는 간단합니다. 파일을 열어 DTSTART 줄 끝에 Z가 있는지, TZID=가 붙어 있는지 보면 어느 해석이 적용된 것인지 바로 알 수 있습니다.
참고로 저희 도구가 시각이 있는 일정에 넣는 DTSTART는 첫 번째 방식인 플로팅 타임입니다(종일 일정은 날짜만 적는 VALUE=DATE 형태입니다). 화면 아래에도 "시간은 사용자 기기의 현지 시각(플로팅 타임)으로 저장됩니다"라고 안내가 나옵니다.
종일 일정이 하루 더 길게 보일 때
종일 일정은 시각 없이 날짜만 적습니다. 이때 표기가 DTSTART;VALUE=DATE:20260813 처럼 VALUE=DATE가 붙는 형태로 바뀝니다.
여기서 사람들이 가장 많이 걸리는 규칙이 있습니다. DTEND는 일정에 포함되지 않는 끝, 즉 배타적인 끝을 가리킵니다. 8월 13일 하루짜리 종일 일정이라면 종료는 13일이 아니라 DTEND;VALUE=DATE:20260814로 적어야 합니다.
종료를 13일로 적으면 표준이 요구하는 "DTEND는 DTSTART보다 뒤" 조건을 어기게 되어, 앱에 따라 다르게 표시되거나 무시될 수 있습니다. 반대로 만든 쪽이 규칙대로 14일로 적었는데 읽는 사람이 그 숫자를 종료일로 오해하면 하루 더 걸쳐 있는 것처럼 보입니다.
날짜만 적힌 종일 일정에 DTEND도 DURATION도 없으면, 표준은 그 일정을 하루짜리로 봅니다. 저희 도구도 종료일을 비워 두면 시작일 다음 날을 DTEND로 넣어 하루짜리 종일 일정으로 만듭니다.
자주 막히는 지점
| 상황 | 확인할 것 |
|---|---|
| 한글 제목이 깨진다 | 파일을 UTF-8로 저장했는지. 표준이 정한 문자셋이 UTF-8입니다 |
| 제목에 쉼표·세미콜론을 넣었더니 값이 잘린다 | 쉼표·세미콜론·역슬래시와 줄바꿈은 백슬래시로 이스케이프해야 합니다. 콜론은 이스케이프하지 않습니다 |
| 줄이 중간에 공백 한 칸과 함께 끊겨 있다 | 한 줄이 길면 다음 줄로 접는(folding) 정상 표기입니다. 줄바꿈 제외 75옥텟을 넘지 않기를 권고합니다 |
| 같은 파일을 두 번 열었는데 일정이 하나뿐 | UID가 같은지. 많은 캘린더 앱이 같은 UID를 기존 일정의 갱신으로 처리합니다 |
| 참석 여부 버튼이 뜨지 않는다 | METHOD가 PUBLISH인지 REQUEST인지, ATTENDEE가 들어 있는지 |
마지막 항목을 조금 더 풀면, 일정 파일을 주고받는 방식은 별도의 표준(iTIP)이 METHOD 값으로 구분합니다. PUBLISH는 응답을 요구하지 않는 단순 게시이고, REQUEST는 참석자에게 응답을 요구하는 초대입니다.
그래서 같은 .ics라도 METHOD:PUBLISH에 참석자 목록이 없으면 "캘린더에 추가"만 뜨고, 수락·거절 버튼은 나오지 않는 것이 정상입니다. 저희 도구가 만드는 파일도 METHOD:PUBLISH입니다.
정리
- .ics는 UTF-8 평문 텍스트 파일이고, 메모장으로 열면 내용이 그대로 보입니다.
- 구조는
BEGIN:VCALENDAR안에BEGIN:VEVENT가 들어가는 형태이며, 일정 하나가 VEVENT 한 덩어리입니다. - VEVENT에 반드시 있어야 하는 값은
UID와DTSTAMP이고, 파일 전체에는VERSION과PRODID가 필요합니다. - 시간 표기는 세 가지입니다. 아무 표시 없으면 여는 기기의 현지 시각,
Z는 UTC 절대 시각,TZID=는 지정 시간대입니다. - 종일 일정의
DTEND는 배타적이라, 하루짜리 일정은 종료를 다음 날짜로 적습니다. - 시간이나 날짜가 어긋나 보이면
DTSTART·DTEND두 줄만 열어 확인하면 원인이 드러납니다.
설치·회원가입 없이 브라우저 안에서 .ics 텍스트가 만들어지며, 입력한 일정 내용은 서버로 전송되지 않습니다.
자주 묻는 질문
.ics 파일을 메모장으로 열어도 괜찮나요?
괜찮습니다. .ics는 실행 파일이 아니라 텍스트 파일이라, 여는 것만으로 무언가 동작하지 않습니다. 오히려 캘린더에 넣기 전에 내용을 확인하는 가장 확실한 방법입니다. 파일 이름 뒤 확장자를 .txt로 바꿔 열어도 내용은 같고, 다시 .ics로 되돌리면 그대로 캘린더에 추가할 수 있습니다.
같은 .ics 파일을 두 번 열면 일정이 두 개 생기나요?
일반적으로는 아닙니다. VEVENT마다 들어 있는 UID가 일정의 고유 식별자 역할을 하기 때문에, 같은 UID를 가진 파일을 다시 열면 새 일정이 생기는 대신 기존 일정이 갱신됩니다. 반대로 같은 내용이라도 UID가 다르면 별개의 일정으로 들어갑니다. 중복이 생겼다면 두 파일의 UID 줄을 비교해 보면 됩니다.
시간대를 확실히 맞추려면 어떻게 적어야 하나요?
참석자가 서로 다른 지역에 있다면 DTSTART 끝에 Z를 붙인 UTC 표기나 TZID= 파라미터를 쓰는 편이 안전합니다. 시간대 표시가 없는 값은 여는 기기의 현지 시각으로 해석되므로, "각자 자기 지역 오후 2시"라는 의미가 됩니다. 같은 지역 안에서만 공유하는 일정이라면 표시 없는 값으로도 어긋나지 않습니다.
알림은 파일 안에 어떻게 적혀 있나요?
일정 안에 BEGIN:VALARM으로 시작하는 별도 덩어리가 들어가고, 그 안의 TRIGGER 줄이 언제 알릴지를 나타냅니다. 예를 들어 TRIGGER:-PT10M은 시작 10분 전이라는 뜻입니다. 저희 도구에서 알림을 "10분 전"으로 고르면 이 줄이 그대로 생성되고, "없음"을 고르면 VALARM 덩어리 자체가 빠집니다. 알림을 실제로 띄울지는 캘린더 앱마다 처리가 다르므로, 넣어 본 뒤 확인하는 편이 정확합니다.
