지하철 앱마다 도착시간이 다른 이유 (원천 데이터로 확인했습니다)

지하철 앱마다 도착 시간이 다르게 나오는 건 앱 버그가 아닙니다. 서울시가 배포하는 원천 데이터 자체가 "보정하지 않은 값"으로 나가고, 보정 책임을 앱에 떠넘기기 때문입니다. 그래서 앱마다 화면이 갈립니다.

요약 서울시 명세는 "현재시각과 recptnDt의 차이만큼 열차가 더 진행한 것으로 보정해서 사용해야 합니다"라고 못 박아 뒀습니다. 원천 값은 매초 줄지 않고 10초 안팎으로 계단식 점프하며, 같은 응답 안에서도 호선마다 생성 시각이 어긋납니다. 앱은 이 계단을 어떻게 다듬느냐를 각자 정합니다. 그래서 다릅니다.

앱마다 다른 건 설계입니다

서울 열린데이터광장의 「서울시 지하철 실시간 도착정보」(OA-12764) 페이지에는 주의사항이 이렇게 적혀 있습니다.

원천에서 데이터가 수집 및 가공되어 서비스되는 과정에서 시간 차가 발생할 수 있습니다. 출력값 중 recptnDt(열차 도착정보를 생성한 시각)는 데이터가 생성된 시간을 의미하며 현재시각과 recptnDt의 차이 만큼 열차가 더 진행한 것으로 보정해서 사용해야 합니다.

명세가 직접 든 예시는 이렇습니다. 현재시간이 10시 5분 30초인데 recptnDt가 10시 3분 30초라면 2분의 시차가 있으니, 도착정보를 2분 당기거나 한 역을 더 진행한 것으로 판단하라는 겁니다.

이 문장이 전부를 설명합니다. 원천은 보정되지 않은 과거 시점의 값을 그대로 내보냅니다. 보정을 할지, 얼마나 할지, 어떻게 할지는 각 앱이 알아서 정합니다. 어떤 앱은 원천 값을 그대로 띄우고, 어떤 앱은 명세가 시키는 보정을 얹어 다듬습니다. 옆 사람 폰과 1~2분 차이가 나는 건 대부분 여기서 생깁니다.

즉 "어느 앱이 맞나"는 애초에 답이 없는 질문입니다. 정확히는 **"원천이 준 값에 각 앱이 서로 다른 해석을 얹은 결과"**입니다.

원천 데이터를 직접 관측해 봤습니다

주장으로 끝내지 않기 위해, 원천 API를 직접 5초 간격으로 폴링해 관측했습니다. 2026년 7월 17일 밤 10시 6분부터 10시 16분까지, 강남역 기준 120행을 봤습니다. 아래는 그때 실제로 관측된 값입니다.

원천은 10초 안팎으로 새로 만들어집니다

2호선 데이터의 recptnDt가 바뀌는 간격을 재 봤더니 15초, 6초, 15초, 16초, 11초, 16초, 11초, 15초였습니다. 대체로 10초 안팎(짧게는 6초, 길게는 16초)으로 새 데이터가 생성됩니다. 매초가 아닙니다.

그래서 앱이 원천 값을 그대로 보여주면, 화면의 숫자는 10초 넘게 멈춰 있다가 한 번에 툭 바뀝니다.

도착 예정 시간은 줄어드는 게 아니라 점프합니다

이게 핵심입니다. 2호선 6383 열차의 도착 예정 초(barvlDt)를 추적한 실측 기록입니다.

관측 시각원천 값화면 문구
22:08:06 ~ 22:08:16530초8분 50초 후
22:08:21420초7분 후
22:08:21 ~ 22:09:11420초7분 후 (50초간 고정)

