Smart Life US

← 목록 · 2026-08-14 · 엑셀·업무 자동화

구글시트 예약 가능 기간 계산하기: 오늘부터 며칠까지 자동 설정

구글시트 예약 가능 기간 계산하기: 오늘부터 며칠까지 자동 설정

도입: 지난 날짜·너무 먼 예약을 막고 싶을 때

구글시트로 입고 예약 시스템을 운영하다 보면 가장 먼저 부딪히는 문제가 있습니다. 이미 마감된 시간대나 너무 먼 미래까지 예약이 들어오는 상황입니다. 특히 운송사나 협력사가 직접 웹앱 예약 화면을 쓴다면, 오늘 마감 시각이 지난 뒤에도 같은 날 시간대를 선택하거나, 몇 달 뒤 날짜를 잡아 두는 사례가 반복됩니다. 이런 예약은 현장에서 다시 조정해야 하고, 담당자는 전화를 돌리며 일정을 재확인하는 데 시간을 쓰게 됩니다.

예약 가능 기간 자동 계산

이 글에서는 구글시트 예약 가능 기간 계산을 Apps Script로 자동화하는 방법을 정리합니다. 오늘 날짜를 기준으로 설정한 N일 이내까지만 예약을 열고, 오늘의 예약 마감 시각이 지나면 오늘 날짜는 목록에서 자동 제외되도록 만드는 것이 핵심입니다. 구글시트 입고 예약 시스템을 이미 쓰고 있다면, 이 로직 하나만 추가해도 “오늘 마감 이후 예약”과 “너무 먼 미래 예약”을 상당 부분 줄일 수 있습니다.


예약 가능 기간을 코드로 계산해야 하는 이유

예약 가능 날짜를 수동으로 관리하면 여러 가지 문제가 발생합니다. 보통은 시트에 날짜를 쭉 적어 두고, 예약 받지 않을 날은 색을 칠하거나 “X” 표시를 하는 방식으로 시작합니다. 마감 시각이 지나면 담당자가 오늘 날짜를 숨기거나 목록에서 지우기도 합니다. 단순해 보이지만 교대 시간, 인수인계, 야간 근무 등 변수가 많다 보니 제때 작업이 이루어지지 않는 경우가 자주 발생합니다.

웹앱이나 구글시트 사이드바로 예약을 받는 경우에는 또 다른 문제가 있습니다. 화면에 뜨는 날짜 목록을 “한 번 만들어 둔 정적 목록”으로 처리하는 경우가 많아, 매일 갱신해 주기 어렵습니다. 담당자가 직접 화면 코드를 건드리기 어렵기 때문에, 실제 운영 기준과 화면 표시가 어긋나는 날이 생깁니다.

이런 문제를 줄이기 위해서는 예약 가능 기간을 계산하는 공통 함수를 하나 두는 것이 좋습니다. 이 함수는 다음을 기준으로 동작합니다.

  • 현재 날짜·시간을 기준으로
  • SETTINGS 시트에 있는 “예약 가능일수(N일)”를 읽고
  • 오늘 예약 마감 시각을 확인한 뒤
  • 결과를 날짜 범위(시작~끝)와 화면용 목록 형태로 돌려줍니다.

이렇게 만들어 두면, 웹앱·사이드바·시트 드롭다운 등 여러 화면에서 모두 같은 함수만 호출하면 됩니다. 담당자는 SETTINGS 시트의 숫자와 마감 시각만 관리하면 되고, 날짜 목록을 직접 수정하는 반복 작업은 줄일 수 있습니다. 코드가 복잡하지 않으면서도, “마감 후 당일 예약을 자동으로 제외해 목록 갱신 누락을 줄일 수 있다”는 점에서 실무에 바로 적용하기 적합한 방식입니다.


예약 기간 계산의 핵심: 오늘, 마감 시각, N일

이번 글에서 구현하는 구글시트 예약 가능 기간 계산 로직은 세 가지 기준으로 정리할 수 있습니다.

첫째, 기준은 언제나 오늘(today) 입니다. 서버에서 스크립트를 실행하는 시각을 기준으로, 오늘 이전 날짜는 모두 예약 불가로 간주합니다. 과거 날짜를 다시 열어 줄 필요가 있더라도, 이 로직에서는 기본적으로 제외해 둔 상태에서 예외를 따로 처리하는 편이 안전합니다.

