You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			77 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			Python
		
	
			
		
		
	
	
			77 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			Python
		
	
from __future__ import annotations
 | 
						|
 | 
						|
from datetime import datetime
 | 
						|
from decimal import ROUND_HALF_UP, Decimal
 | 
						|
from typing import TYPE_CHECKING
 | 
						|
 | 
						|
from isoduration.operations.util import max_day_in_month, mod2, mod3, quot2, quot3
 | 
						|
 | 
						|
if TYPE_CHECKING:  # pragma: no cover
 | 
						|
    from isoduration.types import Duration
 | 
						|
 | 
						|
 | 
						|
def add(start: datetime, duration: Duration) -> datetime:
 | 
						|
    """
 | 
						|
    https://www.w3.org/TR/xmlschema-2/#adding-durations-to-dateTimes
 | 
						|
    """
 | 
						|
 | 
						|
    # Months.
 | 
						|
    temp = Decimal(start.month) + duration.date.months
 | 
						|
    end_month = mod3(temp, Decimal(1), Decimal(13))
 | 
						|
    carry = quot3(temp, Decimal(1), Decimal(13))
 | 
						|
 | 
						|
    # Years.
 | 
						|
    end_year = Decimal(start.year) + duration.date.years + carry
 | 
						|
 | 
						|
    # Zone.
 | 
						|
    end_tzinfo = start.tzinfo
 | 
						|
 | 
						|
    # Seconds.
 | 
						|
    temp = Decimal(start.second) + duration.time.seconds
 | 
						|
    end_second = mod2(temp, Decimal("60"))
 | 
						|
    carry = quot2(temp, Decimal("60"))
 | 
						|
 | 
						|
    # Minutes.
 | 
						|
    temp = Decimal(start.minute) + duration.time.minutes + carry
 | 
						|
    end_minute = mod2(temp, Decimal("60"))
 | 
						|
    carry = quot2(temp, Decimal("60"))
 | 
						|
 | 
						|
    # Hours.
 | 
						|
    temp = Decimal(start.hour) + duration.time.hours + carry
 | 
						|
    end_hour = mod2(temp, Decimal("24"))
 | 
						|
    carry = quot2(temp, Decimal("24"))
 | 
						|
 | 
						|
    # Days.
 | 
						|
    end_max_day_in_month = max_day_in_month(end_year, end_month)
 | 
						|
 | 
						|
    if start.day > end_max_day_in_month:
 | 
						|
        temp = end_max_day_in_month
 | 
						|
    else:
 | 
						|
        temp = Decimal(start.day)
 | 
						|
 | 
						|
    end_day = temp + duration.date.days + (7 * duration.date.weeks) + carry
 | 
						|
 | 
						|
    while True:
 | 
						|
        if end_day < 1:
 | 
						|
            end_day += max_day_in_month(end_year, end_month - 1)
 | 
						|
            carry = Decimal(-1)
 | 
						|
        elif end_day > max_day_in_month(end_year, end_month):
 | 
						|
            end_day -= max_day_in_month(end_year, end_month)
 | 
						|
            carry = Decimal(1)
 | 
						|
        else:
 | 
						|
            break
 | 
						|
 | 
						|
        temp = end_month + carry
 | 
						|
        end_month = mod3(temp, Decimal(1), Decimal(13))
 | 
						|
        end_year = end_year + quot3(temp, Decimal(1), Decimal(13))
 | 
						|
 | 
						|
    return datetime(
 | 
						|
        year=int(end_year.to_integral_value(ROUND_HALF_UP)),
 | 
						|
        month=int(end_month.to_integral_value(ROUND_HALF_UP)),
 | 
						|
        day=int(end_day.to_integral_value(ROUND_HALF_UP)),
 | 
						|
        hour=int(end_hour.to_integral_value(ROUND_HALF_UP)),
 | 
						|
        minute=int(end_minute.to_integral_value(ROUND_HALF_UP)),
 | 
						|
        second=int(end_second.to_integral_value(ROUND_HALF_UP)),
 | 
						|
        tzinfo=end_tzinfo,
 | 
						|
    )
 |