10초 동안 "8분 50초 후"에 멈춰 있다가, 한 번에 110초가 사라지고 "7분 후"로 뛰었습니다. 그러고는 다시 50초 동안 "7분 후"에 붙박여 있었습니다. 같은 시간대에 2호선 8381 열차는 45초 동안 "전역 도착"에 고정돼 있다가 "전역 출발"로 넘어갔습니다.

여기서 놓치기 쉬운 점이 하나 있습니다. 원천 값이 50초간 "7분 후"에 고정돼 있는 동안에도 열차는 실제로 계속 진행합니다. 명세가 "현재시각 − recptnDt만큼 더 진행한 것으로 보정하라"고 적은 이유입니다. 즉 갱신 사이의 raw 숫자는 실제보다 남은 시간을 많게 보여주고 있는 셈입니다.

원천 값은 매끄러운 초시계가 아니라 뚝뚝 끊긴 계단입니다. 앱은 이 계단 앞에서 둘 중 하나를 고를 수밖에 없습니다.

  • 원천을 그대로 표시: 정직하지만 시계가 멈춘 것처럼 보이고, 갑자기 2분이 사라집니다.
  • 명세대로 보정하거나 자체 카운트다운으로 매초 깎기: 부드럽고 실제 위치에 더 가까울 수 있지만, 갱신 순간 숫자가 되돌아가거나 튑니다.

둘 다 틀린 게 아닙니다. 다른 선택입니다. 두 앱을 나란히 놓고 비교하면 당연히 다르게 보입니다.

같은 화면 안에서도 호선끼리 2분 가까이 어긋납니다

강남역을 한 번 조회한 응답 하나를 뜯어봤습니다. 각 행의 recptnDt를 서로 비교하면 이렇습니다. (참고로 응답 JSON에는 응답 전체의 생성 시각 필드가 없어, 아래 "기준 시각"은 API가 응답을 내보낸 HTTP Date 헤더 22:12:59입니다.)

호선recptnDtDate 헤더 대비
2호선22:12:1940초 과거
신분당선22:14:1273초 미래
신분당선22:14:1677초 미래

기준 시각을 빼고 두 recptnDt만 직접 비교해도 결론은 같습니다. 2호선(22:12:19)과 신분당선(22:14:12)의 "지금"이 약 1분 53초 어긋나 있습니다. 신분당선은 아예 미래 시각을 내놓습니다. 같은 호선 안에서도 열차마다 recptnDt가 갈리는 경우가 있었습니다.

서울시가 시키는 대로 "현재시각 − recptnDt"만큼 보정하면, 호선마다 보정량이 달라지고 신분당선은 음수 보정이 됩니다. 이걸 무시할지, 0으로 눌러버릴지, 그대로 적용할지도 앱마다 다릅니다. 환승역에서 유독 이상하게 느껴진다면 이유가 여기에 있습니다.

'전역 출발'이 무슨 뜻인가

의외로 많이 헷갈리는 문구입니다. 군대 전역이 아닙니다. 前驛, 즉 "이 역 바로 앞 역을 방금 출발했다"는 뜻입니다.

실측으로 잡은 문구 순서는 이렇습니다.

  1. [N]번째 전역 (역명) — N개 역 앞에 있음
  2. 전역 도착 — 바로 앞 역에 도착
  3. 전역 출발 — 바로 앞 역을 출발 (곧 옵니다)
  4. 당역 진입 — 지금 승강장으로 들어오는 중
  5. 당역 도착
  6. 당역 출발

"전역 출발"이 뜨면 짐 챙기면 됩니다. 실제로 8381 열차가 "전역 도착"(90초)에서 "전역 출발"(80초)로 넘어가는 순간을 관측했습니다.

"N분 M초 후"처럼 초 단위까지 붙는 문구는 원천의 초 값(150초, 420초, 630초)을 그대로 문자열로 만든 것입니다. 앱이 계산한 게 아니라 원천이 준 그대로입니다.

앱 없이 원천을 직접 확인하는 방법

앱 화면이 의심스러울 때 기준점을 잡는 방법입니다.

