안녕하세요, まさきん입니다.
가족 일정을 AI 어시스턴트를 통해 구글 캘린더에 넣는 일이 늘었습니다. 편리한 반면, 얼마 전 작은 함정을 밟았습니다. 종일 일정이 어째서인지 하루 앞당겨져 들어가 있었던 거예요. 구조를 알아보니 납득이 돼서 기록으로 남겨 둡니다.
※글 게시 시점의 정보입니다. 최신 조건은 공식 사이트에서 확인해 주세요.
- 종일 일정에 “+09:00”이 붙은 일시를 넘겼더니 전날 종일 일정이 되었다
- 밀린 건 시간대가 UTC로 되어 있던 가족 공유 캘린더였다
- Google Calendar API에서 종일 일정은 start.date와 end.date로 지정한다
- end.date에는 다음 날을 넣는 규칙이고, 종료일은 포함되지 않는 것으로 취급된다
- 이번에 “Z”를 붙여 고친 방법은 사용 중인 AI 연동의 입력 방식에 맞춘 우회책
무슨 일이 있었나
저는 AI 어시스턴트(Claude)와 구글 캘린더를 연동해 두었습니다. 가족이 공유하는 캘린더에도 일정을 자동으로 넣게 하고 있고요.
얼마 전 어떤 구독 서비스의 무료 체험을 써 보고 있었습니다. 클라우드 스토리지가 딸린 AI 요금제입니다. 계속 쓸지 판단하는 날을 두 단계로 정하기로 했습니다.
첫 번째는 중간에 사용감을 확인하는 중간 점검일입니다. 두 번째는 계속할지 그만둘지 정하는 최종 판단일입니다. 최종 판단일은 해지 기한 9일 전에 두었습니다. 막판에 판단하려면 바쁜 일에 밀려 흐지부지될 것 같았거든요.
이 두 날을 종일 일정으로 가족 캘린더에 등록했습니다. AI에게 날짜를 알려 주고 넣게 하는, 평소 방식입니다.
그런데 캘린더를 열어 보니 상황이 달랐습니다. 12월의 두 일정이 둘 다 하루 앞에 들어가 있었던 겁니다. 해지 기한 이야기라서 하루만 어긋나도 찜찜하죠.
원인은 “+09:00”과 캘린더의 시간대
알아보니 원인은 날짜를 넘기는 방식이었습니다. AI를 통해 일정을 만들 때 종일 날짜에 “+09:00”을 붙여 지정하고 있었던 거예요. “+09:00”은 일본 시간을 나타내는 표기입니다.
한편 가족 공유 캘린더의 시간대는 UTC로 되어 있었습니다. UTC는 세계 기준 시각이고, 일본 시간보다 9시간 늦습니다.
예를 들어 “12월 10일 0시(+09:00)“를 UTC로 바꾸면 “12월 9일 15시”입니다. UTC 캘린더에서 보면 이 시각은 12월 9일에 속합니다. 그래서 종일 일정도 12월 9일로 들어갔다고 생각하면 앞뒤가 맞습니다.
제가 쓰는 AI 연동 도구의 내부는 제 쪽에서 볼 수 없습니다. 그래서 세세한 변환 절차까지는 단언할 수 없습니다. 다만 어긋난 방식은 9시간 시차로 딱 설명된다고 생각합니다.
”Z”를 붙여 다시 넣었더니 올바른 날에
시험 삼아 날짜를 “Z”를 붙여 넘겨서 일정을 다시 업데이트했습니다. “Z”는 UTC를 나타내는 기호입니다. 그랬더니 이번에는 올바른 날에 들어갔습니다.
“12월 10일 0시(Z)“는 UTC 캘린더에서도 12월 10일 그대로입니다. 시차만큼 날짜가 넘어가는 일이 생기지 않죠.
그 뒤로 이 AI 연동에서는 종일 일정을 Z를 붙여 넘기기로 했습니다. 그렇다고 이게 정석은 아닙니다. 뒤에서 쓰겠지만 원래 사양은 훨씬 단순했습니다.
종일 일정은 “시각이 없는 날짜”
여기서 멈춰서 생각한 건 종일 일정이란 무엇인가 하는 점이었습니다.
시각이 있는 일정은 세계 어디서 봐도 같은 순간을 가리킵니다. 도쿄의 9시는 런던의 0시와 같은 순간입니다. 보는 장소에 따라 표시되는 시각이 바뀌죠.
반면 종일 일정은 “그날 하루”를 가리키는 일정입니다. 생일이나 마감일처럼 시각과 상관없이 날짜 자체에 의미가 있습니다. 원래는 시간대에 따라 움직이면 안 되는 정보죠.
그런데 날짜에 시각이나 시간대를 붙여 넘기면 이야기가 달라집니다. 받는 쪽은 그걸 “어떤 순간”으로 취급할 수도 있습니다. 그 순간이 어느 날짜에 속하는지는 캘린더 쪽 시간대로 정해집니다. 이번 어긋남이 바로 이 불일치였던 것 같습니다.
Google Calendar API의 사양
구글 개발자 문서를 읽어 보니 종일 일정을 넘기는 방법이 분명하게 적혀 있었습니다.
일정의 시작과 종료에는 date와 dateTime이라는 두 종류의 항목이 있습니다. date는 “yyyy-mm-dd” 형식의 날짜로, 종일 일정일 때 쓴다고 되어 있습니다. dateTime은 시각이 붙은 값으로, 시간대 차이(오프셋)가 필요합니다.
| 항목 | 형식 예시 | 쓰는 경우 |
|---|---|---|
| start.date / end.date | 2026-12-10 | 종일 일정 |
| start.dateTime / end.dateTime | 2026-12-10T09:00:00+09:00 | 시각이 있는 일정 |
| start.timeZone / end.timeZone | Asia/Tokyo | 시각이 있는 일정의 지역 지정 |
게다가 문서에는 중요한 한 문장이 있었습니다. 종일 일정에서는 시간대 항목이 의미를 갖지 않는다고 되어 있습니다.
또 시작과 종료는 “둘 다 시각 포함”이거나 “둘 다 종일”로 맞춰야 한다고 합니다. 시작은 date로, 종료는 dateTime으로 하는 식의 혼용은 할 수 없습니다.
즉 종일 일정은 날짜만으로 넘기는 게 정답입니다. 날짜만이라면 캘린더 시간대에 좌우되지 않습니다.
end.date에는 다음 날을 넣는다
또 하나 걸려 넘어지기 쉬운 게 종료일입니다. 문서에는 시작은 “포함”, 종료는 “포함하지 않음”이라고 적혀 있습니다.
12월 10일 하루만의 종일 일정이라면 end.date에는 다음 날인 12월 11일을 넣습니다. 공식 샘플에서도 6월 1일 종일 일정은 end가 6월 2일로 되어 있었습니다.
"start": { "date": "2026-12-10" },
"end": { "date": "2026-12-11" }
여기서 end도 12월 10일로 하면 기간이 0이 되어 버립니다. 사람 감각으로는 조금 이상하지만, 그런 규칙이라고 기억해 두면 좋겠습니다.
이번 Z 표기는 “입력 방식에 맞춘 우회책”
여기는 솔직하게 구분해서 적어 두고 싶습니다.
API 사양을 따르면 종일 일정은 start.date와 end.date로 넘기는 게 정석입니다. 한편 제가 쓰던 건 AI와 캘린더를 잇는 연동 도구였습니다. 그 입력 방식은 종일 일정도 일시 형태로 받도록 만들어져 있었던 것 같습니다.
그 구조 안에서 UTC 캘린더에 올바르게 들어가는 표기가 Z였다는 겁니다. API를 직접 호출할 수 있는 분은 날짜만으로 넘기는 게 깔끔하다고 생각합니다.
- Z를 붙인 0시로 넘기는 방법은 UTC 캘린더였기 때문에 잘된 것일 수 있다
- 캘린더 시간대가 다르면 다른 날로 밀리는 것도 생각할 수 있다
- 쓰는 도구의 입력 방식에서 종일 일정을 어떻게 넘기는지 한 번 확인해 두면 안심
넘기는 방식별 결과 정리
이론상으로 넘기는 방식과 캘린더 시간대의 조합을 나열해 봤습니다. 날짜는 설명용 예시입니다. 실제로 시험한 건 UTC 캘린더의 두 패턴뿐입니다. 나머지는 시차로 계산한 것이니 참고 정도로 봐 주세요.
| 넘기는 방식(12월 10일 의도) | UTC 캘린더 | 일본 시간 캘린더 |
|---|---|---|
| 12월 10일 0시 +09:00 | 12월 9일로 밀렸다(직접 겪음) | 12월 10일이 될 것 |
| 12월 10일 0시 Z | 12월 10일에 들어갔다(직접 겪음) | 12월 10일이 될 것 |
| 날짜만(2026-12-10) | 12월 10일 | 12월 10일 |
일본 시간 캘린더에서는 Z의 0시가 일본 아침 9시에 해당합니다. 그래서 날짜는 밀리지 않는 계산입니다. 그렇지만 UTC보다 서쪽 지역 캘린더에서는 전날로 밀리는 계산이 됩니다. 어떤 경우에도 안정적인 건 역시 날짜만 넘기는 방식이네요.
가족 캘린더를 자동화하는 사람이 밟기 쉬운 점
가족이 공유하는 캘린더는 개인 기본 캘린더와 별도로 만드는 경우가 많을 겁니다. 구글 도움말을 보면 시간대는 캘린더마다 설정할 수 있다고 적혀 있습니다.
즉 내 기본 캘린더가 일본 시간이어도 공유 캘린더는 다른 설정일 수 있습니다. 이번 가족 캘린더가 왜 UTC였는지는 저도 정확히 모릅니다. 모르는 채로 운영하고 있었다는 게 솔직한 이야기입니다.
손으로 일정을 넣는 동안은 이 차이가 잘 드러나지 않을지도 모릅니다. 자동화해서 API로 넣기 시작하면 갑자기 모습을 드러내는 게 아닐까요.
개발자 문서에는 캘린더의 시간대가 “기본 시간대”라고도 불린다고 되어 있습니다. 일정 목록을 가져올 때도 이 시간대가 기준이 된다고 합니다. 자동화한다면 캘린더 설정은 한 번 봐 둬서 손해 볼 게 없다고 생각합니다.
누르면 라쿠텐 로그인 페이지가 열립니다. 로그인하면 캠페인 내용이 표시됩니다.
캘린더 시간대를 확인하는 절차
구글 캘린더 도움말을 따르면 컴퓨터에서의 확인 절차는 다음과 같습니다.
- 컴퓨터에서 구글 캘린더를 연다
- 왼쪽 “내 캘린더”에서 대상 캘린더에 커서를 올린다
- 더보기 아이콘에서 “설정 및 공유”를 연다
- 캘린더 설정에 있는 “시간대”를 본다
- 바꾸고 싶다면 도시나 국가를 검색해 선택한다
전체 “기본 시간대”는 오른쪽 위 설정 아이콘에서 여는 설정 화면에 있습니다. 이것과 캘린더별 설정은 별개이니 둘 다 봐 두면 좋겠습니다.
다만 도움말에는 “일정 주최자가 아니면 변경할 수 없다”는 주석도 있습니다. 공유 캘린더 설정을 바꾸려면 만든 사람에게 부탁하는 게 빠를지도 모릅니다.
등록 후에 확인할 것
구조를 고쳐도 마지막에는 눈으로 보는 게 가장 확실하다고 느낍니다. 제가 정한 확인 포인트는 다음 세 가지입니다.
- 등록한 일정을 캘린더에서 날짜까지 눈으로 확인한다
- 종일 일정이라면 종료일이 다음 날로 되어 있는지 본다
- 공유하는 가족의 스마트폰에서도 같은 날로 보이는지 확인한다
특히 해지 기한처럼 “밀리면 곤란한 일정”은 꼼꼼히 봅니다. 이번에도 눈으로 보고 알아챈 덕분에 살았습니다.
흔한 실패와 함정
제 경험과 공식 문서에서 생각할 수 있는 점을 정리했습니다.
- 종일 일정에 시각과 시간대를 붙여 넘겨 버린다
- 내 기본 캘린더와 공유 캘린더의 시간대가 같다고 믿어 버린다
- end.date에 시작일과 같은 날짜를 넣어 버린다
- 시작은 날짜, 종료는 일시처럼 형식을 섞어 버린다
- 등록됐다는 것만 확인하고 날짜까지는 보지 않는다
제가 밟은 건 첫 번째, 두 번째, 그리고 마지막입니다. 모두 자동화 초반에는 알아채기 어려운 것 같습니다.
시작하기 전에 확인할 것
- 등록할 캘린더의 시간대를 설정 및 공유 화면에서 봤다
- 내 기본 시간대와 어긋나지 않는지 확인했다
- 종일 일정을 날짜만으로 넘길 수 있는지 도구 사양을 확인했다
- 등록 후 종료일이 다음 날로 되어 있는지 보는 습관을 들였다
- 가족 기기에서도 같은 날로 표시되는지 한 번 확인했다
구조를 만들 때의 생각
이번 일로 자동화 순서에 대해 조금 다시 생각했습니다.
회사에서도 데이터를 주고받을 때 형식 불일치가 자주 일어납니다. 가족 일정도 알맹이는 비슷한 데이터 교환이더라고요. 그래서 보내는 쪽 표기와 받는 쪽 설정을 세트로 확인하는 게 중요하다고 느낍니다.
예전에 말로 한 가족 약속을 AI로 캘린더에 넣는 이야기를 썼습니다. 학교 안내문을 캘린더에 등록하는 구조에서는 종일 일정의 end를 다음 날로 하고 있습니다. 이번 사양 이야기는 그 뒷받침도 되었습니다.
시각 기준이 어긋나는 이야기는 cron의 날짜와 요일 함정 글에서도 조금 다뤘습니다. 자동화는 UTC와 어떻게 지내느냐가 중요한 것 같습니다.
자주 묻는 질문
Q. 종일 일정을 API로 만들 때는 무엇을 써야 하나요?
Google Calendar API에서는 start.date와 end.date를 쓴다고 되어 있습니다. 형식은 “yyyy-mm-dd” 날짜입니다. dateTime은 시각이 있는 일정용이라 종일 일정에는 쓰지 않습니다.
Q. end.date에는 무엇을 넣어야 하나요?
종료는 “포함하지 않음”으로 취급되므로 마지막 날의 다음 날을 넣습니다. 12월 10일 하루 일정이라면 end.date는 12월 11일입니다. 공식 샘플도 같은 형태였습니다.
Q. 종일 일정에서 timeZone을 지정하면 효과가 있나요?
개발자 문서에서는 종일 일정에서는 시간대 항목이 의미를 갖지 않는다고 되어 있습니다. 날짜만으로 넘기면 캘린더 시간대에 좌우되지 않을 겁니다.
Q. 캘린더마다 시간대가 다른가요?
구글 도움말에서는 캘린더별로 시간대를 변경하는 절차를 안내하고 있습니다. 그래서 기본 캘린더와 공유 캘린더의 설정이 다를 수도 있습니다. “설정 및 공유” 화면에서 확인할 수 있습니다.
Q. Z를 붙여 넘기면 반드시 올바른 날에 들어가나요?
저는 UTC 캘린더에서 올바른 날에 들어갔습니다. 다만 계산상으로는 캘린더 시간대에 따라 결과가 달라질 수 있습니다. 날짜만으로 넘길 수 있다면 그쪽이 더 안정적이라고 생각합니다.
Q. 공유 캘린더의 시간대를 바꿀 수 없어요.
구글 도움말에는 일정 주최자가 아니면 변경할 수 없다는 주석이 있습니다. 캘린더를 만든 사람에게 설정을 봐 달라고 하는 게 빠를지도 모릅니다.
Q. 이미 밀려서 들어간 일정은 어떻게 고치나요?
저는 올바른 표기로 일정을 다시 업데이트했습니다. 손으로 고칠 때도 일정을 열어 날짜를 바꾸면 됩니다. 고친 뒤에는 가족 기기에서도 표시를 확인해 두면 안심입니다.
참고한 공식 정보
- Events(Google Calendar API 레퍼런스, 영문)
- Calendars and events(Google Calendar API 가이드, 영문)
- Calendars(Google Calendar API 레퍼런스, 영문)
- 여러 시간대에서 구글 캘린더 사용하기(구글 캘린더 고객센터, 일본어 페이지)
정리
종일 일정은 “시각이 없는 날짜”입니다. 거기에 시간대가 붙은 일시를 넘기면 캘린더 쪽 설정에 따라 날짜가 밀릴 수 있습니다. 저희 가족 캘린더에서는 그게 하루 앞당겨지는 형태로 나타났습니다.
API 사양대로라면 종일 일정은 날짜만으로 넘기고 종료일은 다음 날로 합니다. 이번 Z 표기는 쓰고 있는 연동 도구에 맞춘 우회책이라는 위치입니다.
가족 캘린더를 자동화하고 있다면 한 번 캘린더 시간대를 확인해 보시는 건 어떨까요. 체험판 판단일처럼 기한을 관리하는 일정은 특히 밀리면 곤란하죠. 기한 관리하는 김에 매달 고정비도 한번 훑어보면 좋을 것 같습니다.
누르면 라쿠텐 로그인 페이지가 열립니다. 로그인하면 캠페인 내용이 표시됩니다.
이 글에는 제휴 광고가 포함되어 있습니다. 이 사이트의 링크를 통해 상품·서비스에 신청하시면 제휴사로부터 보상을 받을 수 있습니다. 또한 운영자는 라쿠텐 그룹 소속 직원으로, 사원 추천 프로그램을 통해 보상을 받는 경우가 있습니다. 기사 내용과 평가는 광고 유무와 관계없이 운영자의 실제 경험과 조사를 바탕으로 작성했지만, 위 관계를 이해하신 후 읽어 주시기 바랍니다. 자세한 내용은 면책조항·제휴 링크 안내를 참고해 주세요. 면책조항·제휴 링크 안내
이 글에는 기계 번역이 포함되어 있습니다. 정확한 조건은 라쿠텐 모바일 공식 사이트의 다국어 페이지에서 확인해 주세요.
라쿠텐 모바일의 통신 지역·전파 상황이 궁금하신 분은, 공식 전파 개선·조사 요청 양식 을 통해 문의하실 수 있습니다.