********************************************************************************
*** Convert Gregorian to Ethiopian dates
********************************************************************************

program define to_ethiopian
    version 10.0
    syntax varlist(min=1 max=1) [if] [in] [, eth_year(string) eth_month(string) eth_day(string)]
    
	// Date variables are numberic
    confirm numeric variable `varlist'
    
    marksample touse
    
    local fmt : format `varlist'
    local fmt = lower("`fmt'")
    
    // Obtain number of days since January 01, 1960
    tempvar temp_numeric_var_touse
    if "`fmt'" == "%td" {
        gen double `temp_numeric_var_touse' = `varlist' if `touse'
    }
    else if "`fmt'" == "%tc" {
        gen double `temp_numeric_var_touse' = dofc(`varlist') if `touse'
    }
    else {
        display as error "Date variable must be valid STATA date variable formatted as %td, %tc or %tC."
        exit 198
    }
	
	// Default variable names if not provided
	if "`eth_year'" == "" {
        local eth_year "eth_year"
    }
	if "`eth_month'" == "" {
        local eth_month "eth_month"
    }
	if "`eth_day'" == "" {
        local eth_day "eth_day"
    }

	// Validate new variable names
	capture confirm new variable `eth_year'
	if _rc {
		display as error "Option eth_year(): `eth_year' is not a valid new variable name or already exists."
		exit 198
	}
	capture confirm new variable `eth_month'
	if _rc {
		display as error "Option eth_month(): `eth_month' is not a valid new variable name or already exists."
		exit 198
	}
	capture confirm new variable `eth_day'
	if _rc {
		display as error "Option eth_day(): `eth_day' is not a valid new variable name or already exists."
		exit 198
	}
	
    // New variables placeholders
    quietly {
		gen double `eth_year'  = .
		gen double `eth_month' = .
		gen double `eth_day'   = .
		}
    
    // Call mata to perform conversion
    mata: ethdate_compute("`temp_numeric_var_touse'", "`touse'", "`eth_year'", "`eth_month'", "`eth_day'")
    
end


********************************************************************************
*** MATA function to convert Gregorian to Ethiopian dates
********************************************************************************

mata:
void ethdate_compute(string scalar datevar, string scalar touse, 
                     string scalar ethyear, string scalar ethmonth, 
					 string scalar ethday)
{
    real colvector days, years, months
    real scalar i, n
    
    // Read input data
    days = st_data(., datevar, touse)
    n = rows(days)
    
    // Initialize output vectors : Starting year (Tahsas 22, 1952) = January 01, 1960
    years  = J(n, 1, 1952)
    months = J(n, 1, 4)
    days   = days :+ 22 
    
    // Main computation loop
    for (i = 1; i <= n; i++) {
        if (days[i] != .) {  // Skip missing values
            while (days[i] > 30 | days[i] <= 0) {
                // Determine if current year is a leap year
                real scalar is_leap, year_days, pagume_days
                is_leap = mod(years[i], 4) == 3
                year_days = is_leap ? 366 : 365
                
                if (days[i] > year_days) {
                    days[i] = days[i] - year_days
                    years[i] = years[i] + 1
                }
                else if (days[i] <= 0) {
                    years[i] = years[i] - 1
                    is_leap = mod(years[i], 4) == 3
                    year_days = is_leap ? 366 : 365
                    days[i] = days[i] + year_days
                }
                else {
                    days[i] = days[i] - 30
                    months[i] = months[i] + 1
                    
                    if (months[i] == 13) {
                        is_leap = mod(years[i], 4) == 3
                        pagume_days = is_leap ? 6 : 5
                        if (days[i] > pagume_days) {
                            days[i] = days[i] - pagume_days
                            months[i] = 1
                            years[i] = years[i] + 1
                        }
                    }
                }
            }
        }
    }
    
    // Write results back to Stata
    st_store(., ethyear, touse, years)
    st_store(., ethmonth, touse, months)
    st_store(., ethday, touse, days)
}
end