첫째, 승강장 전광판이 가장 앞단입니다. 서울시 명세가 "원천에서 데이터가 수집 및 가공되어 서비스되는 과정에서 시간 차가 발생한다"고 밝힌 만큼, 앱 화면은 수집·가공·전송을 다 거친 뒤의 값입니다. 전광판은 그 앞단에 있습니다. 역에 도착했다면 폰보다 전광판을 보는 게 맞습니다. (전광판이 내부적으로 어떤 신호 체계를 쓰는지는 공개된 1차 자료를 찾지 못했으므로 단정하지 않겠습니다.)

둘째, 원천 API를 직접 조회할 수 있습니다. 서울 열린데이터광장에서 인증키를 발급받으면 누구나 호출할 수 있습니다. 형식은 아래와 같습니다.

http://swopenapi.seoul.go.kr/api/subway/{인증키}/json/realtimeStationArrival/0/15/{역명}

응답에서 arvlMsg2(도착 메시지), arvlMsg3(현재 위치), recptnDt(데이터 생성 시각)를 보면 앱이 무엇을 얼마나 가공했는지 역산할 수 있습니다. 데이터는 공공누리 1유형(출처표시, 상업적 이용·변경 가능)으로 공개돼 있습니다.

셋째, 앱 두 개가 다르면 원천과 대조하세요. 원천에 가까운 쪽이 "덜 다듬은" 값이고, 부드럽게 줄어드는 쪽이 "앱이 보정하거나 계산한" 값입니다. 어느 쪽을 믿을지는 상황에 따라 다릅니다. "전역 출발"·"당역 진입" 같은 위치 문구는 원천 그대로가 신뢰할 만합니다. 반면 "N분 후" 같은 숫자 카운트는, 갱신 사이 raw 값이 실제보다 남은 시간을 많게 보일 수 있으니 부드럽게 줄어드는 화면 쪽이 실제에 더 가까울 수 있습니다.

지하철 실시간 도착정보 조회

역 이름만 넣으면 서울시 원천 데이터를 보정 없이 그대로 보여줍니다 — 내 앱 화면이 맞는지 대조할 기준점

역 이름을 정확히 넣어야 조회됩니다

원천 API는 역명 표기가 조금만 달라도 데이터가 없다고 답합니다. 아래는 직접 조회해 확인한 결과입니다.

조회 실패조회 성공
응암응암순환(상선)
천호천호(풍납토성)
몽촌토성몽촌토성(평화의문)
공릉공릉(서울산업대입구)
이수 / 총신대입구총신대입구(이수)

주의할 점이 두 가지 있습니다.

공식 안내가 실제와 어긋나는 항목이 있습니다. 서울시 안내는 "대모산입구 → 대모산으로 조회"라고 적어 뒀지만, 실측은 반대였습니다. 대모산입구는 정상 조회되고 대모산은 데이터가 없다고 나옵니다. 안내 문서가 실제를 따라오지 못한 것으로 보입니다.

공식 목록이 전부도 아닙니다. 총신대입구(이수)는 안내의 참조 목록에 없는데도 괄호 표기가 필요합니다.

조회되지 않는 구간도 있습니다

명세는 "서울시 이외의 역구간은 미제공"이라고 적고 광명·서동탄·춘천을 예로 듭니다. 실제로 광명과 서동탄은 조회되지 않았습니다.

다만 서울시 밖이라고 전부 안 되는 건 아니었습니다. 판교·인천·부평·수원은 정상적으로 조회됐습니다. "수도권 전체가 안 된다"고 이해하면 틀립니다. 구간별로 갈립니다.

도착 코드에 대해 (관측된 범위에서만)

응답에는 arvlCd라는 숫자 코드가 함께 옵니다. 관측된 조합은 다음과 같습니다.

arvlCd함께 관측된 메시지
0당역 진입
1당역 도착
3전역 출발
5전역 도착
99N분 M초 후 (운행 중)

