#!/usr/bin/env python # -*- coding: utf-8 -*- # Last update January 2011 by Chris Tozzi # For more information or to report problems, see http://christozzi.com/repyblican.php import sys import datetime usage = "Usage: repyblican.py day [republican or Gregorian month] year\n\nExamples:\nrepyblican.py 13 Brumaire 3\nrepyblican.py 27 July 1794\nrepyblican.py Vertu 3" # Arrays of month and sansculottides names. Make first value 'null' so that the first name is array[1], not array[0], as this mitigates confusion below rep_months = 'null','Vendémiaire','Brumaire','Frimaire','Nivôse','Pluviôse','Ventôse','Germinal','Floréal','Prairial','Messidor','Thermidor','Fructidor' greg_months = 'null','January','February','March','April','May','June','July','August','September','October','November','December' sansculottides = 'null','Vertu','Génie','Travail','Opinion','Récompenses','Révolution' # Generate lists of simplified month and sansculottide names (convert all characters to lowercase and remove accents) # This way it doesn't matter whether the input names are capitalized or properly accented rep_months_simp = [] greg_months_simp = [] sansculottides_simp = [] for key in rep_months: key = key.lower().translate(None,"ôéeo") rep_months_simp.append(key) for key in greg_months: key = key.lower() # Don't remove accents for Gregorian month names because they have no accents greg_months_simp.append(key) for key in sansculottides: key = key.lower().translate(None,"ôéeo") sansculottides_simp.append(key) # Check input data for validity def analyze_input(): if len(sys.argv) <= 1: # No arguments given print usage quit() elif len(sys.argv) > 4: # Too many arguments given print "Invalid input :", sys.argv[1:] quit() elif len(sys.argv) == 3 and sys.argv[1].lower().translate(None,"ôéeo") in sansculottides_simp: # Input is sansculottide date if not sys.argv[2].isdigit(): print "Invalid year: ", sys.argv[2] # Input year for sansculottide is not a digit quit() elif not sys.argv[3].isdigit(): # Input year for non-sansculottide date is not a digit print "Invalid year: ", sys.argv[3] quit() elif int(sys.argv[3]) <= 1791: # Input is a republican date if not sys.argv[1].isdigit(): print "Invalid day: ", sys.argv[1] quit() if not 0 < int(sys.argv[1]) < 31: print "Invalid day: ", sys.argv[1] quit() if sys.argv[2].isdigit() and not 0 < int(sys.argv[2]) < 13: print "Invalid month: ", sys.argv[2] quit() if not sys.argv[2].isdigit() and not sys.argv[2].lower().translate(None,"ôéeo") in rep_months_simp: print "Invalid month: ", sys.argv[2] quit() if int(sys.argv[3]) > 14: print "WARNING: republican year", sys.argv[3], "is later than the republican period. I'll still calculate the date, but I can't guarantee accuracy!" elif 1791 < int(sys.argv[3]) < 10000: # Input is a Gregorian date republican_date = "no" if not sys.argv[1].isdigit(): print "Invalid day: ", sys.argv[1] quit() if not 0 < int(sys.argv[1]) < 32: print "Invalid day: ", sys.argv[1] quit() if sys.argv[2].isdigit() and not 0 < int(sys.argv[2]) < 13: print "Invalid month: ", sys.argv[2] quit() if not sys.argv[2].isdigit() and not sys.argv[2].lower() in greg_months_simp: print "Invalid month: ", sys.argv[2] quit() if int(sys.argv[3]) > 1806: print "WARNING: Gregorian year", sys.argv[3], "is later than the republican period. I'll still calculate the date, but I can't guarantee accuracy!" elif int(sys.argv[3]) > 9999: # Year can't exceed 9999 or datetime functions will fail print "Invalid year :", sys.argv[3], ". Year must be between 1 and 9999" quit() else: print "Invalid input :", sys.argv[1:] quit() def get_dates(): # Calculate numerical date global month global day global year for i in range (1,7): if sys.argv[1].lower().translate(None,"ôéeo") == sansculottides_simp[i]: month = int(13) day = int(i) year = int(sys.argv[2]) for i in range(1,13): if rep_months_simp[i] == sys.argv[2].lower().translate(None,"ôéeo") or greg_months_simp[i] == sys.argv[2].lower(): month = int(i) day = int(sys.argv[1]) year = int(sys.argv[3]) if len(sys.argv) > 3 and sys.argv[2].isdigit(): month = int(sys.argv[2]) day = int(sys.argv[1]) year = int(sys.argv[3]) def get_days_since_Republic(): # Calculate days since the Republic was founded (22 September 1792) global days_since_Republic global leaps # Number of republican leap years global greg_leap_years # Gregorian years in which a _republican_ leap year occurs greg_leap_years = '1795','1799','1803','1807' # Could write something to populate this automatically with all possible dates if year <= 1791: # First calculate basic days_since_Republic, ignoring leap years days_since_Republic = int((day)+((month-1)*30)+((year-1)*365)) # Calculate number of republican leap years. Republican leap years # occur on the last day of years 3, 7, 11, etc. A sixth sansculottide # day is added to these years leaps = int(year/4) # If (and only if) we are on the sixth sansculottide of a republican leap year, we add a leap, # since we consider a new leap year to have occurred when the calendar reaches the beginning of # a sixth sansculottide day if month == 13 and day == 6: leaps = leaps + 1 # Add an extra day to days_since_Republic for each leap year days_since_Republic = days_since_Republic + leaps elif year > 1791: days_since_Republic = datetime.date(year, month, day) - datetime.date(1792, 9, 21) days_since_Republic = int(days_since_Republic.days) # Calculate how many _republican_ leap years have occurred since input date # (i.e., how many times a Jour de la Révolution has happened) # The first Jour de la Révolution occurs on 22 September 1795; it recurs # every four republican years thereafter # Note that Gregorian leap years are NOT a reliable means of calculating republican leap years, # because they do NOT always occur every four years (1800 was not a leap year), which republican years do # (The republican calendar was supposed to be adjusted beginning in year 20 to account for this, # but the calendar was abolished before that date) # See http://www.webexhibits.org/calendars/calendar-french.html#anchor-leap-years for more on # republican leap years leaps = 0 # Initially (for dates before 22 September 1795) we have no leaps # Beginning in 1796, there is at least one leap year for every four years that have passed if int(year) >= 1796: leaps = int((year - 1792)/4) # For dates on or after 22 September of each year, we add one more leap year if str(year) in greg_leap_years and month == 9 and day >= 22: leaps = int((year - 1792)/4) + 1 elif str(year) in greg_leap_years and month >= 10: leaps = int((year - 1792)/4) + 1 # Calculate republican date based on days_since_Republic def get_rep_date(): global rep_day global rep_month global rep_year rep_year = int((days_since_Republic)/365) + 1 rep_month = int((days_since_Republic - (365*(rep_year - 1)))/(30.4666666)) + 1 rep_day = int(days_since_Republic - (365*(rep_year - 1)) - (30*(rep_month-1))) - leaps # Below, we run some checks to correct particular situations where rounding and sansculottide # bizarreness cause problems with the numbers produced by the math above # Probably some of this messiness could be avoided if the calculations above were made more precise if rep_day == 0 and rep_month == 1: # This happens on the last sansculottide of each republican year rep_year = rep_year - 1 # Determine if this is a sixth sansculottide, or a fifth if str(year) in greg_leap_years and month == 9 and day == 22: rep_day = 36 elif str(year) in greg_leap_years and month == 9 and day == 23 and year >= 1803: rep_day = 36 else: rep_day = 35 rep_date = "Day of " + str(sansculottides[int(rep_day)-30]) + " (sansculottide) Year " + str(rep_year) elif rep_day > 30 and rep_month == 12: # If rep_day > 30 and the month == 12, we are in the sansculottides rep_date = "Day of " + str(sansculottides[int(rep_day)-30]) + " (sansculottide) Year " + str(rep_year) elif rep_month == 13: # If rep_month == 13, we are also in the sansculottides rep_date = "Day of " + str(sansculottides[int(rep_day)]) + " (sansculottide) Year " + str(rep_year) elif rep_day < 0 and rep_month == 1: # This happens for some third and fourth sansculottides dates rep_year = rep_year - 1 rep_day = rep_day + 35 if year >= 1803: rep_day = rep_day + 1 rep_date = "Day of " + str(sansculottides[int(rep_day)-30]) + " (sansculottide) Year " + str(rep_year) elif rep_month != 12 and rep_day > 30: # This happens on the last day (or days) of each republican month rep_month = rep_month + 1 rep_day = rep_day - 30 rep_date = str(rep_day) + " " + str(rep_months[rep_month]) + " Year " + str(rep_year) elif rep_day < 0: # Sometimes happens towards the end of a republican month rep_day = rep_day + 30 if year >= 1799: rep_month = rep_month - 1 else: rep_month = 1 rep_date = str(rep_day) + " " + str(rep_months[rep_month]) + " Year " + str(rep_year) elif rep_day == 0 and rep_month == 2 and year < 1799: # This happens in certain years for some reason rep_day = 30 rep_month = 1 rep_date = str(rep_day) + " " + str(rep_months[rep_month]) + " Year " + str(rep_year) elif rep_day == 0 and rep_month == 3 and year < 1799: # This happens in certain years for some reason rep_day = 30 rep_month = 2 rep_date = str(rep_day) + " " + str(rep_months[rep_month]) + " Year " + str(rep_year) elif rep_day == 0 and year >= 1799: # This happens in certain years for some reason rep_day = 30 rep_month = rep_month - 1 rep_date = str(rep_day) + " " + str(rep_months[rep_month]) + " Year " + str(rep_year) else: # If none of the above conditions apply, we don't have to adjust the numbers and can simply get the final date rep_date = str(rep_day) + " " + str(rep_months[rep_month]) + " Year " + str(rep_year) print "Republican date: ", rep_date # Calculate Gregorian date based on days_since_Republic def get_greg_date(): greg_date = datetime.date(1792, 9, 21) + datetime.timedelta(days=days_since_Republic) print "Gregorian date: ", greg_date def debug(): # Print out some extra information for debugging purposes print "day =", day print "month =", month print "year =", year print "rep_day =", rep_day print "rep_month =", rep_month print "rep_year =", rep_year print "days since Republic =", days_since_Republic print "leaps =", leaps def main(): analyze_input() get_dates() get_days_since_Republic() get_rep_date() get_greg_date() main()