둘째, 오늘의 예약 마감 시각을 기준으로 오늘 포함 여부를 결정합니다. 앞선 글에서 이미 SETTINGS 시트에 “예약 마감 시각(예: 16:00)”을 저장해 두고, BOOK_timeToMinutes_() 같은 시간 비교용 함수도 만든 상태를 가정합니다.

  • 현재 시간이 마감 시각보다 이르면 → 오늘도 예약 가능
  • 현재 시간이 마감 시각을 지났으면 → 오늘은 예약 목록에서 제외

셋째, 예약 가능 최대 일수(N일)를 설정으로 관리합니다. 예를 들어 BOOKING_MAX_DAYS = 7이라고 입력해 두었다면,

  • 오늘이 8월 14일이고
  • 마감 시각 이전이라면 → 8월 14일~8월 20일
  • 마감 시각 이후라면 → 8월 15일~8월 21일

이 세 기준을 묶어 “시작 날짜와 끝 날짜”를 계산하는 내부 함수 하나를 만들고, 그 결과를 다시 화면용 배열로 바꾸면, 구글시트 입고 예약 시스템·Apps Script 예약 날짜 범위 설정에 바로 쓸 수 있습니다. 이 글에서는 날짜 형식을 Utilities.formatDate로 통일해 yyyy-MM-ddMM/dd(E) 조합으로 표현합니다. 화면과 백엔드가 같은 형식을 쓰도록 맞추는 것이 중요합니다.


1단계 — 예약 가능 기간 계산 함수: getBookingWindow_()

첫 단계에서는 “오늘부터 며칠까지 예약을 받을지” 계산해 주는 내부 함수를 만듭니다. 이 함수는 시작 날짜와 마지막 날짜(둘 다 Date 객체), 그리고 오늘 포함 여부 등을 하나의 객체로 돌려줍니다. 구글시트 오늘부터 N일 계산을 자동화하는 핵심 부분입니다.

이 코드는 “구글시트 → 확장 프로그램 → Apps Script → 기존 예약 프로젝트의 Code.gs 파일 맨 아래”에 붙여 넣습니다. 앞 편에서 loadCalendarConfig_(), BOOK_timeToMinutes_() 같은 기본 함수가 이미 있는 상태를 전제로 합니다. 붙여 넣은 뒤에는 저장(⌘S 또는 Ctrl+S)을 눌러 둡니다.

먼저 예약 가능일수와 마감 시각 설정에 쓸 상수를 모아 둡니다.

Apps Script (JavaScript)
// 예약 기간 계산용 설정 상수 → 여기만 본인 시스템에 맞게 바꾸세요
const BOOK_WINDOW_CONFIG = {                               // → 예약 기간 설정 객체
  SETTINGS_SHEET_NAME: 'SETTINGS',                         // → 설정 시트 이름
  KEY_MAX_DAYS: 'BOOKING_MAX_DAYS',                        // → 예약 가능일수 키
  KEY_CUTOFF_TIME: 'BOOKING_CUTOFF_TIME',                  // → 예약 마감 시각 키 (HH:MM)
  DEFAULT_MAX_DAYS: 7                                      // → 설정 없을 때 기본 7일
};                                                         
                                                          
