Logo Search packages:      
Sourcecode: jcal version File versions

jalali.c

/* 
    * $id:jalali.c - Jalali Calendar
    * Tools for converting Jalali to Gregorian dates and vice-versa.
    * author: Ashkan Ghassemi (ghassemi at ftml dot net)
    * 
    * This program 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 program 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 this program; if not, write to the Free Software
    * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/ 

#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <math.h>
#include "jalali.h"

#define __L_DEBUG

char *jalali_months[] = { "Farvardin", "Ordibehesht", 
                               "Khordaad", "Tir", "Mordaad", "Shahrivar", 
                         "Mehr", "Aabaan", "Aazar", "Dey", "Bahman", 
                         "Esfand" } ;

char *jalali_days[] = { "Shanbeh", "Yek-Shanbeh", "Do-Shanbeh",
                      "Seh-Shanbeh", "Chahaar-Shanbeh", 
                      "Panj-Shanbeh", "Aadineh" } ;

int jalali_month_len[] = { 31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29 } ;

int jleap_tracker[] = { 1, 5, 9, 13, 17, 22, 26, 30 } ;


/* 
 * Jalali leap year indicator 
 */

inline int 
is_jleap(int year) 
{
    int pr = year ;
    pr-=475 ;
    if (pr < 0)
      pr--;

    pr%=2820 ;
    if (pr >= 2783) {
      pr-=2783 ;
      if (pr == 0)
          return 0 ;
      else if (pr % 4 == 0)
          return 1 ;
      else 
          return 0 ;
    } else {
      pr%=128 ;
      if (pr<29) {
          if (pr == 0)
            return 0 ;
          else if (pr % 4 == 0)
            return 1 ;
          else
            return 0 ;
      } else if (pr < 62) {
          pr-=29 ;
          if (pr == 0)
            return 0 ;
          else if (pr % 4 == 0)
            return 1 ;
          else
            return 0 ;
      } else if (pr < 95) {
          pr-=62 ;
          if (pr == 0)
            return 0 ;
          else if (pr % 4 == 0)
            return 1 ;
          else
            return 0 ;
      } else {
          pr-=95 ;
          if (pr == 0)
            return 0 ;
          else if ((pr % 4) == 0)
            return 1 ;
          else 
            return 0 ;
      }
    }
    return 0 ;
}

/* 
 * Gregorian leap year indicator, it is obviously 
 */

inline int 
is_gleap(int year) 
{
    if (((year-GLEAP)%4) == 0) 
      return 1 ;
    else
      return 0 ;
}

/* 
 * This simple function gives us the last leap year in the Jalali Calendar 
 * system, note that input year is considered as a Jalali year.
 */

inline int 
get_last_jleap(int year) 
{
    int i ;
    for (i=year; i>=year-5; i--) {
      if(is_jleap(i))
          return i ;
    }

    return -1 ;
}


/* 
 * This simple function gives us the last leap year in the Gregorian Calendar 
 * system, note that input year is considered as a Gregorian year.
 */

inline int 
get_last_gleap(int year) {
    int i ;
    for (i=year; i>=year-5; i--) {
      if(is_gleap(i))
          return i ;
    }

    return -1 ;
}

/* 
 * Jalali converter is a simple tool used to convert number of days since 
 * Epoch which is our current base for converting days to each other. 
 * (Epoch is 00:00:00 UTC, January 1, 1970). It's important to note that base 
 * is not important at all, it can be anything, but you have to modify 
 * 'config.h' options respectively to suite your needs.
 */
 
