ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • python 만 나이, 살아온 날 계산
    Python/파이썬 자료구조 알고리듬 2021. 6. 2. 11:30
    반응형

    웹으로 만들어 보았습니다.

    https://comdoc.pythonanywhere.com/birth

     

    만 나이 계산기

    만 나이 계산기 생년월일(양력)을 입력하십시오.

    comdoc.pythonanywhere.com

     

    파이썬의 datetime 모듈 사용법

    https://wikidocs.net/104845
    https://dojang.io/mod/page/view.php?id=2463
    https://docs.python.org/ko/3/library/datetime.html

    시간을 빼고 더할 수 있다는 것이 재미있습니다.

    만 나이 전에 살아온 날을 먼저 계산해 봅시다.

    쉬우니까요...

     

    살아온 날 계산기

    # 살아온 날 계산기 2021-06-01 by 컴닥
    
    from datetime import datetime
    
    # birth = input('양력 생일(YYYY-MM-DD)을 입력하세요. ')
    birth = '2021-06-01'
    birth = datetime.strptime(birth, '%Y-%m-%d')
    today = datetime.now()
    print(f"{birth.strftime('%Y-%m-%d')}부터 {today.strftime('%Y-%m-%d')}까지") 
    print(f"{(today - birth).days}일")

    * 생일 0시에 태어난 걸로 가정한 계산 결과입니다.

     

    문자열을 시간 객체로 변환 

    str을 시간 객체로 변환할 때는 str'p'time 메서드를 사용합니다.
    문자열, format을 받아서 시간 객체로 변환합니다. 

    * 시간을 문자열로 변환할 때는 str'f'time을 사용합니다.  

     

    시간 연산 결과는 timedelta 객체

    시간을 연산한 결과는
    datetime.timedelta 객체입니다.
    일수(days)와 시간으로 환산되어 있습니다.
    365 days, 17:13:56.876041

     

    날짜 부분만 가져오기 

    timedelta 객체의
    days 속성으로
    days 부분만 얻을 수 있습니다.

    datetime 객체는
    date() 메서드로
    (날짜만 남아있는)
    'datetime.date' 객체를
    가져올 수 있습니다.

    * date() 메서드를 사용하지 않아도
    날짜 계산에는 문제가 없지만,
    사용하는 게 좀 더 깔끔합니다.

    # 살아온 날 계산기 2021-06-01 by 컴닥
    
    from datetime import datetime
    
    # birth = str(input('양력 생일(YYYY-MM-DD)을 입력하세요. '))
    birth = '2021-06-01'
    birth = datetime.strptime(birth, '%Y-%m-%d').date()
    today = datetime.now().date()
    print(f"{birth}부터 {today}까지")
    print(f"{(today - birth).days}일")

    * 생일 0시에 태어난 것으로 가정하고, 
    오늘 0시까지의 일수를 계산한 것입니다. 

    date.today()를 이용할 수도 있죠. 

    # 살아온 날 계산기 2021-06-01 by 컴닥
    
    from datetime import datetime, date
    
    # birth = str(input('양력 생일(YYYY-MM-DD)을 입력하세요. '))
    birth = '2021-06-01'
    birth = datetime.strptime(birth, '%Y-%m-%d').date()
    today = date.today()
    print(f"{birth.strftime('%Y-%m-%d')}부터 {today.strftime('%Y-%m-%d')}까지")
    print(f"{(today - birth).days}일")

     

     

    만 나이 계산기

    2021년(올해)에서 생년을 뺀 뒤,

    생일이 지나지 않았으면(=미만)
    1을 빼주면 됩니다.

    생일이거나 생일이 지났으면(=이상)
    그냥 두면 됩니다.

    # 만 나이 계산기 2021-06-01 by 컴닥
    from datetime import datetime
    
    # birth = str(input('양력 생일(YYYY-MM-DD)을 입력하세요. '))
    birth = '2020-02-29'
    birth = datetime.strptime(birth, '%Y-%m-%d').date()
    today = datetime.now().date()
    year = today.year - birth.year
    if today.month < birth.month:
        year -= 1
    elif today.month == birth.month and today.day < birth.day:
        year -= 1
    
    print(f"{birth.strftime('%Y-%m-%d')}부터 {today.strftime('%Y-%m-%d')}까지")
    print(f'만나이는 {year}살입니다.')

     

    조금 더 깔끔한 방법이 없을까
    생각해보다가,

    생일(birth)의 연도만
    올해로 바꿔서
    (birthday_of_this_year)
    두 날짜를 비교하면
    될 것 같았지만, 

    2020년 2월 29일 생은~!!!

    다음은 실패한 코드입니다. 

    # 만 나이 계산기 2021-06-01 by 컴닥
    from datetime import datetime
    
    # birth = str(input('양력 생일(YYYY-MM-DD)을 입력하세요. '))
    birth = '2020-02-29'
    birth = datetime.strptime(birth, '%Y-%m-%d').date()
    today = datetime.now().date()
    birthday_of_this_year = birth.replace(year=today.year)
    year = today.year - birth.year
    if today < birthday_of_this_year:
        year -= 1
    
    print(f"{birth.strftime('%Y-%m-%d')}부터 {today.strftime('%Y-%m-%d')}까지")
    print(f'만나이는 {year}살입니다.')
    ValueError: day is out of range for month

     

    아래부턴 재미로...
    시간 낭비 싫으시면 결론부터 읽으시길... 

    쓸데없이 정밀(?)한 만 나이 계산기

    외국 영화에선 만 나이를 개월까지 말하더군요. 
    만약 만 나이를 일 단위까지 계산하면 어떨까요?

    '23년 3개월 6일 동안 살아왔습니다.'라고
    이야기하는 건 쉽지 않을 것 같습니다.

    코딩으로 한 번..

     

    생일이 돌아와야 1살~!

    만 나이를 계산하는 기준은 
    365일이 아니라 
    생일임을 알 수 있습니다.

    매년 생일(생시)이 돌아와야 
    1살을 먹는 겁니다.

    1990년 2월 15일 0시 생이라면
    1991년 2월 15일 0시가 되어야
    1살인 거죠.

     

    윤년, 윤분, 윤초

    윤년, 윤분, 윤초가 있다고
    '생일 날짜'가 바뀌던가요?  

    윤년 윤분 윤초가 있더라도
    생일은 '매년 같은 날짜'입니다. 

    만나이의 기준은 심플합니다.
    '생일'이 돌아오면 1년~!

     

    그런데, 생일이 안 돌아온다면?
    2월 29일 생은? 31일 생은?

    * 만 나이를 일 까지 계산하는 게 삽질인 이유

    위 방식으로 월 단위를 계산한다면 
    15일 0시 생은
    다음 달 15일 0시가 되어야
    한 달을 더 산 게 됩니다.

    그런데...
    생일이 31일이고,
    지난달은 30일로 끝났다면, 
    이번 달 1일은 생일일까요? 
    아니면 생일이 지난 걸까요?

    생일이 지났다고 생각하는 것이
    합리적인 것 같습니다.

    31일생에게 1일이 생일이면,
    1일생에겐 2일이 생일일까요? 

    지난달의 날짜가 많든 모자라든
    달이 지났으면 새로 카운트하는 게
    일반적일 겁니다. (아니면 말고)

    제가 2월 29일 생이라면
    공식적으로는 2월 28일까지는 
    생일 전이라고 말할 것 같고,
    3월 1일이 되면
    생일이 지났다고 말할 것 같습니다. 

    만나이에서는
    생일이 돌아오기 전에는 생일 전이고, 
    생일이 지난 뒤에는 생일 후라고 하니까요. 

    없는 생일이 지났다고 할 수 있냐?
    라고 물으신다면,
    할 말은 없습니다만... 

     

    본론

    코드는 다음과 같습니다. 

    >>> 는 테스트 코드입니다.
    날짜를 다루는 건 헷갈리는 일입니다. 
    테스트 코드를 쓰는 게 편합니다. 
    파이썬 독 테스트 참고 

    # 연-월-일 만 나이 계산기 2021-06-01 by 컴닥
    
    from datetime import datetime, timedelta
    
    
    def birth(birthday: str, today: str):
        """
        >>> birth('2021-10-31', '2021-10-31')
        (0, 0, 0)
        >>> birth('2021-10-31', '2021-11-1')
        (0, 0, 1)
        >>> birth('2021-10-31', '2021-12-1')
        (0, 1, 1)
        >>> birth('2021-11-30', '2021-12-1')
        (0, 0, 1)
        >>> birth('2021-10-30', '2021-11-01')
        (0, 0, 2)
        >>> birth('2020-2-29', '2021-03-01')
        (1, 0, 1)
        """
        birthday = datetime.strptime(birthday, '%Y-%m-%d').date()  # 문자열을 날짜로 바꿉니다.
        if today == '':
            today = datetime.now().date()  # 현재 날짜를 얻습니다.
        else:
            today = datetime.strptime(today, '%Y-%m-%d').date()  # 문자열을 날짜로 바꿉니다.
        if birthday > today:
            print('생일이 오늘보다 뒤입니다.')
            return 0, 0, 0
    
        age_day = today.day - birthday.day
        age_month = today.month - birthday.month
        age_year = today.year - birthday.year
    
        # 일 계산
        if age_day < 0:
            age_month -= 1
            last_month_last_day = (today.replace(day=1) - timedelta(days=1)).day  # 지난 달의 말일 = 지난 달의 날수
            if last_month_last_day > birthday.day:  # 생일: 29일, 지난달 날 수: 30일
                age_day += last_month_last_day
            else:  # 생일: 31일, 지난달 날수: 30
                age_day = today.day
    
        # 월 계산
        if age_month < 0:
            age_year -= 1
            age_month += 12
    
        return age_year, age_month, age_day
    
    
    def main():
        # birth = str(input('양력 생일(YYYY-MM-DD)을 입력하세요. '))
        birthday = '2021-10-31'
        today = '2021-12-1'
        print(birth(birthday, today))
    
    
    main()

    받아 내림

    전체적으로는
    '받아 내림'이 여러 번 있는
    뺄셈과 같습니다.

    * '10진법'이 아니라
    '역법'이라는 점만 다릅니다.

    즉, 오늘 날짜에서 생일을 뺀
    각각(월, 일)의 결과가 0보다 작으면, 
    더 큰 단위를 하나 가져오면 됩니다. 

    일 계산도 기본적으로 같습니다만
    두 가지 테크닉이 추가되어 있습니다. 

     

    지난 달의 일수 계산하기

    지난 달의 일수는 다음 방법으로 구할 수 있습니다. 

    이번 달 1일에서 하루를 빼서,
    지난달의 말일로 날짜를 바꾸면,
    그 날짜가 지난달의 일수가 됩니다.

    (today.replace(day=1) - relativedelta(days=1)).day

    https://jhproject.tistory.com/164
    https://daeguowl.tistory.com/35

     

    생일이 2월 29일인 경우는?

    생일이 31일인데, 지난달 날수가 30일인 경우가 있습니다. 
    이것은 위에서 말씀드린 2월 29일생 문제와 동일합니다. 

    2월 29일 생이라면,
    3월 1일은 생일이 지났다고 하는 게
    직관적인 것 같습니다.

    (반박시 당신이 맞습니다.)

    그래서 생일이 지난달의 일수보다 클 때는 
    오늘 날짜를 일수로 간주합니다. 

     

    결론

    만 나이를 '일'까지 계산하는 건
    (컴퓨터를 사용해도) 삽질인 것 같습니다. 

    굳이 남들이 안 하는 건 다 이유가 있었.... 

    만 나이는 '월'까지만~!

    반응형
Designed by Tistory.