// 예약 가능 기간(시작/끝 날짜)을 계산하는 내부 함수입니다.
// 앞 편에서 만든 loadCalendarConfig_(), BOOK_timeToMinutes_() 를 그대로 씁니다.
function getBookingWindow_() {                             // → 예약 기간 계산 시작
  const today = new Date();                                // → 지금 시각 가져오기
  const todayYmd = Utilities.formatDate(                   // → 오늘을 yyyy-MM-dd로
    today, Session.getScriptTimeZone(), 'yyyy-MM-dd'       // → 스크립트 시간대 사용
  );                                                       
                                                          
  const config = loadCalendarConfig_();                    // → 앞 편에서 만든 설정 로드
  const maxDaysSetting = config[BOOK_WINDOW_CONFIG.KEY_MAX_DAYS]; // → 일수 설정 읽기
  let maxDays = Number(maxDaysSetting);                    // → 숫자로 변환
  if (!Number.isFinite(maxDays) || maxDays <= 0) {         // → 잘못된 값이면
    maxDays = BOOK_WINDOW_CONFIG.DEFAULT_MAX_DAYS;         // → 기본값 7일 사용
  }                                                        
                                                          
  const cutoffStr = config[BOOK_WINDOW_CONFIG.KEY_CUTOFF_TIME];   // → 마감 시각 HH:MM
  let includeToday = true;                                 // → 기본은 오늘 포함
                                                          
  if (cutoffStr) {                                         // → 마감 시각 설정이 있을 때
    const cutoffMinutes = BOOK_timeToMinutes_(cutoffStr);  // → HH:MM을 분으로 변환
    const nowMinutes = today.getHours() * 60 + today.getMinutes(); // → 현재 시각(분)
    if (Number.isFinite(cutoffMinutes) &&                  // → 숫자면 비교 진행
        nowMinutes > cutoffMinutes) {                      // → 마감 시각 지난 경우
      includeToday = false;                                // → 오늘은 제외
    }                                                      
  }                                                        
                                                          
  const startDate = new Date(today);                       // → 시작 날짜 복사
  if (!includeToday) {                                     // → 오늘을 제외해야 하면
    startDate.setDate(startDate.getDate() + 1);            // → 시작을 내일로 이동
  }                                                        
                                                          
  const endDate = new Date(startDate);                     // → 끝 날짜 기준 복사
  endDate.setDate(endDate.getDate() + (maxDays - 1));      // → N일 범위 마지막 날짜
                                                          
  return {                                                 // → 기간 정보 반환
    startDate,                                             // → 시작 날짜
    endDate,                                               // → 마지막 날짜
    includeToday,                                          // → 오늘 포함 여부
    todayYmd                                               // → 오늘 날짜 문자열
  };                                                       
}                                                          

이 코드가 제대로 동작하는지 확인하려면, 같은 파일 맨 아래에 테스트 함수를 하나 더 추가한 뒤 실행합니다.

Apps Script (JavaScript)
// 예약 기간 계산 결과를 로그로 확인하는 테스트 함수입니다.
function BOOK_testGetBookingWindow_() {                    // → 테스트 전용 함수
  const win = getBookingWindow_();                         // → 기간 정보 가져오기
  Logger.log(JSON.stringify(win));                         // → 내용 전체를 로그로
}                                                          

Apps Script 편집기 상단 함수 목록에서 BOOK_testGetBookingWindow_를 선택하고 실행 버튼을 누른 후, 실행 로그를 열어 startDate, endDate, includeToday, todayYmd 값이 기대하는 대로 나오는지 확인합니다. SETTINGS 시트에서 BOOKING_CUTOFF_TIME을 현재 시간보다 이른 값과 늦은 값으로 바꿔 보면서, includeToday가 true/false로 바뀌는지 확인하면 예약 기간 자동화 로직이 의도대로 동작하는지 점검할 수 있습니다.


2단계 — 마지막 예약 가능 날짜만 필요할 때: getBookingMaxDate_()

실무에서는 구글시트 입고 예약 시스템 만들기 과정에서, “예약 가능 전체 기간”보다는 “마지막 예약 가능 날짜”만 필요한 경우도 많습니다. 예를 들어 프론트엔드 달력 위젯에 maxDate를 넘겨 주기만 해도, 사용자가 그 이후 날짜를 선택하지 못하게 막을 수 있습니다. 이때 앞 단계의 기간 계산 함수를 그대로 활용하면 구현이 간단해집니다.

아래 코드는 getBookingWindow_() 바로 아래에 이어서 붙여 넣습니다.

Apps Script (JavaScript)
// 예약 가능 기간의 마지막 날짜(yyyy-MM-dd 문자열)를 돌려주는 함수입니다.
function getBookingMaxDate_() {                            // → 마지막 날짜 계산
  const win = getBookingWindow_();                         // → 기간 정보 가져오기
  const endDate = win.endDate;                             // → 마지막 날짜 객체
  const tz = Session.getScriptTimeZone();                  // → 시간대 가져오기
  return Utilities.formatDate(endDate, tz, 'yyyy-MM-dd');  // → yyyy-MM-dd로 반환
}                                                          
                                                          
// 테스트용: 마지막 날짜만 로그로 확인합니다.
function BOOK_testGetBookingMaxDate_() {                   // → 테스트 전용
  const maxDate = getBookingMaxDate_();                    // → 마지막 날짜 가져오기
  Logger.log('Max booking date: ' + maxDate);              // → 결과 출력
}                                                          

