Source code for bonjour.ethiopian_date

#!/usr/bin/env python
# encoding=utf-8
# maintainer: rgaudin

"""  
.. note:: This version of the Ethiopian Calendar tool is a fork
          from Renaud's version. The only difference is that when
          converting a date to the Julian calendar, this version
          returns a (year, month, day) tuple instead of a 
          :class:`datetime.datetime` object.
          
          We cannot use the native Python :class:`datetime`
          class because the Julian calendar has 13 months,
          and the Python libraries can only deal with 12 months.


Ethiopian Calendar tool for Python 2.6

Copyright (c) 2010 Renaud Gaudin <rgaudin@gmail.com>

This tool is a python port of Java Code from Ealet 2.0 by Senamirmir Project.

This code is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA """

import datetime


[docs]class EthiopianDateConverter(object): """ Class methods for converting between Ethiopian and Gregorian """ @classmethod def _start_day_of_ethiopian(cls, year): """ returns first day of that Ethiopian year Params: * year: an int """ # magic formula gives start of year new_year_day = (year / 100) - (year / 400) - 4 # if the prev ethiopian year is a leap year, new-year occrus on 12th if (year - 1) % 4 == 3: new_year_day += 1 return new_year_day @classmethod
[docs] def date_to_ethiopian(cls, adate): """ Ethiopian date object representation of provided Gregorian date Shortcut to to_ethiopian() classmethod using a date parameter :param adate: Gregorian date to conver to Julian calendar :type adate: :class:`datetime.date` """ return cls.to_ethiopian(adate.year, adate.month, adate.day)
@classmethod
[docs] def to_gregorian(cls, year, month, date): """ Gregorian date object representation of provided Ethiopian date :param year: Julian year :type year: :class:`int` :param month: Julian month :type month: :class:`int` :param date: Julian day :type date: :class:`int` """ # prevent incorect input inputs = (year, month, date) if 0 in inputs or [data.__class__ for data in inputs].count(int) != 3: raise ValueError("Malformed input can't be converted.") # Ethiopian new year in Gregorian calendar new_year_day = cls._start_day_of_ethiopian(year) # September (Ethiopian) sees 7y difference gregorian_year = year + 7 # Number of days in gregorian months # starting with September (index 1) # Index 0 is reserved for leap years switches. gregorian_months = [0, 30, 31, 30, 31, 31, 28, \ 31, 30, 31, 30, 31, 31, 30] # if next gregorian year is leap year, February has 29 days. next_year = gregorian_year + 1 if (next_year % 4 == 0 and next_year % 100 != 0) \ or next_year % 400 == 0: gregorian_months[6] = 29 # calculate number of days up to that date until = ((month - 1) * 30) + date if until <= 37 and year <= 1575: # mysterious rule until += 28 gregorian_months[0] = 31 else: until += new_year_day - 1 # if ethiopian year is leap year, paguemain has six days if year - 1 % 4 == 3: until += 1 # calculate month and date incremently m = 0 for i in range(0, gregorian_months.__len__()): if until <= gregorian_months[i]: m = i gregorian_date = until break else: m = i until -= gregorian_months[i] # if m > 4, we're already on next Gregorian year if m > 4: gregorian_year += 1 # Gregorian months ordered according to Ethiopian order = [8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9] gregorian_month = order[m] return datetime.date(gregorian_year, gregorian_month, gregorian_date)
@classmethod
[docs] def to_ethiopian(cls, year, month, date): """ Ethiopian date object representation of provided Gregorian date :param year: Gregorian year :type year: :class:`int` :param month: Gregorian month :type month: :class:`int` :param date: Gregorian day :type date: :class:`int` """ # prevent incorect input inputs = (year, month, date) if 0 in inputs or [data.__class__ for data in inputs].count(int) != 3: raise ValueError("Malformed input can't be converted.") # date between 5 and 14 of May 1582 are invalid if month == 10 and date >= 5 and date <= 14 and year == 1582: raise ValueError("Invalid Date between 5-14 May 1582.") # Number of days in gregorian months # starting with January (index 1) # Index 0 is reserved for leap years switches. gregorian_months = [0, 31, 28, 31, 30, 31, 30, \ 31, 31, 30, 31, 30, 31] # Number of days in ethiopian months # starting with January (index 1) # Index 0 is reserved for leap years switches. ethiopian_months = [0, 30, 30, 30, 30, 30, 30, 30, \ 30, 30, 5, 30, 30, 30, 30] # if gregorian leap year, February has 29 days. if (year % 4 == 0 and year % 100 != 0) or year % 400 == 0: gregorian_months[2] = 29 # September sees 8y difference ethiopian_year = year - 8 # if ethiopian leap year pagumain has 6 days if ethiopian_year % 4 == 3: ethiopian_months[10] = 6 else: ethiopian_months[10] = 5 # Ethiopian new year in Gregorian calendar new_year_day = cls._start_day_of_ethiopian(year - 8) # calculate number of days up to that date until = 0 for i in range(1, month): until += gregorian_months[i] until += date # update tahissas (december) to match january 1st if ethiopian_year % 4 == 0: tahissas = 26 else: tahissas = 25 # take into account the 1582 change if year < 1582: ethiopian_months[1] = 0 ethiopian_months[2] = tahissas elif until <= 277 and year == 1582: ethiopian_months[1] = 0 ethiopian_months[2] = tahissas else: tahissas = new_year_day - 3 ethiopian_months[1] = tahissas # calculate month and date incremently m = 0 for m in range(1, ethiopian_months.__len__()): if until <= ethiopian_months[m]: if m == 1 or ethiopian_months[m] == 0: ethiopian_date = until + (30 - tahissas) else: ethiopian_date = until break else: until -= ethiopian_months[m] # if m > 4, we're already on next Ethiopian year if m > 10: ethiopian_year += 1 # Ethiopian months ordered according to Gregorian order = [0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1, 2, 3, 4] ethiopian_month = order[m] return (ethiopian_year, ethiopian_month, ethiopian_date)