{ }codelper
덧셈그리고·또는P0170

며칠 뒤, 며칠 전의 날짜

기준 날짜에서 며칠 뒤, 또는 며칠 전의 날짜를 구하는 계산기를 만든다. 첫 줄에 기준 날짜가 YYYY-MM-DD 꼴로 주어진다. 둘째 줄에 물음 수 n이 주어지고, 다음 n줄에 정수 k가 하나씩 주어진다. k가 양수이면 기준 날짜에서 k일 뒤, 음수이면 |k|일 전, 0이면 기준 날짜 그대로를 뜻한다. 달력은 지금 쓰는 그레고리력이고, 1582년보다 앞선 날짜는 나오지 않는다. 1월·3월·5월·7월·8월·10월·12월은 31일, 4월·6월·9월·11월은 30일, 2월은 28일이고 윤년의 2월만 29일이다. 연도가 4로 나누어떨어지면서 100으로는 나누어떨어지지 않거나, 400으로 나누어떨어지면 윤년이다. 그래서 2000년은 윤년이지만 1900년과 2100년은 윤년이 아니다. 물음마다 답 날짜를 YYYY-MM-DD 꼴(연도 네 자리, 월과 일은 두 자리)로 한 줄에 하나씩 입력 차례대로 출력하라.

입력
1900-01-01 ≤ 기준 날짜 ≤ 2100-12-31(달력에 있는 날), 1 ≤ n ≤ 1,000, -100,000 ≤ k ≤ 100,000
출력
물음마다 한 줄에 답 날짜(YYYY-MM-DD)
예시 1 · stdin
2024-02-28
6
1
2
-59
366
-1
0
stdout
2024-02-29
2024-03-01
2023-12-31
2025-02-28
2024-02-27
2024-02-28
예시 2 · stdin
1900-02-28
4
1
36525
-100000
100000
stdout
1900-03-01
2000-02-29
1626-05-15
2173-12-13
main.py
입력(stdin)

실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).

$ 준비됐어요

코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.

다른 언어로는?언어별 풀이 보기 · 8개 언어 풀이

날짜를 "1600년 1월 1일부터 며칠째"인 수 하나로 바꾸면 k일 뒤는 그 수에 k를 더하는 덧셈 하나가 되고, 다시 날짜로 바꾸면 돼요.
첫째 함정은 덧셈 자체예요.
읽은 줄은 문자열이라 JS·TS·크레이콘에서 수 + "1"은 더하기가 아니라 이어 붙이기("1540001")예요.
Java·C#도 한쪽이 String이면 +가 이어 붙이기이고, Python은 int + str이 TypeError로 멈춰요.
C·C++는 scanf·cin으로 처음부터 정수로 읽으니 이 문제가 없어요.
그래서 JS·TS Number(줄), 크레이콘 수로변환(), Java Integer.parseInt, C# int.Parse, Python int로 먼저 바꿔요.
둘째 함정은 윤년 조건이에요.
일곱 언어는 (y % 4 == 0 && y % 100 != 0) || y % 400 == 0, Python은 and·or로 써요.
&&가 ||보다 먼저 묶이는 것은 여덟 언어가 같아서 괄호가 없어도 같은 뜻이지만, gcc는 -Wall에서 괄호를 쳐 달라고 경고해요.
"4년마다 윤년"으로만 쓰면 1900-02-28의 다음 날이 1900-02-29가 돼요.
셋째 함정은 남은 날을 넘길 때의 비교예요.
남은 날이 그해 날 수와 딱 같으면 다음 해 1월 1일이니 >=로 물어야 하고, >로 물으면 12월 32일 같은 날이 나와요.
라이브러리로도 풀 수 있어요: Python date + timedelta(days=k), Java LocalDate.plusDays, C# DateTime.AddDays, C++20 std::chrono::sys_days.
JS의 Date는 조심해야 해요.
new Date("2024-02-28")은 UTC 자정으로 읽히는데 getDate()는 지역 시간이라 UTC보다 늦은 곳(미국 등)에서는 하루 전 날짜가 나오고, 지역 시간에 86,400,000밀리초씩 더하면 일광 절약 시간이 끝나는 날(하루가 25시간)에 날짜가 넘어가지 않아요.
그래서 getUTCDate·setUTCDate처럼 UTC로만 계산해요.
C와 크레이콘에는 날짜 라이브러리가 없어 직접 세요(C의 mktime도 지역 시간이에요).

