如何计算一个人生日后的第10000天是哪天?

19

我想知道如何用基本的Python解决这个问题(不使用任何库):如何计算一个人生日后的第10000天是什么时候?

例如,给定日期为2008年5月19日星期一,则所需日期为2035年10月5日星期五(根据https://www.durrans.com/projects/calc/10000/index.html?dob=19%2F5%2F2008&e=mc2)。

到目前为止,我已经编写了以下脚本:

years = range(2000, 2050)
lst_days = []
count = 0
tot_days = 0
for year in years:
    if((year % 400 == 0) or  (year % 100 != 0) and  (year % 4 == 0)):
        lst_days.append(366)
    else:
        lst_days.append(365)
while tot_days <= 10000:
        tot_days = tot_days + lst_days[count]
        count = count+1
print(count)

这个程序用于估算人的年龄,从他们的生日开始算起10,000天后的年龄(适用于2000年后出生的人)。但是我该如何操作呢?


2
@eandklahn 这是一个关于我儿子(高中生)的程序。我不想使用任何预定义库,只用了循环和条件语句。我展示这个脚本是因为我想要展示我已经做了一些东西。我希望避免问题看起来像是一个学生练习寻找解决方案:-)!如果我的代码有误导性,我可以删除它。 - Dimitris
5
这让我感到困惑,因为问题不清楚。看起来你有一段代码,声称它可以实现你想要的功能,那么问题出在哪里呢? - Tomerikoo
1
我写了一个类似的程序来庆祝一个好朋友成为千亿秒老年人的那一天。他完全被惊到了,我们度过了愉快的时光。 - Mark Ransom
1
你的儿子了解模算术吗?这在这里非常重要。事实上,如果你的儿子还不知道模算术,那么今天制作一个没有模运算的程序版本是值得的,然后等到他学习了模运算后,再制作第二个版本的程序使用它们。 - Stef
5
在Python中避免使用名称 sum 作为自己的变量名。您可能会注意到它在代码中出现时显示为不同的颜色:这是因为它是Python中内置函数的名称。在Python中掩盖内置函数的名称是令人困惑的,甚至可能产生意外后果。 - Stef
显示剩余15条评论
4个回答

20

仅使用基本的Python包

基于"没有特殊的包"这一前提,您可以使用datetime.timedelta来解决此类问题:

import datetime

start_date = datetime.datetime(year=2008, month=5, day=19)

end_date = start_date + datetime.timedelta(days=10000)

print(end_date.date())

没有任何基础包(并继续解决问题)

即使是绕过基本的Python包,按照以下方式进行处理应该会有所帮助(我希望如此!)。

首先定义一个函数来确定一年是否为闰年:

def is_it_a_leap_year(year) -> bool:
    """
    Determine if a year is a leap year

    Args:
        year: int

    Extended Summary:
        According to:
            https://airandspace.si.edu/stories/editorial/science-leap-year
        The rule is that if the year is divisible by 100 and not divisible by
        400, leap year is skipped. The year 2000 was a leap year, for example,
        but the years 1700, 1800, and 1900 were not.  The next time a leap year
        will be skipped is the year 2100.
    """
    if year % 4 != 0:

        return False

    if year % 100 == 0 and year % 400 != 0:

        return False

    return True

然后定义一个函数来确定一个人的年龄(利用上述内容来识别闰年):

def age_after_n_days(start_year: int,
                     start_month: int,
                     start_day: int,
                     n_days: int) -> tuple:
    """
    Calculate an approximate age of a person after a given number of days,
    attempting to take into account leap years appropriately.

    Return the number of days left until their next birthday

    Args:
        start_year (int): year of the start date
        start_month (int): month of the start date
        start_day (int): day of the start date
        n_days (int): number of days to elapse
    """

    # Check if the start date happens on a leap year and occurs before the
    # 29 February (additional leap year day)
    start_pre_leap = (is_it_a_leap_year(start_year) and start_month < 3)

    # Account for the edge case where you start exactly on the 29 February
    if start_month == 2 and start_day == 29:

        start_pre_leap = False

    # Keep a running counter of age
    age = 0

    # Store the "current year" whilst iterating through the days
    current_year = start_year

    # Count the number of days left
    days_left = n_days

    # While there is at least one year left to elapse...
    while days_left > 364:

        # Is it a leap year?
        if is_it_a_leap_year(current_year):

            # If not the first year
            if age > 0:

                days_left -= 366

            # If the first year is a leap year but starting after the 29 Feb...
            elif age == 0 and not start_pre_leap:

                days_left -= 365

            else:

                days_left -= 366

        # If not a leap year...
        else:

            days_left -= 365

        # If the number of days left hasn't dropped below zero
        if days_left >= 0:

            # Increment age
            age += 1

            # Increment year
            current_year += 1

    return age, days_left