이 표는 우리가 직접 관측한 조합입니다. 다만 arvlCd가 1인데 메시지는 "[10]번째 전역"인 행도 관측됐습니다. 코드와 문구가 항상 일치하지는 않으니, 코드보다 메시지를 믿는 편이 안전합니다.

정리

  • 앱마다 다른 건 버그가 아니라 설계입니다. 서울시가 명세에 "보정해서 사용하라"고 적어 뒀고, 보정 방식은 앱이 각자 정합니다.
  • 원천은 10초 안팎으로 갱신되고, 도착 예정 시간은 45~50초 고정됐다가 100초 넘게 점프합니다. 매끄럽게 줄어드는 화면은 앱이 만든 것입니다.
  • 같은 응답 안에서도 호선 간 데이터 생성 시각이 2분 가까이 어긋납니다. 환승역에서 이상한 이유입니다.
  • "전역 출발"이면 곧 옵니다. 앞 역을 방금 떠났다는 뜻입니다.
  • 승강장에 있다면 전광판이 가장 앞단의 값입니다.

결국 믿을 기준은 하나입니다. 앱이 뭘 얼마나 가공했는지 모르겠다면, 가공되지 않은 원천이 뭐라고 하는지 직접 보면 됩니다.

지하철 실시간 도착정보 조회

역 이름만 넣으면 서울시 원천 데이터를 보정 없이 그대로 보여줍니다 — 내 앱 화면이 맞는지 대조할 기준점

자주 묻는 질문

그래서 어느 앱이 제일 정확한가요?

답할 수 없습니다. 우리가 관측한 건 앱이 아니라 원천 데이터이고, 각 앱이 어떤 보정을 하는지는 공개돼 있지 않습니다. 다만 확실한 건, 어떤 앱도 원천 피드가 담지 않은 정보를 새로 만들어낼 수는 없다는 점입니다. 원천 raw 값은 과거 시점(recptnDt)의 값이라, 오히려 명세가 요구하는 보정을 제대로 적용한 앱이 실제 위치에 더 가까울 수 있습니다. 부드럽게 보여주느냐 계단으로 보여주느냐는 표현의 문제이고, 그 위에 얹은 보정이 실제와 얼마나 맞느냐는 앱마다 다릅니다.

도착 시간이 몇십 초 동안 안 줄어드는데 앱이 멈춘 건가요?

정상입니다. 원천 값이 실제로 고정돼 있습니다. 2호선 열차 하나가 50초 동안 "7분 후"에 붙박여 있는 걸 실측했습니다. 원천을 그대로 보여주는 앱이라면 그동안 숫자가 안 움직이는 게 맞습니다. 다만 그동안 열차는 계속 진행하므로, 고정된 raw 숫자는 실제보다 여유가 있어 보일 수 있습니다. 그러다 한 번에 뛰는 것도 정상입니다.

환승역에서 유독 시간이 이상한데 왜 그런가요?

한 응답 안에서도 호선마다 데이터 생성 시각이 다르기 때문입니다. 강남역에서 2호선은 40초 과거, 신분당선은 73초 미래의 시각을 달고 왔습니다. 두 호선의 "지금"이 1분 53초 어긋난 셈입니다. 같은 화면에 나란히 놓여 있어도 기준 시각이 다릅니다.

전광판과 앱이 다르면 뭘 믿어야 하나요?

전광판입니다. 서울시 명세가 밝히듯 앱 화면은 데이터가 수집·가공·전송되는 과정을 다 거친 뒤의 값이고, 그 과정에서 시간 차가 생깁니다. 전광판은 그 앞단에 있습니다. 다만 역에 도착하기 전이라면 전광판을 볼 수 없으니, 그때는 원천 데이터를 가공 없이 보여주는 화면이 가장 가까운 대안입니다.

가격 보기카톡 무료 상담