Pythonmain.py · 45 줄
BASE = 1600  # 날짜를 1600-01-01부터 센 날 수로 바꾼다(답의 연도는 1626 ~ 2374)MONTH_DAYS = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]  def is_leap(y):    # 4로 나누어떨어지고 100으로는 안 나누어떨어지거나, 400으로 나누어떨어지면 윤년    return (y % 4 == 0 and y % 100 != 0) or y % 400 == 0  def year_days(y):    return 366 if is_leap(y) else 365  def month_days(y, m):    return 29 if m == 2 and is_leap(y) else MONTH_DAYS[m - 1]  def to_count(y, m, d):    total = d - 1    for yy in range(BASE, y):        total += year_days(yy)    for mm in range(1, m):        total += month_days(y, mm)    return total  def from_count(c):    y = BASE    while c >= year_days(y):  # 남은 날이 그해 날 수와 같으면 다음 해 1월 1일이다        c -= year_days(y)        y += 1    m = 1    while c >= month_days(y, m):        c -= month_days(y, m)        m += 1    return y, m, c + 1  y, m, d = map(int, input().strip().split("-"))start = to_count(y, m, d)n = int(input())for _ in range(n):    k = int(input())  # 수로 바꾼 다음에 더한다    ry, rm, rd = from_count(start + k)    print(f"{ry:04d}-{rm:02d}-{rd:02d}")
JavaScriptmain.js · 36 줄
const lines = require("fs").readFileSync(0, "utf8").split("\n");const BASE = 1600; // 날짜를 1600-01-01부터 센 날 수로 바꾼다(답의 연도는 1626 ~ 2374)const MONTH_DAYS = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];// 4로 나누어떨어지고 100으로는 안 나누어떨어지거나, 400으로 나누어떨어지면 윤년const isLeap = (y) => (y % 4 === 0 && y % 100 !== 0) || y % 400 === 0;const yearDays = (y) => (isLeap(y) ? 366 : 365);const monthDays = (y, m) => (m === 2 && isLeap(y) ? 29 : MONTH_DAYS[m - 1]);const toCount = (y, m, d) => {  let total = d - 1;  for (let yy = BASE; yy < y; yy++) total += yearDays(yy);  for (let mm = 1; mm < m; mm++) total += monthDays(y, mm);  return total;};const fromCount = (c) => {  let y = BASE;  while (c >= yearDays(y)) {    // 남은 날이 그해 날 수와 같으면 다음 해 1월 1일이다    c -= yearDays(y);    y++;  }  let m = 1;  while (c >= monthDays(y, m)) {    c -= monthDays(y, m);    m++;  }  return `${String(y).padStart(4, "0")}-${String(m).padStart(2, "0")}-${String(c + 1).padStart(2, "0")}`;};const [y, m, d] = lines[0].trim().split("-").map(Number);const start = toCount(y, m, d);const n = Number(lines[1]);const out = [];for (let i = 0; i < n; i++) {  const k = Number(lines[2 + i]); // 문자열 그대로 +하면 이어 붙이기가 된다 → 수로 바꾼 다음에 더한다  out.push(fromCount(start + k));}console.log(out.join("\n"));
TypeScriptmain.ts · 37 줄
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");const BASE = 1600; // 날짜를 1600-01-01부터 센 날 수로 바꾼다(답의 연도는 1626 ~ 2374)const MONTH_DAYS: number[] = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];// 4로 나누어떨어지고 100으로는 안 나누어떨어지거나, 400으로 나누어떨어지면 윤년const isLeap = (y: number): boolean => (y % 4 === 0 && y % 100 !== 0) || y % 400 === 0;const yearDays = (y: number): number => (isLeap(y) ? 366 : 365);const monthDays = (y: number, m: number): number => (m === 2 && isLeap(y) ? 29 : MONTH_DAYS[m - 1]);const toCount = (y: number, m: number, d: number): number => {  let total = d - 1;  for (let yy = BASE; yy < y; yy++) total += yearDays(yy);  for (let mm = 1; mm < m; mm++) total += monthDays(y, mm);  return total;};const fromCount = (c: number): string => {  let y = BASE;  while (c >= yearDays(y)) {    // 남은 날이 그해 날 수와 같으면 다음 해 1월 1일이다    c -= yearDays(y);    y++;  }  let m = 1;  while (c >= monthDays(y, m)) {    c -= monthDays(y, m);    m++;  }  return `${String(y).padStart(4, "0")}-${String(m).padStart(2, "0")}-${String(c + 1).padStart(2, "0")}`;};const [y, m, d] = lines[0].trim().split("-").map(Number);const start = toCount(y, m, d);const n = Number(lines[1]);const out: string[] = [];for (let i = 0; i < n; i++) {  const k = Number(lines[2 + i]); // 문자열 그대로 +하면 이어 붙이기가 된다 → 수로 바꾼 다음에 더한다  out.push(fromCount(start + k));}console.log(out.join("\n"));
JavaMain.java · 53 줄
import java.io.BufferedReader;import java.io.InputStreamReader; public class Main {    static final int BASE = 1600; // 날짜를 1600-01-01부터 센 날 수로 바꾼다(답의 연도는 1626 ~ 2374)    static final int[] MONTH_DAYS = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};     // 4로 나누어떨어지고 100으로는 안 나누어떨어지거나, 400으로 나누어떨어지면 윤년    static boolean isLeap(int y) {        return (y % 4 == 0 && y % 100 != 0) || y % 400 == 0;    }     static int yearDays(int y) {        return isLeap(y) ? 366 : 365;    }     static int monthDays(int y, int m) {        return (m == 2 && isLeap(y)) ? 29 : MONTH_DAYS[m - 1];    }     static int toCount(int y, int m, int d) {        int total = d - 1;        for (int yy = BASE; yy < y; yy++) total += yearDays(yy);        for (int mm = 1; mm < m; mm++) total += monthDays(y, mm);        return total;    }     static String fromCount(int c) {        int y = BASE, m = 1;        while (c >= yearDays(y)) { // 남은 날이 그해 날 수와 같으면 다음 해 1월 1일이다            c -= yearDays(y);            y++;        }        while (c >= monthDays(y, m)) {            c -= monthDays(y, m);            m++;        }        return String.format("%04d-%02d-%02d", y, m, c + 1);    }     public static void main(String[] args) throws Exception {        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));        String[] p = in.readLine().trim().split("-");        int start = toCount(Integer.parseInt(p[0]), Integer.parseInt(p[1]), Integer.parseInt(p[2]));        int n = Integer.parseInt(in.readLine().trim());        StringBuilder out = new StringBuilder();        for (int i = 0; i < n; i++) {            int k = Integer.parseInt(in.readLine().trim()); // 문자열과 +하면 이어 붙이기가 된다 → 수로 바꾼다            out.append(fromCount(start + k)).append('\n');        }        System.out.print(out);    }}
C#Main.cs · 51 줄
using System;using System.Text; class Program{    const int Base = 1600; // 날짜를 1600-01-01부터 센 날 수로 바꾼다(답의 연도는 1626 ~ 2374)    static readonly int[] MonthDaysTable = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };     // 4로 나누어떨어지고 100으로는 안 나누어떨어지거나, 400으로 나누어떨어지면 윤년    static bool IsLeap(int y) => (y % 4 == 0 && y % 100 != 0) || y % 400 == 0;    static int YearDays(int y) => IsLeap(y) ? 366 : 365;    static int MonthDays(int y, int m) => (m == 2 && IsLeap(y)) ? 29 : MonthDaysTable[m - 1];     static int ToCount(int y, int m, int d)    {        int total = d - 1;        for (int yy = Base; yy < y; yy++) total += YearDays(yy);        for (int mm = 1; mm < m; mm++) total += MonthDays(y, mm);        return total;    }     static string FromCount(int c)    {        int y = Base, m = 1;        while (c >= YearDays(y)) // 남은 날이 그해 날 수와 같으면 다음 해 1월 1일이다        {            c -= YearDays(y);            y++;        }        while (c >= MonthDays(y, m))        {            c -= MonthDays(y, m);            m++;        }        return $"{y:D4}-{m:D2}-{c + 1:D2}";    }     static void Main()    {        string[] p = Console.ReadLine().Trim().Split('-');        int start = ToCount(int.Parse(p[0]), int.Parse(p[1]), int.Parse(p[2]));        int n = int.Parse(Console.ReadLine());        var sb = new StringBuilder();        for (int i = 0; i < n; i++)        {            int k = int.Parse(Console.ReadLine()); // 문자열과 +하면 이어 붙이기가 된다 → 수로 바꾼다            sb.Append(FromCount(start + k)).Append('\n');        }        Console.Write(sb);    }}
C++main.cpp · 43 줄
#include <array>#include <cstdio>#include <iostream> constexpr int BASE = 1600; // 날짜를 1600-01-01부터 센 날 수로 바꾼다(답의 연도는 1626 ~ 2374)constexpr std::array<int, 12> MONTH_DAYS{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // 4로 나누어떨어지고 100으로는 안 나누어떨어지거나, 400으로 나누어떨어지면 윤년bool isLeap(int y) { return (y % 4 == 0 && y % 100 != 0) || y % 400 == 0; }int yearDays(int y) { return isLeap(y) ? 366 : 365; }int monthDays(int y, int m) { return (m == 2 && isLeap(y)) ? 29 : MONTH_DAYS[m - 1]; } int toCount(int y, int m, int d) {    int total = d - 1;    for (int yy = BASE; yy < y; yy++) total += yearDays(yy);    for (int mm = 1; mm < m; mm++) total += monthDays(y, mm);    return total;} void printDate(int c) {    int y = BASE, m = 1;    while (c >= yearDays(y)) { // 남은 날이 그해 날 수와 같으면 다음 해 1월 1일이다        c -= yearDays(y);        y++;    }    while (c >= monthDays(y, m)) {        c -= monthDays(y, m);        m++;    }    std::printf("%04d-%02d-%02d\n", y, m, c + 1);} int main() {    int y, m, d, n;    char dash;    std::cin >> y >> dash >> m >> dash >> d >> n;    int start = toCount(y, m, d);    for (int i = 0; i < n; i++) {        int k;        std::cin >> k;        printDate(start + k);    }}
Cmain.c · 43 줄
#include <stdio.h> #define BASE 1600 /* 날짜를 1600-01-01부터 센 날 수로 바꾼다(답의 연도는 1626 ~ 2374) */ static const int MONTH_DAYS[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; /* 4로 나누어떨어지고 100으로는 안 나누어떨어지거나, 400으로 나누어떨어지면 윤년 */int is_leap(int y) { return (y % 4 == 0 && y % 100 != 0) || y % 400 == 0; }int year_days(int y) { return is_leap(y) ? 366 : 365; }int month_days(int y, int m) { return (m == 2 && is_leap(y)) ? 29 : MONTH_DAYS[m - 1]; } int to_count(int y, int m, int d) {    int total = d - 1;    for (int yy = BASE; yy < y; yy++) total += year_days(yy);    for (int mm = 1; mm < m; mm++) total += month_days(y, mm);    return total;} void print_date(int c) {    int y = BASE, m = 1;    while (c >= year_days(y)) { /* 남은 날이 그해 날 수와 같으면 다음 해 1월 1일이다 */        c -= year_days(y);        y++;    }    while (c >= month_days(y, m)) {        c -= month_days(y, m);        m++;    }    printf("%04d-%02d-%02d\n", y, m, c + 1);} int main(void) {    int y, m, d, n;    scanf("%d-%d-%d", &y, &m, &d);    scanf("%d", &n);    int start = to_count(y, m, d);    for (int i = 0; i < n; i++) {        int k;        scanf("%d", &k);        print_date(start + k);    }    return 0;}
Craykonmain.cray · 66 줄
BASE = 1600; // 날짜를 1600-01-01부터 센 날 수로 바꾼다(답의 연도는 1626 ~ 2374)MONTH_DAYS = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; // 4로 나누어떨어지고 100으로는 안 나누어떨어지거나, 400으로 나누어떨어지면 윤년윤년인가(y){    돌려주기 y % 4 == 0 && y % 100 != 0 || y % 400 == 0;} 해의날수(y){    만약 (윤년인가(y))    {        돌려주기 366;    }    돌려주기 365;} 달의날수(y, m){    만약 (m == 2 && 윤년인가(y))    {        돌려주기 29;    }    돌려주기 MONTH_DAYS[m - 1];} 센날수(y, m, d){    total = d - 1;    반복 (yy = BASE; yy < y; yy++)    {        total += 해의날수(yy);    }    반복 (mm = 1; mm < m; mm++)    {        total += 달의날수(y, mm);    }    돌려주기 total;} 날짜로(c){    y = BASE;    동안 (c >= 해의날수(y))    {        c -= 해의날수(y);        y += 1;    }    m = 1;    동안 (c >= 달의날수(y, m))    {        c -= 달의날수(y, m);        m += 1;    }    돌려주기 ("" + y).앞채우기(4, "0") + "-" + ("" + m).앞채우기(2, "0") + "-" + ("" + (c + 1)).앞채우기(2, "0");} 칸 = 콘솔.줄읽기().공백제거().나누기("-");start = 센날수(칸[0].수로변환(), 칸[1].수로변환(), 칸[2].수로변환());n = 콘솔.줄읽기().수로변환();반복 (i = 0; i < n; i++){    k = 콘솔.줄읽기().수로변환(); // 문자열 그대로 +하면 이어 붙이기가 된다 → 수로 바꾼 다음에 더한다    콘솔.쓰기(날짜로(start + k));}