(Python) 그 날짜가 몇 주째인지 계산하기

특정한 년,월,일을 입력 받았을 때 그 날짜가 해당 월의 몇 째 주에 속하는지를 알려주는 함수를 작성해보자. 예를 들어 2020년 4월 27일 월요일은 4월의 5주차에 해당하는 날이다. 2020년 5월 15일은 2주차에 해당하는 날이다. 27, 15일은 각각 7로 나누는 것만으로도 3주나 차이가 나는데, 정확한 계산방법은 무엇일까?

(Python) 그 날짜가 몇 주째인지 계산하기 더보기

오일러 프로젝트 19

오일러 프로젝트 19번 문제는 20세기에서 매월 1일이 일요일인 경우를 세는 문제이다. 복잡해 보이지만 사실 쉬운 문제이다.

다음은 달력에 관한 몇 가지 일반적인 정보입니다 (필요한 경우 좀 더 연구를 해 보셔도 좋습니다).

  • 1900년 1월 1일은 월요일이다.
  • 4월, 6월, 9월, 11월은 30일까지 있고, 1월, 3월, 5월, 7월, 8월, 10월, 12월은 * 31일까지 있다.
  • 2월은 28일이지만, 윤년에는 29일까지 있다.
  • 윤년은 연도를 4로 나누어 떨어지는 해를 말한다. 하지만 400으로 나누어 떨어지지 않는 매 100년째는 윤년이 아니며, 400으로 나누어 떨어지면 윤년이다

20세기 (1901년 1월 1일 ~ 2000년 12월 31일) 에서, 매월 1일이 일요일인 경우는 총 몇 번입니까?

접근

기준 날짜를 정해놓고 날짜를 하루씩 올려가면서 1일이면서 월요일인 경우를 세는 코드를 작성하면 된다. 이 때 2월은 윤년일 때 29일이 있다. 윤년 여부를 결정하는 것은 위에 설명되어 있는데, 나이브하게 코딩하면

if year % 4 == 0 {
  if year % 100 == 0 {
     if year % 400 == 0 { return true }
     return false
  }
  return true
}

이렇게 중첩되는데, 넓은 범위에서부터 비교하면

  1. 400으로 나눠지면 윤년이다.
  2. 그 와중에 100으로 나눠지면 윤년이 아니다.
  3. 400으로 나눠지지 않는 경우에는 4로 나눠지면 윤년이다.

따라서 다음의 한 줄로 찾을 수 있다.

return (year % 400 == 0) || (year % 100 != 0) && (year % 4 == 0)

그외에 요일은 임의로 정하면 된다. 편의상 0을 일요일, 6을 토요일로 두겠다.

// 1900년 1월 1일은 일요일이다. (문제)
var (year, month, day, weekday) = (1900, 1, 1, 0)
var result = 0
while year < 2001 {
  let days: [Int] = {
    if year % 400 == 0 || year % 100 != 0 && year % 4 == 0 {
      return [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
    }
    return [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
  }()
  /// 조건에 맞으면 카운트를 1올린다.
  /// 20세기는 1901년부터 2000년이라는 점을 잊지말자
  if (1901...2000) ~= year, day == 1, weekday == 0 { result += 1 }
  /// 다음날로 이동한다.
  (day, weekday) = (day + 1, (weekday + 1) % 7)
  if day > days[month-1] {
    (day, month) = (1, month + 1)
    if month > 12 {
      (month, year) = (1, year + 1)
    }
  }
}
print(result)

파이썬 풀이

풀이 패턴 자체가 매우 단순하기 때문에 파이썬으로 같은 코드를 쓰는 것보다는 다른 풀이를 쓰고자 한다. datetime 모듈의 datetime 은 두 날짜간의 거리를 계산할 수 있는데, 이 때 쓰이는 값이 timedelta 객체이다. 반대로 datetime 에 timedelta 객체를 더하면 그 날이 지난 날짜를 얻을 수 있다.1 이를 이용해서 계산해보자. 참고로 weekday는 다른 날짜 속성과는 달리 메소드이므로 호출해서 값을 얻어야 한다.

import datetime

def solve():
  ## 1900-01-01을 참조할 필요없이 20세기 첫날부터 그냥 시작한다.
  t = datetime.datetime(1901, 1, 1)
  d = datetime.timedelat(days=1)
  result = 0
  while t.year < 2001:
    if t.day == 0 and t.weekday() == 0:
      result += 1
    t += d
  print(result)

 


  1. 이 때 사용되는 방식은 그냥 덧셈(+)이다. 

날짜 계산 레시피

아주 짧은 기간 사이의 차이를 계산하는 법

Javascript

Date 객체를 빼면 그 사이의 밀리세컨드 값이 나온다.

var start = new Date();
/* perform some time-taking work... */
var end = new Date();
console.log(end - start);
날짜 계산 레시피 더보기