편집기에서 BOOK_testGetBookingMaxDate_를 선택해 실행한 뒤, 로그에 Max booking date: 2026-08-21처럼 출력되는지 확인합니다. SETTINGS 시트의 BOOKING_MAX_DAYS 값을 7에서 5, 10 등으로 바꾸고 다시 실행했을 때 날짜가 그에 맞게 변하면, “오늘부터 N일 이내 예약” 계산이 제대로 연동되고 있는 것입니다.


3단계 — 화면에서 쓰기 좋은 날짜 목록: getBookingWindowForClient()

이제 계산된 예약 가능 기간을 화면에서 바로 사용할 수 있는 형태로 바꾸겠습니다. 웹앱, 사이드바, 또는 다른 클라이언트 코드에서 이 함수를 호출하면, 선택 박스나 날짜 버튼 목록을 바로 채울 수 있도록 만드는 것이 목표입니다. 구글시트 날짜 목록 생성 스크립트로도 그대로 활용 가능합니다.

반환 형식은 다음과 같이 설계합니다.

  • ymd: 저장·전송용 날짜 문자열(예: 2026-08-14)
  • label: 화면 표시용 문자열(예: 08/14(수))
  • isToday: 오늘 날짜인지 여부(true/false)

웹앱에서는 label을 드롭다운에 보여 주고, ymd를 실제 값으로 저장하면 됩니다. isToday는 “오늘”에만 표시를 달거나 기본 선택값을 지정할 때 활용할 수 있습니다.

아래 코드는 앞에서 만든 두 함수 바로 아래에 이어서 붙여 넣습니다.

Apps Script (JavaScript)
// 클라이언트(웹앱, 사이드바)가 쓰기 좋은 예약 가능 날짜 목록을 돌려줍니다.
function getBookingWindowForClient() {                     // → 화면용 목록 함수
  const win = getBookingWindow_();                         // → 기간 정보 가져오기
  const tz = Session.getScriptTimeZone();                  // → 시간대
  const result = [];                                       // → 결과 배열
                                                          
  const cur = new Date(win.startDate);                     // → 시작 날짜 복사
  const end = new Date(win.endDate);                       // → 마지막 날짜 복사
                                                          
  while (cur.getTime() <= end.getTime()) {                 // → 시작~끝까지 반복
    const ymd = Utilities.formatDate(                      // → yyyy-MM-dd 포맷
      cur, tz, 'yyyy-MM-dd'                               
    );                                                     
    const mmdd = Utilities.formatDate(                     // → MM/dd 포맷
      cur, tz, 'MM/dd'                                     
    );                                                     
    const dow = Utilities.formatDate(                      // → 요일 한글 약어
      cur, tz, 'E'                                         
    );                                                     
                                                          
    result.push({                                          // → 한 날짜 객체 추가
      ymd: ymd,                                            // → 저장용 날짜
      label: mmdd + '(' + dow + ')',                       // → 화면 표시용
      isToday: (ymd === win.todayYmd)                      // → 오늘 여부 표시
    });                                                    
                                                          
    cur.setDate(cur.getDate() + 1);                        // → 다음 날짜로 이동
  }                                                        
                                                          
  return result;                                           // → 전체 목록 반환
}                                                          
                                                          
// 테스트용: 예약 가능 날짜 목록을 로그로 확인합니다.
function BOOK_testGetBookingWindowForClient() {            // → 테스트 전용
  const list = getBookingWindowForClient();                // → 목록 가져오기
  Logger.log(JSON.stringify(list));                        // → 전체를 로그로
}                                                          

편집기에서 BOOK_testGetBookingWindowForClient를 실행하면, 실행 로그에 다음과 비슷한 배열이 찍힙니다.

TEXT
[
  {"ymd":"2026-08-14","label":"08/14(목)","isToday":true},
  {"ymd":"2026-08-15","label":"08/15(금)","isToday":false},
  ...
]

예약 마감 시각 이전에는 첫 번째 원소가 오늘 날짜이고, 마감 시각 이후에는 오늘이 빠지고 다음 날부터 시작하는지 확인합니다. 이렇게 확인되면, 웹앱에서는 google.script.run.getBookingWindowForClient()를 호출해 이 배열을 받아, 화면의 날짜 선택 영역을 자동으로 채울 수 있습니다.


실무 팁: 설정·테스트·확장 시 고려할 점