使用您的示例,您可以通过以下方式测试该函数:

age, remaining_days = age_after_n_days(start_year=2000, start_month=5, start_day=19, n_days=10000)

现在您已经知道了完整年份和剩余天数,您可以使用剩余天数来计算确切的日期。

3
问题中明确提到不得使用库。使用 datetime 可以轻松实现此目标。 - Abhyuday Vaish
FYI:闰年更加复杂。例如,千年如2000年也不是闰年。时间对于编程来说是一种恐怖,这就是为什么日期时间包如此复杂的原因。 - Adriaan

2
如果你导入datetime库
import datetime
your_date = "01/05/2000"
(day, month, years) = your_date.split("/")
date = datetime.date(int(years), int(month), int(day))
date_10000 = date+datetime.timedelta(days=10000)
print(date_10000)

没有库脚本
your_date = "20/05/2000"
(day, month, year) = your_date.split("/")
days = 10000
year = int(year)
month = int(month)
day = int(day)
end=False
#m1,m3,m5,m7,m8,m10,m12=31
#m2=28
#m4,m6,m9,m11=30
m=[31,28,31,30,31,30,31,31,30,31,30,31]
while end!=True:
    if(((year % 400 == 0) or  (year % 100 != 0) and  (year % 4 == 0)) and(days-366>=0)):   
        days-=366
        year+=1
    elif(((year % 400 != 0) or  (year % 100 != 0) and  (year % 4 != 0)) and(days-366>=0)):
        days-=365
        year+=1
    else:
        end=True
end=False
if(((year % 400 == 0) or  (year % 100 != 0) and  (year % 4 == 0))):   
    m[1]=29
else:
    m[1]=28
while end!=True:
    if(days-m[month]>=0):
        days-=m[month]
        if(month+1!=12):
            month+=1
        else:
            year+=1
            if(((year % 400 == 0) or  (year % 100 != 0) and  (year % 4 == 0))):   
                m[1]=29
            else:
                m[1]=28
            month=0
    else:
        end=True

if(day+days>m[month]):
    day=day+days-m[month]+1
    if(month+1!=12):
        month+=1
    else:
        year+=1
        if(((year % 400 == 0) or  (year % 100 != 0) and  (year % 4 == 0))):   
            m[1]=29
        else:
            m[1]=28
        month=0
else:
    day=day+days
print(day,"/",month,"/",year)

前三行可以直接写成 date = datetime.datetime.strptime("01/05/2000", "%d/%m/%Y") - Tomerikoo
@KruII,你的回答显示IndexError: list index out of range针对于08/12/2004 - Abhyuday Vaish
FYI:闰年更加复杂。例如,千年如2000年也不是闰年。时间对于编程来说是一种恐怖,这就是为什么日期时间包如此复杂的原因。 - Adriaan

2

这是我想出的一种解决方案,不涉及任何库或包,只有循环和条件语句(考虑了闰年):

def isLeapYear(years):
  if years % 4 == 0:
    if years % 100 == 0:
      if years % 400 == 0:
        return True
      else:
        return False
    else:
      return True
  else:
    return False

monthDays = [31,28,31,30,31,30,31,31,30,31,30,31]
sum = 0
sumDays = []
for i in monthDays:
  sumDays.append(365 - sum)
  sum += i

timeInp = input("Please enter your birthdate in the format dd/mm/yyyy\n")
timeInp = timeInp.split("/")
days = int(timeInp[0])
months = int(timeInp[1])
years = int(timeInp[2])
totDays = 10000

if totDays > 366:
  if isLeapYear(years):
    if months == 1 or months == 2:
      totDays -= (sumDays[months - 1] + 1 - days) + 1
    else:
      totDays -= (sumDays[months - 1] - days) + 1
  else:
    totDays -= (sumDays[months - 1] - days) + 1

  months = 1
  days = 1
  years += 1

while totDays > 366:
  if isLeapYear(years):
    totDays -= 366
  else:
    totDays -= 365
  years += 1