long 
convert_to_days(int year, int month, int day)
{
    int n_years = year - BASE_CAL_YEAR ;
    int i ;
    int today = 0 ;
    long fu_days = 0 ;
    double redirect = 0.0 ;
    double c_flag = 0.0 ;

    for (i=1; i<month; i++) 
        today+= jalali_month_len[i-1] ;
    
    today+=day ;

    redirect = c_flag = (n_years * YEAR_LEND) + (today - 287.0) ;
    c_flag-= floor(c_flag) ;
    
    if (c_flag >=0.0) {
      if (c_flag < 0.75)
          fu_days = floor(redirect) ;
      else
          fu_days = ceil(redirect) ;
    } else {
      if (abs(c_flag) < 0.5)
          fu_days = floor(redirect) ;
      else 
          fu_days = floor(redirect) ;
    }

    return fu_days ;
}

    
int 
convert_to_jalali(long fu_days, j_date* jd) 
{
    register int i = 0 ;
    int r_days = 0 ;
    long n_days = 0 ;
    long n_years = 0 ;
    long fn_days ;
    double redirect ;
    
    /* determining day of the week */
    n_days = fu_days ;
    n_days%= 7 ;
    n_days+= 5 ;
    if (n_days == -1)
      n_days = 6 ;
    jd->wday = abs(n_days % 7) ;
    
    fn_days = fu_days + 287 ;

    /* determining current year */
    n_years = (fu_days / YEAR_LEND) ;
    jd->year = n_years + BASE_CAL_YEAR ;

    redirect = ((n_years * YEAR_LEND) - floor(n_years * YEAR_LEND)) ;
    
    /*
     * Accurate constant is not known, probably does't work for some
     * blah-blah dates, but I'll improve it later.
     */

#ifndef __L_DEBUG
    fprintf(stdout, "red=%lf\n", redirect) ;
    fprintf(stdout, "fud=%i\n", fu_days) ;
#endif

    if (redirect <= SEGMENT_REDIRECTION)
      jd->today = ceil(fn_days - (n_years * YEAR_LEND)) ; 

    else if ((redirect> SEGMENT_REDIRECTION) && (redirect < 0.88))
      jd->today = (fn_days - (n_years * YEAR_LEND)) + 1;
    else 
      jd->today = floor(fn_days - (n_years * YEAR_LEND)) ;

    if (fu_days<0 && (jd->today)<=0) {
      if (jd->today == 0)
          (jd->today) = (!is_jleap((jd->year)-1)) ? 365:366 ;
      else
          (jd->today)+= (!is_jleap((jd->year)-1)) ? 365:366 ;
      (jd->year)-- ;
    }
          
    if ((jd->today) == 366) {
      (jd->today)-= (is_jleap(jd->year)) ? 0:365 ;
      if (!is_jleap(jd->year))
          (jd->year)++ ;
    }
    else if ((jd->today) > 366) {
      (jd->today)-= (is_jleap(jd->year)) ? 366:365 ;
      (jd->year)++ ;
    }

    r_days = jd->today ;

    for (i=1; i<=11; i++) {
        if (r_days < jalali_month_len[i-1]+1) {
            (jd->month) = i ;
            (jd->day) = r_days ;
            return 0 ;
        }
        r_days-=jalali_month_len[i-1] ;
    }
    
    jd->month = 12 ;
    jd->day = r_days ;                   
    return 0 ;
}         

void 
calc_current(j_date* jd) 
{
    time_t n_seconds = time(NULL) ;

    /* 
     * This section requires optimization since time-difference
     * calculation is static at the moment.
     * Assuming IRST +3:30.
     */
     
    // struct tm t_info ;
    // gmtime_r(&timep, &t_info) ;
    // localtime_r(&n_seconds, &t_info) ;
    // n_seconds = mktime(&t_info) ;
    // n_seconds += n_seconds - mktime(&t_info) ;

    n_seconds += (210 * 60) ;
    long n_days ;
    n_days  = (n_seconds / DAY_LEN) ; 
    convert_to_jalali(n_days, jd) ;
#ifndef __L_DEBUG
    printf("(CUR) y:%d m:%d d:%d w:%d j:%d\n", jd->year, jd->month, jd->day, 
         jd->wday, jd->today) ;
#endif
} 

int 
get_week_day(int dyear, int dmonth, int dday) 
{
    j_date jd ;
    long fu_days = convert_to_days(dyear, dmonth, dday) ;
    convert_to_jalali(fu_days, &jd) ;
    return (jd.wday) ;
}

int 
get_year_day(int dyear, int dmonth, int dday)
{
    j_date jd ;
    long fu_days = convert_to_days(dyear, dmonth, dday) ;
    convert_to_jalali(fu_days, &jd) ;
    return (jd.today) ;
}

int 
get_year_week(int dyear, int dmonth, int dday)
{
    j_date jd ;
    long fu_days = convert_to_days(dyear, dmonth, dday) ;
    convert_to_jalali(fu_days, &jd) ;
    return ((int)ceil((jd.today+jd.wday)/7)) ;
}

Generated by  Doxygen 1.6.0   Back to index