실제 운영 환경에서 이 로직을 사용할 때는 몇 가지를 더 챙기는 것이 좋습니다.

첫째, 설정값과 현장 정책을 일치시켜야 합니다. 예를 들어 현장에서는 “최대 5일 전까지만 예약”이라고 안내하면서, BOOKING_MAX_DAYS를 7로 두면 화면에는 7일치가 노출됩니다. 예약팀, 현장, 협력사에 전달한 안내 문구와 SETTINGS 시트 값을 항상 함께 점검해야 혼선을 줄일 수 있습니다.

둘째, 마감 시각의 의미를 명확히 정리해야 합니다. 이 글에서 쓰는 BOOKING_CUTOFF_TIME은 “예약 입력 마감 시각” 기준입니다. 입고 시간 마감(트럭 도착 가능 시간)과 구분되는 경우도 많기 때문에, 설정 시트에 비고 열을 두고 “예약 입력 마감(예: 16:00)”처럼 적어 두면 운영 인수인계가 훨씬 수월합니다.

셋째, 테스트는 시간을 움직여 가며 반복해서 진행하는 것이 좋습니다. 실제 마감 시각까지 기다리기 어렵다면,

  • BOOKING_CUTOFF_TIME을 현재 시각보다 1시간 전으로 설정하고 BOOK_testGetBookingWindow_()를 실행해 includeToday가 false가 되는지 보고
  • 다시 더 늦은 시각으로 바꾸어 true로 돌아오는지도 확인합니다.

이 과정을 거치면 “마감 이후 오늘 자동 제외”가 정확히 구현되었는지 안심하고 쓸 수 있습니다.

넷째, 프론트엔드와 백엔드의 날짜·시간대 개념을 통일해야 합니다. 이 글에서는 내부 저장용으로 yyyy-MM-dd, 화면용으로 MM/dd(E)를 사용했습니다. 브라우저의 로캘 설정, 모바일·PC 혼용 환경에서는 표시 형식이 달라 보일 수 있으니, 프론트 코드에서도 받은 ymd 문자열을 그대로 저장·전송하고, 표시만 따로 포맷팅하는 구조를 추천합니다. 날짜 형식 통일과 관련해서는 별도로 정리한 글인 구글시트 날짜 형식 통일 방법: 입고 예약 시스템 기본 5편도 함께 참고하면 도움이 됩니다.

마지막으로, 예약 불가일(공휴일·재고조사일 등)을 따로 관리하는 구조를 준비하는 것이 좋습니다. 지금 소개한 함수들은 “오늘부터 N일 이내”라는 기간 필터만 담당합니다. 실제 운영에서는 여기에 “휴무일 목록”을 추가로 두고, getBookingWindowForClient()에서 해당 날짜를 건너뛰는 방식으로 확장하면 유지 보수가 쉽습니다. 기간 계산 로직은 그대로 두고, 나중에 불가일·특정 요일 제외 등의 규칙을 한 겹 더 씌우는 구조가 장기 운영에서 유리합니다.


정리

예약 시스템에서 가장 잦은 실수 중 하나가 “마감된 날과 너무 먼 미래 날짜가 계속 열려 있는 것”입니다. 구글시트와 Apps Script를 함께 사용하면, 오늘 기준 N일 이내의 예약 가능 기간을 자동 계산하고, 마감 시각 이후에는 오늘을 제외한 날짜만 노출하도록 손쉽게 구현할 수 있습니다. 이 글에서 정리한 getBookingWindow_(), getBookingMaxDate_(), getBookingWindowForClient() 세 함수는 그 구조를 단순하게 유지하면서도 실무에 바로 적용할 수 있는 수준의 기능을 제공합니다.

지금 바로 할 수 있는 행동은 한 가지입니다. 현재 사용 중인 예약 시트에 SETTINGS 시트를 만들고, BOOKING_MAX_DAYSBOOKING_CUTOFF_TIME 두 값을 입력한 뒤, 이 글의 코드를 Apps Script 프로젝트에 그대로 붙여 넣어 테스트해 보시기 바랍니다. 오늘 기준으로 어떤 날짜까지 예약을 열어 둘지, 그리고 마감 이후 오늘이 자동으로 빠지는지 직접 확인해 보면, 이후 예약 화면(UI) 자동화 작업도 훨씬 수월해집니다.