i = 0
while totDays != 0:
  if isLeapYear(years):
    monthDays[1] = 29
  else:
    monthDays[1] = 28

  if totDays >= monthDays[i]:
    months += 1
    totDays -= monthDays[i]
  elif totDays == monthDays[i]:
    months += 1
    totDays = 0
  else:
    days += totDays
    if days % (monthDays[i] + 1)!= days:
      days %= monthDays[i] + 1
      months += 1
    totDays = 0

  if months == 13:
    months = 1
    years += 1

  i += 1
  if i == 12:
    i = 0

print(str(days) + "/" + str(months) + "/" + str(years))

正如其名称所示,isLeapYear() 接受一个参数 years 并返回一个布尔值。
为了简化问题,我们的第一步是将日期“翻译”到下一年。这使得我们未来的计算更加容易。为此,我们可以定义一个数组 sumDays,它存储每个月完成一年(到新年)所需的天数。然后,我们从 totDays 中减去这个数量,考虑闰年,并更新我们的变量。
接下来,就是简单的部分,只需在足够的天数内向前跳过年份。
一旦我们不能再添加另一整年,我们就逐月进行,直到我们用完所有天数。
示例测试用例:
输入 #1:
19/05/2008

输出 #1:

5/10/2035

输入 #2:

05/05/2020

输出 #2:

21/9/2047

第三个输入:

29/02/2020

输出 #3:

17/7/2047

我使用这个网站检查了大部分的解决方案: https://www.countcalculate.com/calendar/birthday-in-days/result


“isLeapYear”函数中的“if forest”对于人眼来说令人惊讶地难以解析。将其压缩为一个布尔表达式,并使用“and”和“or”,可能会更易于理解和维护。 - Stef
FYI:闰年更加复杂。例如,千年如2000年也不是闰年。时间对于编程来说是一种恐怖,这就是为什么日期时间包如此复杂的原因。 - Adriaan
哇,我编写这个代码已经快一年了哈哈。OP说他们不想使用任何包,所以我假设他们只是想手动编写所有内容。但是,闰年的规则确实很烦人。 - Aniketh Malyala

1

我已经更新了计算闰年和月份日期的代码。这是我正在使用的代码:

n = input("Enter your DOB:(dd/mm/yyyy)")
d,m,y = n.split('/') #Splitting the DOB
d,m,y = int(d), int(m), int(y)
def if_leap(year): # Checking for leap year.
    if year % 4 != 0:
        return False
    elif year % 100 == 0 and year % 400 != 0:
        return False
    else:
        return True


target = 10000
while target > 364: # getting no.of years
    if if_leap(y):
        target -= 366
        y += 1
    else:
        target -= 365
        y += 1

while target > 27: # getting no. of months
    if m == 2 :
        if if_leap(y):
            target -= 29
            m += 1
            if m >= 12: # Resetting the month to 1 if it's value is greater than 12
                y += 1
                m -= 12
        else:
            target -= 28
            m += 1
            if m >= 12:
                y += 1
                m -= 12
    elif m in [1, 3, 5, 7, 8, 10, 12]:
        target -= 31
        m += 1
        if m >= 12:
            y += 1
            m -= 12
    elif m in [4, 6, 9, 11]:
        target -= 30
        m += 1
        if m >= 12:
            y += 1
            m -= 12
            
d = d + target # getting the no. of days
if d > 27:
    if m == 2:
        if if_leap(y):
            d -= 29
            m += 1
        else:
            d -= 28
            m += 1
    elif m in [1, 3, 5, 7, 8, 10, 12]:
        d -= 31
        m += 1
    else:
        d -= 30
        m += 1

print(f"The 10000th date will be {d}/{m}/{y}") 

输出:

Enter your DOB:(dd/mm/yyyy): 06/01/2006
The 10000th date will be 24/5/2033

附言:当我使用那个网站进行检查时,会得到一些略微不同的输出。有人能找出代码中的错误/错误吗?这将非常有帮助。 例如,对于日期08/12/2004,应该是25/4/2032,但我的输出显示为24/4/2032


FYI:闰年更加复杂。例如,千年如2000年也不是闰年。时间对于编程来说是一种恐怖,这就是为什么日期时间包如此复杂的原因。 - Adriaan
@Adriaan 谢谢你提供的信息。我一定会去看看! - Abhyuday Vaish

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接