#ifndef MODULE_DATE_CALC
#define MODULE_DATE_CALC
/*****************************************************************************/
/*  MODULE NAME:  DatePcalc.c                           MODULE TYPE:  (lib)  */
/*****************************************************************************/
/*          Gregorian calendar date calculations in compliance with          */
/*          ISO/R 2015-1971, DIN 1355 and (to some extent) ISO 8601.         */
/*****************************************************************************/
/*  MODULE IMPORTS:                                                          */
/*****************************************************************************/
#include <stdio.h>                                  /*  MODULE TYPE:  (sys)  */
#include <stdlib.h>                                 /*  MODULE TYPE:  (sys)  */
#include <string.h>                                 /*  MODULE TYPE:  (sys)  */
#include <time.h>                                   /*  MODULE TYPE:  (sys)  */
#include "ToolBox.h"                                /*  MODULE TYPE:  (dat)  */
/*****************************************************************************/
/*  MODULE INTERFACE:                                                        */
/*****************************************************************************/

/* Make the VMS linker happy: */

#ifdef VMS
#define DateCalc_Day_of_Week_Abbreviation_ DateCalc_DoW_Abbrev_
#define DateCalc_nth_weekday_of_month_year DateCalc_nth_weekday
#endif

boolean
DateCalc_leap_year                     (Z_int   year);

boolean
DateCalc_check_date                    (Z_int   year,
                                        Z_int   month,
                                        Z_int   day);

boolean
DateCalc_check_time                    (Z_int   hour,
                                        Z_int   min,
                                        Z_int   sec);

boolean
DateCalc_check_business_date           (Z_int   year,
                                        Z_int   week,
                                        Z_int   dow);

Z_int
DateCalc_Day_of_Year                   (Z_int   year,
                                        Z_int   month,
                                        Z_int   day);

Z_long
DateCalc_Date_to_Days                  (Z_int   year,
                                        Z_int   month,
                                        Z_int   day);

Z_int
DateCalc_Day_of_Week                   (Z_int   year,
                                        Z_int   month,
                                        Z_int   day);

Z_int
DateCalc_Weeks_in_Year                 (Z_int   year);

Z_int
DateCalc_Week_Number                   (Z_int   year,
                                        Z_int   month,
                                        Z_int   day);

boolean
DateCalc_week_of_year                  (Z_int  *week,       /*   O   */
                                        Z_int  *year,       /*  I/O  */
                                        Z_int   month,      /*   I   */
                                        Z_int   day);       /*   I   */

boolean
DateCalc_monday_of_week                (Z_int   week,       /*   I   */
                                        Z_int  *year,       /*  I/O  */
                                        Z_int  *month,      /*   O   */
                                        Z_int  *day);       /*   O   */

boolean
DateCalc_nth_weekday_of_month_year     (Z_int  *year,       /*  I/O  */
                                        Z_int  *month,      /*  I/O  */
                                        Z_int  *day,        /*   O   */
                                        Z_int   dow,        /*   I   */
                                        Z_int   n);         /*   I   */

boolean
DateCalc_standard_to_business          (Z_int  *year,       /*  I/O  */
                                        Z_int  *week,       /*   O   */
                                        Z_int  *dow,        /*   O   */
                                        Z_int   month,      /*   I   */
                                        Z_int   day);       /*   I   */

boolean
DateCalc_business_to_standard          (Z_int  *year,       /*  I/O  */
                                        Z_int  *month,      /*   O   */
                                        Z_int  *day,        /*   O   */
                                        Z_int   week,       /*   I   */
                                        Z_int   dow);       /*   I   */

Z_long
DateCalc_Delta_Days                    (Z_int   year1,
                                        Z_int   month1,
                                        Z_int   day1,
                                        Z_int   year2,
                                        Z_int   month2,
                                        Z_int   day2);

boolean /* PRIVATE */
DateCalc_delta_hms                     (Z_long *Dd,         /*  I/O  */
                                        Z_int  *Dh,         /*   O   */
                                        Z_int  *Dm,         /*   O   */
                                        Z_int  *Ds,         /*   O   */
                                        Z_int   hour1,      /*   I   */
                                        Z_int   min1,       /*   I   */
                                        Z_int   sec1,       /*   I   */
                                        Z_int   hour2,      /*   I   */
                                        Z_int   min2,       /*   I   */
                                        Z_int   sec2);      /*   I   */

boolean
DateCalc_delta_dhms                    (Z_long *Dd,         /*   O   */
                                        Z_int  *Dh,         /*   O   */
                                        Z_int  *Dm,         /*   O   */
                                        Z_int  *Ds,         /*   O   */
                                        Z_int   year1,      /*   I   */
                                        Z_int   month1,     /*   I   */
                                        Z_int   day1,       /*   I   */
                                        Z_int   hour1,      /*   I   */
                                        Z_int   min1,       /*   I   */
                                        Z_int   sec1,       /*   I   */
                                        Z_int   year2,      /*   I   */
                                        Z_int   month2,     /*   I   */
                                        Z_int   day2,       /*   I   */
                                        Z_int   hour2,      /*   I   */
                                        Z_int   min2,       /*   I   */
                                        Z_int   sec2);      /*   I   */

boolean
DateCalc_delta_ymd                     (Z_int  *year1,      /*  I/O  */
                                        Z_int  *month1,     /*  I/O  */
                                        Z_int  *day1,       /*  I/O  */
                                        Z_int   year2,      /*   I   */
                                        Z_int   month2,     /*   I   */
                                        Z_int   day2);      /*   I   */

boolean
DateCalc_delta_ymdhms                  (Z_int  *D_y,        /*   O   */
                                        Z_int  *D_m,        /*   O   */
                                        Z_int  *D_d,        /*   O   */
                                        Z_int  *Dh,         /*   O   */
                                        Z_int  *Dm,         /*   O   */
                                        Z_int  *Ds,         /*   O   */
                                        Z_int   year1,      /*   I   */
                                        Z_int   month1,     /*   I   */
                                        Z_int   day1,       /*   I   */
                                        Z_int   hour1,      /*   I   */
                                        Z_int   min1,       /*   I   */
                                        Z_int   sec1,       /*   I   */
                                        Z_int   year2,      /*   I   */
                                        Z_int   month2,     /*   I   */
                                        Z_int   day2,       /*   I   */
                                        Z_int   hour2,      /*   I   */
                                        Z_int   min2,       /*   I   */
                                        Z_int   sec2);      /*   I   */

boolean
DateCalc_norm_delta_ymd                (Z_int  *year1,      /*  I/O  */
                                        Z_int  *month1,     /*  I/O  */
                                        Z_int  *day1,       /*  I/O  */
                                        Z_int   year2,      /*   I   */
                                        Z_int   month2,     /*   I   */
                                        Z_int   day2);      /*   I   */

boolean
DateCalc_norm_delta_ymdhms             (Z_int  *D_y,        /*   O   */
                                        Z_int  *D_m,        /*   O   */
                                        Z_int  *D_d,        /*   O   */
                                        Z_int  *Dhh,        /*   O   */
                                        Z_int  *Dmm,        /*   O   */
                                        Z_int  *Dss,        /*   O   */
                                        Z_int   year1,      /*   I   */
                                        Z_int   month1,     /*   I   */
                                        Z_int   day1,       /*   I   */
                                        Z_int   hour1,      /*   I   */
                                        Z_int   min1,       /*   I   */
                                        Z_int   sec1,       /*   I   */
                                        Z_int   year2,      /*   I   */
                                        Z_int   month2,     /*   I   */
                                        Z_int   day2,       /*   I   */
                                        Z_int   hour2,      /*   I   */
                                        Z_int   min2,       /*   I   */
                                        Z_int   sec2);      /*   I   */

void
DateCalc_Normalize_DHMS                (Z_long *Dd,         /*  I/O  */
                                        Z_long *Dh,         /*  I/O  */
                                        Z_long *Dm,         /*  I/O  */
                                        Z_long *Ds);        /*  I/O  */

boolean
DateCalc_add_delta_days                (Z_int  *year,       /*  I/O  */
                                        Z_int  *month,      /*  I/O  */
                                        Z_int  *day,        /*  I/O  */
                                        Z_long  Dd);        /*   I   */

boolean
DateCalc_add_delta_dhms                (Z_int  *year,       /*  I/O  */
                                        Z_int  *month,      /*  I/O  */
                                        Z_int  *day,        /*  I/O  */
                                        Z_int  *hour,       /*  I/O  */
                                        Z_int  *min,        /*  I/O  */
                                        Z_int  *sec,        /*  I/O  */
                                        Z_long  Dd,         /*   I   */
                                        Z_long  Dh,         /*   I   */
                                        Z_long  Dm,         /*   I   */
                                        Z_long  Ds);        /*   I   */

boolean /* PRIVATE */
DateCalc_add_year_month                (Z_int  *year,       /*  I/O  */
                                        Z_int  *month,      /*  I/O  */
                                        Z_long  Dy,         /*   I   */
                                        Z_long  Dm);        /*   I   */

boolean
DateCalc_add_delta_ym                  (Z_int  *year,       /*  I/O  */
                                        Z_int  *month,      /*  I/O  */
                                        Z_int  *day,        /*  I/O  */
                                        Z_long  Dy,         /*   I   */
                                        Z_long  Dm);        /*   I   */

boolean
DateCalc_add_delta_ymd                 (Z_int  *year,       /*  I/O  */
                                        Z_int  *month,      /*  I/O  */
                                        Z_int  *day,        /*  I/O  */
                                        Z_long  Dy,         /*   I   */
                                        Z_long  Dm,         /*   I   */
                                        Z_long  Dd);        /*   I   */

boolean
DateCalc_add_delta_ymdhms              (Z_int  *year,       /*  I/O  */
                                        Z_int  *month,      /*  I/O  */
                                        Z_int  *day,        /*  I/O  */
                                        Z_int  *hour,       /*  I/O  */
                                        Z_int  *min,        /*  I/O  */
                                        Z_int  *sec,        /*  I/O  */
                                        Z_long  D_y,        /*   I   */
                                        Z_long  D_m,        /*   I   */
                                        Z_long  D_d,        /*   I   */
                                        Z_long  Dh,         /*   I   */
                                        Z_long  Dm,         /*   I   */
                                        Z_long  Ds);        /*   I   */

boolean
DateCalc_add_norm_delta_ymd            (Z_int  *year,       /*  I/O  */
                                        Z_int  *month,      /*  I/O  */
                                        Z_int  *day,        /*  I/O  */
                                        Z_long  Dy,         /*   I   */
                                        Z_long  Dm,         /*   I   */
                                        Z_long  Dd);        /*   I   */

boolean
DateCalc_add_norm_delta_ymdhms         (Z_int  *year,       /*  I/O  */
                                        Z_int  *month,      /*  I/O  */
                                        Z_int  *day,        /*  I/O  */
                                        Z_int  *hour,       /*  I/O  */
                                        Z_int  *min,        /*  I/O  */
                                        Z_int  *sec,        /*  I/O  */
                                        Z_long  D_y,        /*   I   */
                                        Z_long  D_m,        /*   I   */
                                        Z_long  D_d,        /*   I   */
                                        Z_long  Dh,         /*   I   */
                                        Z_long  Dm,         /*   I   */
                                        Z_long  Ds);        /*   I   */

boolean
DateCalc_system_clock                  (Z_int  *year,       /*   O   */
                                        Z_int  *month,      /*   O   */
                                        Z_int  *day,        /*   O   */
                                        Z_int  *hour,       /*   O   */
                                        Z_int  *min,        /*   O   */
                                        Z_int  *sec,        /*   O   */
                                        Z_int  *doy,        /*   O   */
                                        Z_int  *dow,        /*   O   */
                                        Z_int  *dst,        /*   O   */
                                        boolean gmt);       /*   I   */

boolean
DateCalc_gmtime                        (Z_int  *year,       /*   O   */
                                        Z_int  *month,      /*   O   */
                                        Z_int  *day,        /*   O   */
                                        Z_int  *hour,       /*   O   */
                                        Z_int  *min,        /*   O   */
                                        Z_int  *sec,        /*   O   */
                                        Z_int  *doy,        /*   O   */
                                        Z_int  *dow,        /*   O   */
                                        Z_int  *dst,        /*   O   */
                                        time_t  seconds);   /*   I   */

boolean
DateCalc_localtime                     (Z_int  *year,       /*   O   */
                                        Z_int  *month,      /*   O   */
                                        Z_int  *day,        /*   O   */
                                        Z_int  *hour,       /*   O   */
                                        Z_int  *min,        /*   O   */
                                        Z_int  *sec,        /*   O   */
                                        Z_int  *doy,        /*   O   */
                                        Z_int  *dow,        /*   O   */
                                        Z_int  *dst,        /*   O   */
                                        time_t  seconds);   /*   I   */

boolean
DateCalc_mktime                        (time_t *seconds,    /*   O   */
                                        Z_int   year,       /*   I   */
                                        Z_int   month,      /*   I   */
                                        Z_int   day,        /*   I   */
                                        Z_int   hour,       /*   I   */
                                        Z_int   min,        /*   I   */
                                        Z_int   sec,        /*   I   */
                                        Z_int   doy,        /*   I   */
                                        Z_int   dow,        /*   I   */
                                        Z_int   dst);       /*   I   */

boolean
DateCalc_timezone                      (Z_int  *year,       /*   O   */
                                        Z_int  *month,      /*   O   */
                                        Z_int  *day,        /*   O   */
                                        Z_int  *hour,       /*   O   */
                                        Z_int  *min,        /*   O   */
                                        Z_int  *sec,        /*   O   */
                                        Z_int  *dst,        /*   O   */
                                        time_t when);       /*   I   */

boolean
DateCalc_date2time                     (time_t *seconds,    /*   O   */
                                        Z_int   year,       /*   I   */
                                        Z_int   month,      /*   I   */
                                        Z_int   day,        /*   I   */
                                        Z_int   hour,       /*   I   */
                                        Z_int   min,        /*   I   */
                                        Z_int   sec);       /*   I   */

boolean
DateCalc_time2date                     (Z_int  *year,       /*   O   */
                                        Z_int  *month,      /*   O   */
                                        Z_int  *day,        /*   O   */
                                        Z_int  *hour,       /*   O   */
                                        Z_int  *min,        /*   O   */
                                        Z_int  *sec,        /*   O   */
                                        time_t  seconds);   /*   I   */

boolean
DateCalc_easter_sunday                 (Z_int  *year,       /*  I/O  */
                                        Z_int  *month,      /*   O   */
                                        Z_int  *day);       /*   O   */

Z_int
DateCalc_Decode_Month                  (charptr buffer,
                                        Z_int   length,
                                        Z_int   lang);

Z_int
DateCalc_Decode_Day_of_Week            (charptr buffer,
                                        Z_int   length,
                                        Z_int   lang);

Z_int
DateCalc_Decode_Language               (charptr buffer,
                                        Z_int   length);

boolean
DateCalc_decode_date_eu                (charptr buffer,     /*   I   */
                                        Z_int  *year,       /*   O   */
                                        Z_int  *month,      /*   O   */
                                        Z_int  *day,        /*   O   */
                                        Z_int   lang);      /*   I   */

boolean
DateCalc_decode_date_us                (charptr buffer,     /*   I   */
                                        Z_int  *year,       /*   O   */
                                        Z_int  *month,      /*   O   */
                                        Z_int  *day,        /*   O   */
                                        Z_int   lang);      /*   I   */

Z_int
DateCalc_Fixed_Window                  (Z_int   year);

Z_int
DateCalc_Moving_Window                 (Z_int   year);

Z_int
DateCalc_Compress                      (Z_int   year,
                                        Z_int   month,
                                        Z_int   day);

boolean
DateCalc_uncompress                    (Z_int   date,       /*   I   */
                                        Z_int  *century,    /*   O   */
                                        Z_int  *year,       /*   O   */
                                        Z_int  *month,      /*   O   */
                                        Z_int  *day);       /*   O   */

boolean
DateCalc_check_compressed              (Z_int   date);

charptr
DateCalc_Compressed_to_Text            (Z_int   date,
                                        Z_int   lang);

charptr
DateCalc_Date_to_Text                  (Z_int   year,
                                        Z_int   month,
                                        Z_int   day,
                                        Z_int   lang);

charptr
DateCalc_Date_to_Text_Long             (Z_int   year,
                                        Z_int   month,
                                        Z_int   day,
                                        Z_int   lang);

charptr                                                     /*   O   */
DateCalc_English_Ordinal               (charptr result,     /*   O   */
                                        Z_int   number);    /*   I   */

charptr
DateCalc_Calendar                      (Z_int   year,
                                        Z_int   month,
                                        boolean orthodox,
                                        Z_int   lang);

void
DateCalc_Dispose                       (charptr string);

N_char
DateCalc_ISO_LC                        (N_char c);

N_char
DateCalc_ISO_UC                        (N_char c);

charptr
DateCalc_Version                       (void);

/*****************************************************************************/
/*  MODULE RESOURCES:                                                        */
/*****************************************************************************/

#define  DateCalc_YEAR_OF_EPOCH        70    /* year of reference (epoch)    */
#define  DateCalc_CENTURY_OF_EPOCH   1900    /* century of reference (epoch) */
#define  DateCalc_EPOCH (DateCalc_CENTURY_OF_EPOCH + DateCalc_YEAR_OF_EPOCH)

const Z_int DateCalc_Days_in_Year_[2][14] =
{
    { 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
    { 0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
};

const Z_int DateCalc_Days_in_Month_[2][13] =
{
    { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
    { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
};

#define DateCalc_LANGUAGES 14

Z_int DateCalc_Language = 1; /* Default = 1 (English) */

const N_char DateCalc_Month_to_Text_[DateCalc_LANGUAGES+1][13][32] =
{
    {
        "???", "???", "???", "???", "???", "???", "???",
        "???", "???", "???", "???", "???", "???"
    },
    {
        "???", "January", "February", "March", "April", "May", "June",
        "July", "August", "September", "October", "November", "December"
    },
    {
        "???", "janvier", "février", "mars", "avril", "mai", "juin",
        "juillet", "aoűt", "septembre", "octobre", "novembre", "décembre"
    },
    {
        "???", "Januar", "Februar", "März", "April", "Mai", "Juni",
        "Juli", "August", "September", "Oktober", "November", "Dezember"
    },
    {
        "???", "enero", "febrero", "marzo", "abril", "mayo", "junio",
        "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"
    },
    {
        "???", "janeiro", "fevereiro", "março", "abril", "maio", "junho",
        "julho", "agosto", "setembro", "outubro", "novembro", "dezembro"
    },
    {
        "???", "januari", "februari", "maart", "april", "mei", "juni",
        "juli", "augustus", "september", "oktober", "november", "december"
    },
    {
        "???", "Gennaio", "Febbraio", "Marzo", "Aprile", "Maggio", "Giugno",
        "Luglio", "Agosto", "Settembre", "Ottobre", "Novembre", "Dicembre"
    },
    {
        "???", "januar", "februar", "mars", "april", "mai", "juni",
        "juli", "august", "september", "oktober", "november", "desember"
    },
    {
        "???", "januari", "februari", "mars", "april", "maj", "juni",
        "juli", "augusti", "september", "oktober", "november", "december"
    },
    {
        "???", "januar", "februar", "marts", "april", "maj", "juni",
        "juli", "august", "september", "oktober", "november", "december"
    },
    {
        "???", "tammikuu", "helmikuu", "maaliskuu", "huhtikuu",
        "toukokuu", "kesäkuu", "heinäkuu", "elokuu",
        "syyskuu", "lokakuu", "marraskuu", "joulukuu"
    },
    {
        "???", "Január", "Február", "Március", "Április", "Május", "Június",
        "Július", "Augusztus", "Szeptember", "Október", "November", "December"
    },
    {
        "???", "Styczen", "Luty", "Marzec", "Kwiecien", "Maj", "Czerwiec",    /* ISO-Latin-1 approximation */
        "Lipiec", "Sierpien", "Wrzesien", "Pazdziernik", "Listopad", "Grudzien"
    },
    {
        "???", "Ianuarie", "Februarie", "Martie", "Aprilie", "Mai", "Iunie",
        "Iulie", "August", "Septembrie", "Octombrie", "Noiembrie", "Decembrie"
    }
};

const N_char DateCalc_Day_of_Week_to_Text_[DateCalc_LANGUAGES+1][8][32] =
{
    {
        "???", "???", "???", "???",
        "???", "???", "???", "???"
    },
    {
        "???", "Monday", "Tuesday", "Wednesday",
        "Thursday", "Friday", "Saturday", "Sunday"
    },
    {
        "???", "Lundi", "Mardi", "Mercredi",
        "Jeudi", "Vendredi", "Samedi", "Dimanche"
    },
    {
        "???", "Montag", "Dienstag", "Mittwoch",
        "Donnerstag", "Freitag", "Samstag", "Sonntag"
    },
    {
        "???", "Lunes", "Martes", "Miércoles",
        "Jueves", "Viernes", "Sábado", "Domingo"
    },
    {
        "???", "Segunda-feira", "Terça-feira", "Quarta-feira",
        "Quinta-feira", "Sexta-feira", "Sábado", "Domingo"
    },
    {
        "???", "Maandag", "Dinsdag", "Woensdag",
        "Donderdag", "Vrijdag", "Zaterdag", "Zondag"
    },
    {
        "???", "Lunedě", "Martedě", "Mercoledě",
        "Giovedě", "Venerdě", "Sabato", "Domenica"
    },
    {
        "???", "mandag", "tirsdag", "onsdag",
        "torsdag", "fredag", "lřrdag", "sřndag"
    },
    {
        "???", "mĺndag", "tisdag", "onsdag",
        "torsdag", "fredag", "lördag", "söndag"
    },
    {
        "???", "mandag", "tirsdag", "onsdag",
        "torsdag", "fredag", "lřrdag", "sřndag"
    },
    {
        "???", "maanantai", "tiistai", "keskiviikko",
        "torstai", "perjantai", "lauantai", "sunnuntai"
    },
    {
        "???", "hétfő", "kedd", "szerda",
        "csütörtök", "péntek", "szombat", "vasárnap"
    },
    {
        "???", "poniedzialek", "wtorek", "sroda",    /* ISO-Latin-1 approximation */
        "czwartek", "piatek", "sobota", "niedziela"
    },
    {
        "???", "Luni", "Marti", "Miercuri",
        "Joi", "Vineri", "Sambata", "Duminica"
    }
};

const N_char DateCalc_Day_of_Week_Abbreviation_[DateCalc_LANGUAGES+1][8][4] =

    /* Fill the fields below _only_ if special abbreviations are needed! */
    /* Note that the first field serves as a flag and must be non-empty! */
{
    {
        "", "", "", "", "", "", "", ""    /*  0 */
    },
    {
        "", "", "", "", "", "", "", ""    /*  1 */
    },
    {
        "", "", "", "", "", "", "", ""    /*  2 */
    },
    {
        "", "", "", "", "", "", "", ""    /*  3 */
    },
    {
        "", "", "", "", "", "", "", ""    /*  4 */
    },
    {
        "", "", "", "", "", "", "", ""    /*  5 */
/*      "???", "2Ş", "3Ş", "4Ş", "5Ş", "6Ş", "Sáb", "Dom"    /*  5 */
    },
    {
        "", "", "", "", "", "", "", ""    /*  6 */
    },
    {
        "", "", "", "", "", "", "", ""    /*  7 */
    },
    {
        "", "", "", "", "", "", "", ""    /*  8 */
    },
    {
        "", "", "", "", "", "", "", ""    /*  9 */
    },
    {
        "", "", "", "", "", "", "", ""    /* 10 */
    },
    {
        "", "", "", "", "", "", "", ""    /* 11 */
    },
    {
        "", "", "", "", "", "", "", ""    /* 12 */
    },
    {
        "???", "Pn", "Wt", "Sr", "Cz", "Pt", "So", "Ni"    /* 13 */ /* ISO-Latin-1 approximation */
    },
    {
        "", "", "", "", "", "", "", ""    /* 14 */
    }
};

const N_char DateCalc_English_Ordinals_[4][4] =
{
    "th",
    "st",
    "nd",
    "rd"
};

const N_char DateCalc_Date_Long_Format_[DateCalc_LANGUAGES+1][64] =
{
    "%s, %d %s %d",                     /*  0  Default     */
    "%s, %s %s %d",                     /*  1  English     */
    "%s %d %s %d",                      /*  2  Français    */
    "%s, den %d. %s %d",                /*  3  Deutsch     */
    "%s, %d de %s de %d",               /*  4  Espańol     */
    "%s, dia %d de %s de %d",           /*  5  Portuguęs   */
    "%s, %d %s %d",                     /*  6  Nederlands  */
    "%s, %d %s %d",                     /*  7  Italiano    */
    "%s, %d. %s %d",                    /*  8  Norsk       */
    "%s, %d %s %d",                     /*  9  Svenska     */
    "%s, %d. %s %d",                    /* 10  Dansk       */
    "%s, %d. %sta %d",                  /* 11  suomi       */
    "%d. %s %d., %s",                   /* 12  Magyar      */
    "%s, %d %s %d",                     /* 13  polski      */
    "%s %d %s %d"                       /* 14  Romaneste   */
};

const N_char DateCalc_Language_to_Text_[DateCalc_LANGUAGES+1][32] =
{
    "???", "English", "Français", "Deutsch", "Espańol",
    "Portuguęs", "Nederlands", "Italiano", "Norsk", "Svenska",
    "Dansk", "suomi", "Magyar", "polski", "Romaneste"
};

/*****************************************************************************/
/*  MODULE IMPLEMENTATION:                                                   */
/*****************************************************************************/

static boolean DateCalc_is_digit(N_char c)
{
    N_int i = (N_int) c;

    if ((i >= 0x30) and (i <= 0x39)) return(true);
    return(false);
}

static boolean DateCalc_is_alnum(N_char c)
{
    N_int i = (N_int) c;

    if (((i >= 0x30) and (i <= 0x39)) or
        ((i >= 0x41) and (i <= 0x5A)) or
        ((i >= 0x61) and (i <= 0x7A)) or
        ((i >= 0xC0) and (i <= 0xD6)) or
        ((i >= 0xD8) and (i <= 0xF6)) or
        ((i >= 0xF8) and (i <= 0xFF)))
            return(true);
    return(false);
}

N_char DateCalc_ISO_LC(N_char c)
{
    N_int i = (N_int) c;

    if (((i >= 0x41) and (i <= 0x5A)) or
        ((i >= 0xC0) and (i <= 0xD6)) or
        ((i >= 0xD8) and (c <= 0xDE))) i += 0x20;
    return((N_char) i);
}

N_char DateCalc_ISO_UC(N_char c)
{
    N_int i = (N_int) c;

    if (((i >= 0x61) and (i <= 0x7A)) or
        ((i >= 0xE0) and (i <= 0xF6)) or
        ((i >= 0xF8) and (c <= 0xFE))) i -= 0x20;
    return((N_char) i);
}

static Z_long DateCalc_Year_to_Days(Z_int year)
{
    Z_long days;

    days = year * 365L;
    days += year >>= 2;
    days -= year /= 25;
    days += year >>  2;
    return(days);
}

static boolean DateCalc_scan9(charptr str, Z_int len, Z_int idx, boolean neg)
{   /* Mnemonic: COBOL "PIC 9" */
    if ((str != NULL) and (idx >= 0) and (idx < len))
        return( DateCalc_is_digit(str[idx]) XOR neg );
    return(false);
}

static boolean DateCalc_scanx(charptr str, Z_int len, Z_int idx, boolean neg)
{   /* Mnemonic: COBOL "PIC X" */
    if ((str != NULL) and (idx >= 0) and (idx < len))
        return( DateCalc_is_alnum(str[idx]) XOR neg );
    return(false);
}

static Z_int DateCalc_Str2Int(charptr string, Z_int length)
{
    Z_int number = 0;

    while (length-- > 0)
    {
        if (number) number *= 10;
        number += (Z_int) (*string++ - '0');
    }
    return(number);
}

static void DateCalc_Center(charptr *target, charptr source, Z_int width)
{
    Z_int length;
    Z_int blank;

    length = strlen((char *)source);
    if (length > width) length = width;
    blank = width - length;
    blank >>= 1;
    while (blank-- > 0) *(*target)++ = ' ';
    while (length-- > 0) *(*target)++ = *source++;
    *(*target)++ = '\n';
    *(*target)   = '\0';
}

static void DateCalc_Blank(charptr *target, Z_int count)
{
    while (count-- > 0) *(*target)++ = ' ';
    *(*target) = '\0';
}

static void DateCalc_Newline(charptr *target, Z_int count)
{
    while (count-- > 0) *(*target)++ = '\n';
    *(*target) = '\0';
}

static void DateCalc_Normalize_Time(Z_long *Dd, Z_long *Dh, Z_long *Dm, Z_long *Ds)
{
    Z_long quot;

    quot = (Z_long) (*Ds / 60L);
    *Ds -= quot * 60L;
    *Dm += quot;
    quot = (Z_long) (*Dm / 60L);
    *Dm -= quot * 60L;
    *Dh += quot;
    quot = (Z_long) (*Dh / 24L);
    *Dh -= quot * 24L;
    *Dd += quot;
}

static void DateCalc_Normalize_Ranges(Z_long *Dd, Z_long *Dh, Z_long *Dm, Z_long *Ds)
{
    Z_long quot;

    /* Prevent overflow errors on systems */
    /* with short "long"s (e.g. 32 bits): */

    quot = (Z_long) (*Dh / 24L);
    *Dh -= quot * 24L;
    *Dd += quot;
    quot = (Z_long) (*Dm / 60L);
    *Dm -= quot * 60L;
    *Dh += quot;
    DateCalc_Normalize_Time(Dd,Dh,Dm,Ds);
}

static void DateCalc_Normalize_Signs(Z_long *Dd, Z_long *Dh, Z_long *Dm, Z_long *Ds)
{
    Z_long quot;

    quot = (Z_long) (*Ds / 86400L);
    *Ds -= quot * 86400L;
    *Dd += quot;
    if (*Dd != 0L)
    {
        if (*Dd > 0L)
        {
            if (*Ds < 0L)
            {
                *Ds += 86400L;
                (*Dd)--;
            }
        }
        else
        {
            if (*Ds > 0L)
            {
                *Ds -= 86400L;
                (*Dd)++;
            }
        }
    }
    *Dh = 0L;
    *Dm = 0L;
    if (*Ds != 0L) DateCalc_Normalize_Time(Dd,Dh,Dm,Ds);
}

void DateCalc_Normalize_DHMS(Z_long *Dd, Z_long *Dh, Z_long *Dm, Z_long *Ds)
{
    DateCalc_Normalize_Ranges(Dd,Dh,Dm,Ds);
    *Ds += ((*Dh * 60L) + *Dm) * 60L;
    DateCalc_Normalize_Signs(Dd,Dh,Dm,Ds);
}

/*****************************************************************************/

boolean DateCalc_leap_year(Z_int year)
{
    Z_int yy;

    return( ((year AND 0x03) == 0) and
            ( (((yy = (Z_int) (year / 100)) * 100) != year) or
                ((yy AND 0x03) == 0) ) );
}

boolean DateCalc_check_date(Z_int year, Z_int month, Z_int day)
{
    if ((year >= 1) and
        (month >= 1) and (month <= 12) and
        (day >= 1) and
        (day <= DateCalc_Days_in_Month_[DateCalc_leap_year(year)][month]))
            return(true);
    return(false);
}

boolean DateCalc_check_time(Z_int hour, Z_int min, Z_int sec)
{
    if ((hour >= 0) and (min >= 0) and (sec >= 0) and
        (hour < 24) and (min < 60) and (sec < 60))
            return(true);
    return(false);
}

boolean DateCalc_check_business_date(Z_int year, Z_int week, Z_int dow)
{
    if ((year >= 1) and
        (week >= 1) and (week <= DateCalc_Weeks_in_Year(year)) and
        (dow >= 1) and (dow <= 7))
            return(true);
    return(false);
}

Z_int DateCalc_Day_of_Year(Z_int year, Z_int month, Z_int day)
{
    boolean leap;

    if ((year >= 1) and
        (month >= 1) and (month <= 12) and
        (day >= 1) and
        (day <= DateCalc_Days_in_Month_[leap=DateCalc_leap_year(year)][month]))
            return( DateCalc_Days_in_Year_[leap][month] + day );
    return(0);
}

Z_long DateCalc_Date_to_Days(Z_int year, Z_int month, Z_int day)
{
    boolean leap;

    if ((year >= 1) and
        (month >= 1) and (month <= 12) and
        (day >= 1) and
        (day <= DateCalc_Days_in_Month_[leap=DateCalc_leap_year(year)][month]))
            return( DateCalc_Year_to_Days(--year) +
                    DateCalc_Days_in_Year_[leap][month] + day );
    return(0L);
}

Z_int DateCalc_Day_of_Week(Z_int year, Z_int month, Z_int day)
{
    Z_long days;

    days = DateCalc_Date_to_Days(year,month,day);
    if (days > 0L)
    {
        days--;
        days %= 7L;
        days++;
    }
    return( (Z_int) days );
}

Z_int DateCalc_Weeks_in_Year(Z_int year)
{
    return( 52 + ((DateCalc_Day_of_Week(year,1,1)   == 4) or
                  (DateCalc_Day_of_Week(year,12,31) == 4)) );
}

Z_int DateCalc_Week_Number(Z_int year, Z_int month, Z_int day)
{
    Z_int first;

    first = DateCalc_Day_of_Week(year,1,1) - 1;
    return( (Z_int)
        ( (DateCalc_Delta_Days(year,1,1, year,month,day) + first) / 7L )
        + (first < 4) );
}

boolean DateCalc_week_of_year(Z_int *week,
                              Z_int *year, Z_int month, Z_int day)
{
    if (DateCalc_check_date(*year,month,day))
    {
        *week = DateCalc_Week_Number(*year,month,day);
        if (*week == 0) *week = DateCalc_Weeks_in_Year(--(*year));
        else if (*week > DateCalc_Weeks_in_Year(*year))
        {
            *week = 1;
            (*year)++;
        }
        return(true);
    }
    return(false);
}

boolean DateCalc_monday_of_week(Z_int  week,
                                Z_int *year, Z_int *month, Z_int *day)
{
    Z_int first;

    *month = *day = 1;
    first = DateCalc_Day_of_Week(*year,1,1) - 1;
    if (first < 4) week--;
    return( DateCalc_add_delta_days(year,month,day, (week * 7L - first)) );
}

boolean
DateCalc_nth_weekday_of_month_year(Z_int *year, Z_int *month, Z_int *day,
                                   Z_int  dow,  Z_int  n)
{
    Z_int  mm = *month;
    Z_int  first;
    Z_long delta;

    *day = 1;
    if ((*year < 1) or
        (mm < 1) or (mm > 12) or
        (dow < 1) or (dow > 7) or
        (n < 1) or (n > 5))
        return(false);
    first = DateCalc_Day_of_Week(*year,mm,1);
    if (dow < first) dow += 7;
    delta = (Z_long) (dow - first);
    delta += (n-1) * 7L;
    if (DateCalc_add_delta_days(year,month,day,delta) and (*month == mm))
        return(true);
    return(false);
}

boolean DateCalc_standard_to_business(Z_int *year,  Z_int *week, Z_int *dow,
                                      Z_int  month, Z_int  day)
{
    Z_int yy = *year;

    if (DateCalc_week_of_year(week,year,month,day))
    {
        *dow = DateCalc_Day_of_Week(yy,month,day);
        return(true);
    }
    return(false);
}

boolean DateCalc_business_to_standard(Z_int *year, Z_int *month, Z_int *day,
                                      Z_int  week, Z_int  dow)
{
    Z_int  first;
    Z_long delta;

    if (DateCalc_check_business_date(*year,week,dow))
    {
        *month = *day = 1;
        first = DateCalc_Day_of_Week(*year,1,1);
        delta = ((week + (first > 4) - 1) * 7L) + (dow - first);
        return( DateCalc_add_delta_days(year,month,day,delta) );
    }
    return(false);
}

Z_long DateCalc_Delta_Days(Z_int year1, Z_int month1, Z_int day1,
                           Z_int year2, Z_int month2, Z_int day2)
{
    return( DateCalc_Date_to_Days(year2,month2,day2) -
            DateCalc_Date_to_Days(year1,month1,day1) );
}

boolean DateCalc_delta_hms(Z_long *Dd,
                           Z_int  *Dh,    Z_int *Dm,   Z_int *Ds,
                           Z_int   hour1, Z_int  min1, Z_int  sec1,
                           Z_int   hour2, Z_int  min2, Z_int  sec2)
{
    Z_long HH;
    Z_long MM;
    Z_long SS;

    if (DateCalc_check_time(hour1,min1,sec1) and
        DateCalc_check_time(hour2,min2,sec2))
    {
        SS = ((((hour2 * 60L) + min2) * 60L) + sec2) -
             ((((hour1 * 60L) + min1) * 60L) + sec1);
        DateCalc_Normalize_Signs(Dd,&HH,&MM,&SS);
        *Dh = (Z_int) HH;
        *Dm = (Z_int) MM;
        *Ds = (Z_int) SS;
        return(true);
    }
    return(false);
}

boolean DateCalc_delta_dhms(Z_long *Dd,
                            Z_int  *Dh,    Z_int *Dm,     Z_int *Ds,
                            Z_int   year1, Z_int  month1, Z_int  day1,
                            Z_int   hour1, Z_int  min1,   Z_int  sec1,
                            Z_int   year2, Z_int  month2, Z_int  day2,
                            Z_int   hour2, Z_int  min2,   Z_int  sec2)
{
    *Dd = *Dh = *Dm = *Ds = 0;
    if (DateCalc_check_date(year1,month1,day1) and
        DateCalc_check_date(year2,month2,day2))
    {
        *Dd = DateCalc_Delta_Days(year1,month1,day1, year2,month2,day2);
        return( DateCalc_delta_hms(Dd,Dh,Dm,Ds,
                                   hour1,min1,sec1,
                                   hour2,min2,sec2) );
    }
    return(false);
}

boolean DateCalc_delta_ymd(Z_int *year1, Z_int *month1, Z_int *day1,
                           Z_int  year2, Z_int  month2, Z_int  day2)
{
    if (DateCalc_check_date(*year1,*month1,*day1) and
        DateCalc_check_date(year2,month2,day2))
    {
        *day1   = day2   - *day1;
        *month1 = month2 - *month1;
        *year1  = year2  - *year1;
        return(true);
    }
    return(false);
}

boolean DateCalc_delta_ymdhms(Z_int *D_y,   Z_int *D_m,    Z_int *D_d,
                              Z_int *Dh,    Z_int *Dm,     Z_int *Ds,
                              Z_int  year1, Z_int  month1, Z_int  day1,
                              Z_int  hour1, Z_int  min1,   Z_int  sec1,
                              Z_int  year2, Z_int  month2, Z_int  day2,
                              Z_int  hour2, Z_int  min2,   Z_int  sec2)
{
    Z_long Dd;

    if (not DateCalc_delta_ymd(&year1,&month1,&day1, year2,month2,day2))
        return(false);
    Dd = (Z_long) day1;
    if (not DateCalc_delta_hms(&Dd,Dh,Dm,Ds, hour1,min1,sec1, hour2,min2,sec2))
        return(false);
    *D_y = year1;
    *D_m = month1;
    *D_d = (Z_int) Dd;
    return(true);
}

boolean DateCalc_norm_delta_ymd(Z_int *year1, Z_int *month1, Z_int *day1,
                                Z_int  year2, Z_int  month2, Z_int  day2)
{
    Z_long Dy = 0L;
    Z_long Dm = 0L;
    Z_long Dd = 0L;
    Z_long d2;
    Z_int  ty;
    Z_int  tm;
    Z_int  td;

    if (DateCalc_check_date(*year1,*month1,*day1) and
        DateCalc_check_date(year2,month2,day2))
    {
        d2 =    DateCalc_Date_to_Days(year2,month2,day2);
        Dd = d2-DateCalc_Date_to_Days(*year1,*month1,*day1);
        if ((Dd < -30L) or (Dd > 30L))
        {
            Dy = (Z_long) (year2  - *year1);
            Dm = (Z_long) (month2 - *month1);
            ty=*year1; tm=*month1; td=*day1; if (!DateCalc_add_delta_ym(&ty,&tm,&td,Dy,Dm)) return(false); Dd=d2-DateCalc_Date_to_Days(ty,tm,td);
            if (!(((Dy >= 0L) and (Dm >= 0L) and (Dd >= 0L)) or
                  ((Dy <= 0L) and (Dm <= 0L) and (Dd <= 0L))))
            {
                if      ((Dy < 0L) and (Dm > 0L)) { Dy++; Dm -= 12L; }
                else if ((Dy > 0L) and (Dm < 0L)) { Dy--; Dm += 12L; }
                if      ((Dm < 0L) and (Dd > 0L)) { Dm++; ty=*year1; tm=*month1; td=*day1; if (!DateCalc_add_delta_ym(&ty,&tm,&td,Dy,Dm)) return(false); Dd=d2-DateCalc_Date_to_Days(ty,tm,td); }
                else if ((Dm > 0L) and (Dd < 0L)) { Dm--; ty=*year1; tm=*month1; td=*day1; if (!DateCalc_add_delta_ym(&ty,&tm,&td,Dy,Dm)) return(false); Dd=d2-DateCalc_Date_to_Days(ty,tm,td); }
                if      ((Dy < 0L) and (Dd > 0L)) { Dy++; Dm -= 12L; }
                else if ((Dy > 0L) and (Dd < 0L)) { Dy--; Dm += 12L; }
                if      ((Dm < 0L) and (Dd > 0L)) { Dm++; ty=*year1; tm=*month1; td=*day1; if (!DateCalc_add_delta_ym(&ty,&tm,&td,Dy,Dm)) return(false); Dd=d2-DateCalc_Date_to_Days(ty,tm,td); }
                else if ((Dm > 0L) and (Dd < 0L)) { Dm--; ty=*year1; tm=*month1; td=*day1; if (!DateCalc_add_delta_ym(&ty,&tm,&td,Dy,Dm)) return(false); Dd=d2-DateCalc_Date_to_Days(ty,tm,td); }
            }
        }
        *year1  = (Z_int) Dy;
        *month1 = (Z_int) Dm;
        *day1   = (Z_int) Dd;
        return(true);
    }
    return(false);
}

boolean DateCalc_norm_delta_ymdhms(Z_int *D_y,   Z_int *D_m,    Z_int *D_d,
                                   Z_int *Dhh,   Z_int *Dmm,    Z_int *Dss,
                                   Z_int  year1, Z_int  month1, Z_int  day1,
                                   Z_int  hour1, Z_int  min1,   Z_int  sec1,
                                   Z_int  year2, Z_int  month2, Z_int  day2,
                                   Z_int  hour2, Z_int  min2,   Z_int  sec2)
{
    Z_long Dy = 0L;
    Z_long Dm = 0L;
    Z_long Dd = 0L;
    Z_long d2, hh, mm, ss;
    Z_int  ty;
    Z_int  tm;
    Z_int  td;

    if (DateCalc_check_date(year1,month1,day1) and
        DateCalc_check_time(hour1,min1,  sec1) and
        DateCalc_check_date(year2,month2,day2) and
        DateCalc_check_time(hour1,min2,  sec2))
    {
        ss = ( (hour2-hour1) * 60L + (min2-min1) ) * 60L + (sec2-sec1);
        d2 =    DateCalc_Date_to_Days(year2,month2,day2);
        Dd = d2-DateCalc_Date_to_Days(year1,month1,day1);
        if ((Dd < -30L) or (Dd > 30L))
        {
            Dy = (Z_long) (year2  - year1);
            Dm = (Z_long) (month2 - month1);
            ty=year1; tm=month1; td=day1; if (!DateCalc_add_delta_ym(&ty,&tm,&td,Dy,Dm)) return(false); Dd=d2-DateCalc_Date_to_Days(ty,tm,td);
            if (!(((Dy >= 0L) and (Dm >= 0L) and (Dd >= 0L) and (ss >= 0L)) or
                  ((Dy <= 0L) and (Dm <= 0L) and (Dd <= 0L) and (ss <= 0L))))
            {
                if      ((Dy < 0L) and (Dm > 0L)) { Dy++; Dm -= 12L; }
                else if ((Dy > 0L) and (Dm < 0L)) { Dy--; Dm += 12L; }
                if      ((Dm < 0L) and (Dd > 0L)) { Dm++; ty=year1; tm=month1; td=day1; if (!DateCalc_add_delta_ym(&ty,&tm,&td,Dy,Dm)) return(false); Dd=d2-DateCalc_Date_to_Days(ty,tm,td); }
                else if ((Dm > 0L) and (Dd < 0L)) { Dm--; ty=year1; tm=month1; td=day1; if (!DateCalc_add_delta_ym(&ty,&tm,&td,Dy,Dm)) return(false); Dd=d2-DateCalc_Date_to_Days(ty,tm,td); }
                if      ((Dy < 0L) and (Dd > 0L)) { Dy++; Dm -= 12L; }
                else if ((Dy > 0L) and (Dd < 0L)) { Dy--; Dm += 12L; }
                if      ((Dm < 0L) and (Dd > 0L)) { Dm++; ty=year1; tm=month1; td=day1; if (!DateCalc_add_delta_ym(&ty,&tm,&td,Dy,Dm)) return(false); Dd=d2-DateCalc_Date_to_Days(ty,tm,td); }
                else if ((Dm > 0L) and (Dd < 0L)) { Dm--; ty=year1; tm=month1; td=day1; if (!DateCalc_add_delta_ym(&ty,&tm,&td,Dy,Dm)) return(false); Dd=d2-DateCalc_Date_to_Days(ty,tm,td); }
                if      ((Dd < 0L) and (ss > 0L)) { Dd++; ss -= 86400L; }
                else if ((Dd > 0L) and (ss < 0L)) { Dd--; ss += 86400L; }
                if      ((Dm < 0L) and (ss > 0L)) { Dm++; ty=year1; tm=month1; td=day1; if (!DateCalc_add_delta_ym(&ty,&tm,&td,Dy,Dm)) return(false); Dd=d2-DateCalc_Date_to_Days(ty,tm,td); }
                else if ((Dm > 0L) and (ss < 0L)) { Dm--; ty=year1; tm=month1; td=day1; if (!DateCalc_add_delta_ym(&ty,&tm,&td,Dy,Dm)) return(false); Dd=d2-DateCalc_Date_to_Days(ty,tm,td); }
                if      ((Dy < 0L) and (ss > 0L)) { Dy++; Dm -= 12L; }
                else if ((Dy > 0L) and (ss < 0L)) { Dy--; Dm += 12L; }
                if      ((Dm < 0L) and (ss > 0L)) { Dm++; ty=year1; tm=month1; td=day1; if (!DateCalc_add_delta_ym(&ty,&tm,&td,Dy,Dm)) return(false); Dd=d2-DateCalc_Date_to_Days(ty,tm,td); }
                else if ((Dm > 0L) and (ss < 0L)) { Dm--; ty=year1; tm=month1; td=day1; if (!DateCalc_add_delta_ym(&ty,&tm,&td,Dy,Dm)) return(false); Dd=d2-DateCalc_Date_to_Days(ty,tm,td); }
                if      ((Dd < 0L) and (ss > 0L)) { Dd++; ss -= 86400L; }
                else if ((Dd > 0L) and (ss < 0L)) { Dd--; ss += 86400L; }
            }
        }
        else
        {
            if      ((Dd < 0L) and (ss > 0L)) { Dd++; ss -= 86400L; }
            else if ((Dd > 0L) and (ss < 0L)) { Dd--; ss += 86400L; }
        }
        mm = (Z_long) ( ss / 60 );
        ss -= mm * 60;
        hh = (Z_long) ( mm / 60 );
        mm -= hh * 60;
        *D_y    = (Z_int) Dy;
        *D_m    = (Z_int) Dm;
        *D_d    = (Z_int) Dd;
        *Dhh    = (Z_int) hh;
        *Dmm    = (Z_int) mm;
        *Dss    = (Z_int) ss;
        return(true);
    }
    return(false);
}

boolean DateCalc_add_delta_days(Z_int *year, Z_int *month, Z_int *day,
                                                           Z_long Dd)
{
    Z_long  days;
    boolean leap;

    if (((days = DateCalc_Date_to_Days(*year,*month,*day)) > 0L) and
        ((days += Dd) > 0L))
    {
        if (Dd != 0L)
        {
            *year = (Z_int) ( days / 365.2425 );
            *day  = (Z_int) ( days - DateCalc_Year_to_Days(*year) );
            if (*day < 1)
            {
                *day = (Z_int) ( days - DateCalc_Year_to_Days(*year-1) );
            }
            else (*year)++;
            leap = DateCalc_leap_year(*year);
            if (*day > DateCalc_Days_in_Year_[leap][13])
            {
                *day -= DateCalc_Days_in_Year_[leap][13];
                leap  = DateCalc_leap_year(++(*year));
            }
            for ( *month = 12; *month >= 1; (*month)-- )
            {
                if (*day > DateCalc_Days_in_Year_[leap][*month])
                {
                    *day -= DateCalc_Days_in_Year_[leap][*month];
                    break;
                }
            }
        }
        return(true);
    }
    return(false);
}

boolean DateCalc_add_delta_dhms(Z_int *year, Z_int *month, Z_int *day,
                                Z_int *hour, Z_int *min,   Z_int *sec,
                                Z_long Dd,
                                Z_long Dh,   Z_long Dm,    Z_long Ds)
{
    if (DateCalc_check_date(*year,*month,*day) and
        DateCalc_check_time(*hour,*min,*sec))
    {
        DateCalc_Normalize_Ranges(&Dd,&Dh,&Dm,&Ds);
        Ds += ((((*hour * 60L) + *min) * 60L) + *sec) +
               ((( Dh   * 60L) +  Dm)  * 60L);
        while (Ds < 0L)
        {
            Ds += 86400L;
            Dd--;
        }
        if (Ds > 0L)
        {
            Dh = 0L;
            Dm = 0L;
            DateCalc_Normalize_Time(&Dd,&Dh,&Dm,&Ds);
            *hour = (Z_int) Dh;
            *min  = (Z_int) Dm;
            *sec  = (Z_int) Ds;
        }
        else *hour = *min = *sec = 0;
        return( DateCalc_add_delta_days(year,month,day,Dd) );
    }
    return(false);
}

boolean DateCalc_add_year_month(Z_int *year, Z_int *month,
                                Z_long Dy,   Z_long Dm)
{
    Z_long quot;

    if ((*year < 1) or (*month < 1) or (*month > 12)) return(false);
    if (Dm != 0L)
    {
        Dm  += (Z_long) (*month - 1);
        quot = (Z_long) (Dm / 12L);
        Dm  -= quot * 12L;
        if (Dm < 0L)
        {
            Dm += 12L;
            quot--;
        }
        *month = (Z_int) (Dm + 1);
        Dy += quot;
    }
    if (Dy != 0L)
    {
        Dy += (Z_long) *year;
        *year = (Z_int) Dy;
    }
    if (*year < 1) return(false);
    return(true);
}

boolean DateCalc_add_delta_ym(Z_int *year, Z_int *month, Z_int *day,
                              Z_long Dy,   Z_long Dm)
{
    Z_int Dd;

    if (not DateCalc_check_date(*year,*month,*day)) return(false);
    if (not DateCalc_add_year_month(year,month,Dy,Dm)) return(false);
    if (*day >
        (Dd = DateCalc_Days_in_Month_[DateCalc_leap_year(*year)][*month]))
            *day = Dd;
    return(true);
}

boolean DateCalc_add_delta_ymd(Z_int *year, Z_int *month, Z_int *day,
                               Z_long Dy,   Z_long Dm,    Z_long Dd)
{
    if (not DateCalc_check_date(*year,*month,*day)) return(false);
    if (not DateCalc_add_year_month(year,month,Dy,Dm)) return(false);
    Dd += (Z_long) (*day - 1);
    *day = 1;
    return( DateCalc_add_delta_days(year,month,day,Dd) );
}

boolean DateCalc_add_delta_ymdhms(Z_int *year, Z_int *month, Z_int *day,
                                  Z_int *hour, Z_int *min,   Z_int *sec,
                                  Z_long D_y,  Z_long D_m,   Z_long D_d,
                                  Z_long Dh,   Z_long Dm,    Z_long Ds)
{
    if (not (DateCalc_check_date(*year,*month,*day) and
             DateCalc_check_time(*hour,*min,*sec))) return(false);
    if (not  DateCalc_add_year_month(year,month,D_y,D_m)) return(false);
    D_d += (Z_long) (*day - 1);
    *day = 1;
    return( DateCalc_add_delta_dhms(year,month,day,hour,min,sec,D_d,Dh,Dm,Ds) );
}

boolean DateCalc_add_norm_delta_ymd(Z_int *year, Z_int *month, Z_int *day,
                                    Z_long Dy,   Z_long Dm,    Z_long Dd)
{
    if (not DateCalc_add_delta_ym(year,month,day,Dy,Dm)) return(false);
    return( DateCalc_add_delta_days(year,month,day,Dd) );
}

boolean DateCalc_add_norm_delta_ymdhms(Z_int *year, Z_int *month, Z_int *day,
                                       Z_int *hour, Z_int *min,   Z_int *sec,
                                       Z_long D_y,  Z_long D_m,   Z_long D_d,
                                       Z_long Dh,   Z_long Dm,    Z_long Ds)
{
    if (not DateCalc_add_delta_ym(year,month,day,D_y,D_m)) return(false);
    return( DateCalc_add_delta_dhms(year,month,day,hour,min,sec,D_d,Dh,Dm,Ds) );
}

boolean DateCalc_system_clock(Z_int  *year, Z_int *month, Z_int *day,
                              Z_int  *hour, Z_int *min,   Z_int *sec,
                              Z_int  *doy,  Z_int *dow,   Z_int *dst,
                              boolean gmt)
{
    time_t seconds;
    struct tm *date;

    if (time(&seconds) >= 0)
    {
        if (gmt) date = gmtime(&seconds);
        else     date = localtime(&seconds);
        if (date != NULL)
        {
            *year  = (*date).tm_year + 1900;
            *month = (*date).tm_mon + 1;
            *day   = (*date).tm_mday;
            *hour  = (*date).tm_hour;
            *min   = (*date).tm_min;
            *sec   = (*date).tm_sec;
            *doy   = (*date).tm_yday + 1;
            *dow   = (*date).tm_wday; if (*dow == 0) *dow = 7;
            *dst   = (*date).tm_isdst;
            if (*dst != 0)
            {
                if (*dst < 0) *dst = -1;
                else          *dst =  1;
            }
            return(true);
        }
    }
    return(false);
}

boolean DateCalc_gmtime(Z_int  *year, Z_int *month, Z_int *day,
                        Z_int  *hour, Z_int *min,   Z_int *sec,
                        Z_int  *doy,  Z_int *dow,   Z_int *dst,
                        time_t  seconds)
{
    struct tm *date;

    if ((seconds >= 0) and ((date = gmtime(&seconds)) != NULL))
    {
        *year  = (*date).tm_year + 1900;
        *month = (*date).tm_mon + 1;
        *day   = (*date).tm_mday;
        *hour  = (*date).tm_hour;
        *min   = (*date).tm_min;
        *sec   = (*date).tm_sec;
        *doy   = (*date).tm_yday + 1;
        *dow   = (*date).tm_wday; if (*dow == 0) *dow = 7;
        *dst   = (*date).tm_isdst;
        if (*dst != 0)
        {
            if (*dst < 0) *dst = -1;
            else          *dst =  1;
        }
        return(true);
    }
    return(false);
}

boolean DateCalc_localtime(Z_int  *year, Z_int *month, Z_int *day,
                           Z_int  *hour, Z_int *min,   Z_int *sec,
                           Z_int  *doy,  Z_int *dow,   Z_int *dst,
                           time_t  seconds)
{
    struct tm *date;

    if ((seconds >= 0) and ((date = localtime(&seconds)) != NULL))
    {
        *year  = (*date).tm_year + 1900;
        *month = (*date).tm_mon + 1;
        *day   = (*date).tm_mday;
        *hour  = (*date).tm_hour;
        *min   = (*date).tm_min;
        *sec   = (*date).tm_sec;
        *doy   = (*date).tm_yday + 1;
        *dow   = (*date).tm_wday; if (*dow == 0) *dow = 7;
        *dst   = (*date).tm_isdst;
        if (*dst != 0)
        {
            if (*dst < 0) *dst = -1;
            else          *dst =  1;
        }
        return(true);
    }
    return(false);
}

/* MacOS (Classic):                                            */
/* <695056.0>     = Fri  1-Jan-1904 00:00:00 (time=0x00000000) */
/* <744766.23295> = Mon  6-Feb-2040 06:28:15 (time=0xFFFFFFFF) */

/* Unix:                                                       */
/* <719163.0>     = Thu  1-Jan-1970 00:00:00 (time=0x00000000) */
/* <744018.11647> = Tue 19-Jan-2038 03:14:07 (time=0x7FFFFFFF) */

boolean DateCalc_mktime(time_t *seconds,
                        Z_int year, Z_int month, Z_int day,
                        Z_int hour, Z_int min,   Z_int sec,
                        Z_int doy,  Z_int dow,   Z_int dst)
{
    struct tm date;

    *seconds = (time_t) 0;

#ifdef MACOS_TRADITIONAL
    if ( (year  < 1904) or (year  > 2040) or
#else
    if ( (year  < 1970) or (year  > 2038) or
#endif
         (month <    1) or (month >   12) or
         (day   <    1) or (day   >   31) or
         (hour  <    0) or (hour  >   23) or
         (min   <    0) or (min   >   59) or
         (sec   <    0) or (sec   >   59) )
    return(false);

#ifdef MACOS_TRADITIONAL
    if ( (year == 2040) and ( (month >  2) or
                            ( (month == 2) and ( (day >  6) or
                                               ( (day == 6) and ( (hour >  6) or
                                                                ( (hour == 6) and ( (min >  28) or
                                                                                  ( (min == 28) and (sec > 15) ) ))))))) )
    return(false);
#else
    if ( (year == 2038) and ( (month >  1) or
                            ( (month == 1) and ( (day >  19) or
                                               ( (day == 19) and ( (hour >  3) or
                                                                 ( (hour == 3) and ( (min >  14) or
                                                                                   ( (min == 14) and (sec > 7) ) ))))))) )
    return(false);
#endif

    year -= 1900;
    month--;
    if (doy <= 0) doy = -1;
    else          doy--;
    if (dow <= 0) dow = -1; else
    if (dow == 7) dow =  0;
    if (dst != 0)
    {
        if (dst < 0) dst = -1;
        else         dst =  1;
    }
    date.tm_year  = year;
    date.tm_mon   = month;
    date.tm_mday  = day;
    date.tm_hour  = hour;
    date.tm_min   = min;
    date.tm_sec   = sec;
    date.tm_yday  = doy;
    date.tm_wday  = dow;
    date.tm_isdst = dst;
    *seconds = mktime(&date);
    return(*seconds >= 0);
}

boolean DateCalc_timezone(Z_int *year, Z_int *month, Z_int *day,
                          Z_int *hour, Z_int *min,   Z_int *sec,
                          Z_int *dst,  time_t when)
{
    struct tm *date;
    Z_int  year1;
    Z_int  month1;
    Z_int  day1;
    Z_int  hour1;
    Z_int  min1;
    Z_int  sec1;
    Z_int  year2;
    Z_int  month2;
    Z_int  day2;
    Z_int  hour2;
    Z_int  min2;
    Z_int  sec2;

    if (when >= 0)
    {
        if ((date = gmtime(&when)) == NULL) return(false);
        year1  = (*date).tm_year + 1900;
        month1 = (*date).tm_mon + 1;
        day1   = (*date).tm_mday;
        hour1  = (*date).tm_hour;
        min1   = (*date).tm_min;
        sec1   = (*date).tm_sec;
        if ((date = localtime(&when)) == NULL) return(false);
        year2  = (*date).tm_year + 1900;
        month2 = (*date).tm_mon + 1;
        day2   = (*date).tm_mday;
        hour2  = (*date).tm_hour;
        min2   = (*date).tm_min;
        sec2   = (*date).tm_sec;
        if (DateCalc_delta_ymdhms(year, month, day,  hour, min, sec,
                                  year1,month1,day1, hour1,min1,sec1,
                                  year2,month2,day2, hour2,min2,sec2))
        {
            *dst = (*date).tm_isdst;
            if (*dst != 0)
            {
                if (*dst < 0) *dst = -1;
                else          *dst =  1;
            }
            return(true);
        }
    }
    return(false);
}

/* MacOS (Classic):                                            */
/* <695056.0>     = Fri  1-Jan-1904 00:00:00 (time=0x00000000) */
/* <744766.23295> = Mon  6-Feb-2040 06:28:15 (time=0xFFFFFFFF) */

/* Unix:                                                       */
/* <719163.0>     = Thu  1-Jan-1970 00:00:00 (time=0x00000000) */
/* <744018.11647> = Tue 19-Jan-2038 03:14:07 (time=0x7FFFFFFF) */

#ifdef MACOS_TRADITIONAL
    #define DateCalc_DAYS_TO_EPOCH  695056L
    #define DateCalc_DAYS_TO_OVFLW  744766L
    #define DateCalc_SECS_TO_OVFLW   23295L
#else
    #define DateCalc_DAYS_TO_EPOCH  719163L
    #define DateCalc_DAYS_TO_OVFLW  744018L
    #define DateCalc_SECS_TO_OVFLW   11647L
#endif

/* Substitute for BSD's timegm(3) function: */

boolean DateCalc_date2time(time_t *seconds,
                           Z_int year, Z_int month, Z_int day,
                           Z_int hour, Z_int min,   Z_int sec)
{
    Z_long days;
#ifdef MACOS_TRADITIONAL
    N_long secs;
#else
    Z_long secs;
#endif

    *seconds = (time_t) 0;

    days = DateCalc_Date_to_Days(year,month,day);
    secs = (((hour * 60L) + min) * 60L) + sec;

    if (   (days <  DateCalc_DAYS_TO_EPOCH) or
#ifndef MACOS_TRADITIONAL
           (secs <  0L) or
#endif
           (days >  DateCalc_DAYS_TO_OVFLW) or
         ( (days == DateCalc_DAYS_TO_OVFLW) and (secs > DateCalc_SECS_TO_OVFLW) ) )
    return(false);

    *seconds = (time_t) (((days - DateCalc_DAYS_TO_EPOCH) * 86400L) + secs);
    return(true);
}

/* Substitute for POSIX's gmtime(3) function: */

boolean DateCalc_time2date(Z_int *year, Z_int *month, Z_int *day,
                           Z_int *hour, Z_int *min,   Z_int *sec,
                           time_t seconds)
{
#ifdef MACOS_TRADITIONAL
    N_long ss = (N_long) seconds;
    N_long mm;
    N_long hh;
    N_long dd;

    dd = (N_long) (ss / 86400L);
    ss -= dd * 86400L;
    mm = (N_long) (ss / 60L);
    ss -= mm * 60L;
    hh = (N_long) (mm / 60L);
#else
    Z_long ss = (Z_long) seconds;
    Z_long mm;
    Z_long hh;
    Z_long dd;

    if (ss < 0L) return(false);
    dd = (Z_long) (ss / 86400L);
    ss -= dd * 86400L;
    mm = (Z_long) (ss / 60L);
    ss -= mm * 60L;
    hh = (Z_long) (mm / 60L);
#endif

    mm -= hh * 60L;
    dd += (DateCalc_DAYS_TO_EPOCH-1L);
    *sec   = (Z_int) ss;
    *min   = (Z_int) mm;
    *hour  = (Z_int) hh;
    *day   = (Z_int) 1;
    *month = (Z_int) 1;
    *year  = (Z_int) 1;
    return( DateCalc_add_delta_days(year,month,day,dd) );
}

boolean DateCalc_easter_sunday(Z_int *year, Z_int *month, Z_int *day)
{
    /****************************************************************/
    /*                                                              */
    /*  Gauss'sche Regel (Gaussian Rule)                            */
    /*  ================================                            */
    /*                                                              */
    /*  Quelle / Source:                                            */
    /*                                                              */
    /*  H. H. Voigt, "Abriss der Astronomie", Wissenschaftsverlag,  */
    /*  Bibliographisches Institut, Seite 9.                        */
    /*                                                              */
    /****************************************************************/

    Z_int a, b, c, d, e, m, n;

    if ((*year < 1583) or (*year > 2299)) return(false);

    if      (*year < 1700) { m = 22; n = 2; }
    else if (*year < 1800) { m = 23; n = 3; }
    else if (*year < 1900) { m = 23; n = 4; }
    else if (*year < 2100) { m = 24; n = 5; }
    else if (*year < 2200) { m = 24; n = 6; }
    else                   { m = 25; n = 0; }

    a = *year % 19;
    b = *year % 4;
    c = *year % 7;
    d = (19 * a + m) % 30;
    e = (2 * b + 4 * c + 6 * d + n) % 7;
    *day = 22 + d + e;
    *month = 3;
    if (*day > 31)
    {
        *day -= 31; /* same as *day = d + e - 9; */
        (*month)++;
    }
    if ((*day == 26) and (*month == 4)) *day = 19;
    if ((*day == 25) and (*month == 4) and
        (d == 28) and (e == 6) and (a > 10)) *day = 18;
    return(true);
}

/*  Carnival Monday / Rosenmontag / Veille du Mardi Gras   =  easter sunday - 48  */
/*  Mardi Gras / Karnevalsdienstag / Mardi Gras            =  easter sunday - 47  */
/*  Ash Wednesday / Aschermittwoch / Mercredi des Cendres  =  easter sunday - 46  */
/*  Palm Sunday / Palmsonntag / Dimanche des Rameaux       =  easter sunday - 7   */
/*  Easter Friday / Karfreitag / Vendredi Saint            =  easter sunday - 2   */
/*  Easter Saturday / Ostersamstag / Samedi de Paques      =  easter sunday - 1   */
/*  Easter Monday / Ostermontag / Lundi de Paques          =  easter sunday + 1   */
/*  Ascension of Christ / Christi Himmelfahrt / Ascension  =  easter sunday + 39  */
/*  Whitsunday / Pfingstsonntag / Dimanche de Pentecote    =  easter sunday + 49  */
/*  Whitmonday / Pfingstmontag / Lundi de Pentecote        =  easter sunday + 50  */
/*  Feast of Corpus Christi / Fronleichnam / Fete-Dieu     =  easter sunday + 60  */

Z_int DateCalc_Decode_Month(charptr buffer, Z_int length, Z_int lang) /* 0 = error */
{
    Z_int   i,j;
    Z_int   month;
    boolean same;
    boolean ok;

/*****************************************************************************/
/*  BEWARE that the parameter "length" must always be set in such a way      */
/*  so that the string in "buffer[0]" up to "buffer[length-1]" does not      */
/*  contain any terminating null character '\0'. Otherwise this routine      */
/*  may read beyond allocated memory, probably resulting in an access        */
/*  violation and program abortion. This problem cannot arise, for example,  */
/*  if you use the library function "strlen" to determine the length         */
/*  "length" of the string in "buffer".                                      */
/*****************************************************************************/

    if ((lang < 1) or (lang > DateCalc_LANGUAGES)) lang = DateCalc_Language;
    month = 0;
    ok = true;
    for ( i = 1; ok and (i <= 12); i++ )
    {
        same = true;
        for ( j = 0; same and (j < length); j++ )
        {
            same = ( DateCalc_ISO_UC(buffer[j]) ==
                     DateCalc_ISO_UC(DateCalc_Month_to_Text_[lang][i][j]) );
        }
        if (same)
        {
            if (month > 0) ok = false;
            else           month = i;
        }
    }
    if (ok) return(month);
    else return(0);
}

Z_int DateCalc_Decode_Day_of_Week(charptr buffer, Z_int length, Z_int lang) /* 0 = error */
{
    Z_int   i,j;
    Z_int   day;
    boolean same;
    boolean ok;

/*****************************************************************************/
/*  BEWARE that the parameter "length" must always be set in such a way      */
/*  so that the string in "buffer[0]" up to "buffer[length-1]" does not      */
/*  contain any terminating null character '\0'. Otherwise this routine      */
/*  may read beyond allocated memory, probably resulting in an access        */
/*  violation and program abortion. This problem cannot arise, for example,  */
/*  if you use the library function "strlen" to determine the length         */
/*  "length" of the string in "buffer".                                      */
/*****************************************************************************/

    if ((lang < 1) or (lang > DateCalc_LANGUAGES)) lang = DateCalc_Language;
    day = 0;
    ok = true;
    for ( i = 1; ok and (i <= 7); i++ )
    {
        same = true;
        for ( j = 0; same and (j < length); j++ )
        {
            same = ( DateCalc_ISO_UC(buffer[j]) ==
                     DateCalc_ISO_UC(DateCalc_Day_of_Week_to_Text_[lang][i][j]) );
        }
        if (same)
        {
            if (day > 0) ok = false;
            else         day = i;
        }
    }
    if (ok) return(day);
    else return(0);
}

Z_int DateCalc_Decode_Language(charptr buffer, Z_int length) /* 0 = error */
{
    Z_int   i,j;
    Z_int   lang;
    boolean same;
    boolean ok;

/*****************************************************************************/
/*  BEWARE that the parameter "length" must always be set in such a way      */
/*  so that the string in "buffer[0]" up to "buffer[length-1]" does not      */
/*  contain any terminating null character '\0'. Otherwise this routine      */
/*  may read beyond allocated memory, probably resulting in an access        */
/*  violation and program abortion. This problem cannot arise, for example,  */
/*  if you use the library function "strlen" to determine the length         */
/*  "length" of the string in "buffer".                                      */
/*****************************************************************************/

    lang = 0;
    ok = true;
    for ( i = 1; ok and (i <= DateCalc_LANGUAGES); i++ )
    {
        same = true;
        for ( j = 0; same and (j < length); j++ )
        {
            same = ( DateCalc_ISO_UC(buffer[j]) ==
                     DateCalc_ISO_UC(DateCalc_Language_to_Text_[i][j]) );
        }
        if (same)
        {
            if (lang > 0) ok = false;
            else          lang = i;
        }
    }
    if (ok) return(lang);
    else return(0);
}

boolean DateCalc_decode_date_eu(charptr buffer,
                                Z_int *year, Z_int *month, Z_int *day, Z_int lang)
{
    Z_int i,j;
    Z_int length;

    if ((lang < 1) or (lang > DateCalc_LANGUAGES)) lang = DateCalc_Language;
    *year = *month = *day = 0;
    length = strlen((char *)buffer);
    if (length > 0)
    {
        i = 0;
        while (DateCalc_scan9(buffer,length,i,true)) i++;
        j = length-1;
        while (DateCalc_scan9(buffer,length,j,true)) j--;
        if (i+1 < j)        /* at least 3 chars, else error! */
        {
            buffer += i;
            length = j-i+1;
            i = 1;
            while (DateCalc_scan9(buffer,length,i,false)) i++;
            j = length-2;
            while (DateCalc_scan9(buffer,length,j,false)) j--;
            if (j < i)  /* only numerical chars without delimiters */
            {
                switch (length)
                {
                case 3:
                    *day   = DateCalc_Str2Int(buffer,  1);
                    *month = DateCalc_Str2Int(buffer+1,1);
                    *year  = DateCalc_Str2Int(buffer+2,1);
                    break;
                case 4:
                    *day   = DateCalc_Str2Int(buffer,  1);
                    *month = DateCalc_Str2Int(buffer+1,1);
                    *year  = DateCalc_Str2Int(buffer+2,2);
                    break;
                case 5:
                    *day   = DateCalc_Str2Int(buffer,  1);
                    *month = DateCalc_Str2Int(buffer+1,2);
                    *year  = DateCalc_Str2Int(buffer+3,2);
                    break;
                case 6:
                    *day   = DateCalc_Str2Int(buffer,  2);
                    *month = DateCalc_Str2Int(buffer+2,2);
                    *year  = DateCalc_Str2Int(buffer+4,2);
                    break;
                case 7:
                    *day   = DateCalc_Str2Int(buffer,  1);
                    *month = DateCalc_Str2Int(buffer+1,2);
                    *year  = DateCalc_Str2Int(buffer+3,4);
                    break;
                case 8:
                    *day   = DateCalc_Str2Int(buffer,  2);
                    *month = DateCalc_Str2Int(buffer+2,2);
                    *year  = DateCalc_Str2Int(buffer+4,4);
                    break;
                default:
                    return(false);
                    break;
                }
            }
            else        /* at least one non-numerical char (i <= j) */
            {
                *day  = DateCalc_Str2Int(buffer,i);
                *year = DateCalc_Str2Int(buffer+(j+1),length-(j+1));
                while (DateCalc_scanx(buffer,length,i,true)) i++;
                while (DateCalc_scanx(buffer,length,j,true)) j--;
                if (i <= j)         /* at least one char left for month */
                {
                    buffer += i;
                    length = j-i+1;
                    i = 1;
                    while (DateCalc_scanx(buffer,length,i,false)) i++;
                    if (i >= length)    /* ok, no more delimiters */
                    {
                        i = 0;
                        while (DateCalc_scan9(buffer,length,i,false)) i++;
                        if (i >= length) /* only digits for month */
                        {
                            *month = DateCalc_Str2Int(buffer,length);
                        }
                        else             /* match with month names */
                        {
                            *month = DateCalc_Decode_Month(buffer,length,lang);
                        }
                    }
                    else return(false); /* delimiters inside month string */
                }
                else return(false); /* no chars left for month */
            }           /* at least one non-numerical char (i <= j) */
        }
        else return(false); /* less than 3 chars in buffer */
    }
    else return(false); /* length <= 0 */
    *year = DateCalc_Moving_Window(*year);
    return( DateCalc_check_date(*year,*month,*day) );
}

boolean DateCalc_decode_date_us(charptr buffer,
                                Z_int *year, Z_int *month, Z_int *day, Z_int lang)
{
    Z_int i,j,k;
    Z_int length;

    if ((lang < 1) or (lang > DateCalc_LANGUAGES)) lang = DateCalc_Language;
    *year = *month = *day = 0;
    length = strlen((char *)buffer);
    if (length > 0)
    {
        i = 0;
        while (DateCalc_scanx(buffer,length,i,true)) i++;
        j = length-1;
        while (DateCalc_scan9(buffer,length,j,true)) j--;
        if (i+1 < j)        /* at least 3 chars, else error! */
        {
            buffer += i;
            length = j-i+1;
            i = 1;
            while (DateCalc_scanx(buffer,length,i,false)) i++;
            j = length-2;
            while (DateCalc_scan9(buffer,length,j,false)) j--;
            if (i >= length)  /* only alphanumeric chars left */
            {
                if (j < 0) /* case 0 : xxxx999999xxxx */
                {          /*             j0     i    */
                    switch (length)
                    {
                    case 3:
                        *month = DateCalc_Str2Int(buffer,  1);
                        *day   = DateCalc_Str2Int(buffer+1,1);
                        *year  = DateCalc_Str2Int(buffer+2,1);
                        break;
                    case 4:
                        *month = DateCalc_Str2Int(buffer,  1);
                        *day   = DateCalc_Str2Int(buffer+1,1);
                        *year  = DateCalc_Str2Int(buffer+2,2);
                        break;
                    case 5:
                        *month = DateCalc_Str2Int(buffer,  1);
                        *day   = DateCalc_Str2Int(buffer+1,2);
                        *year  = DateCalc_Str2Int(buffer+3,2);
                        break;
                    case 6:
                        *month = DateCalc_Str2Int(buffer,  2);
                        *day   = DateCalc_Str2Int(buffer+2,2);
                        *year  = DateCalc_Str2Int(buffer+4,2);
                        break;
                    case 7:
                        *month = DateCalc_Str2Int(buffer,  1);
                        *day   = DateCalc_Str2Int(buffer+1,2);
                        *year  = DateCalc_Str2Int(buffer+3,4);
                        break;
                    case 8:
                        *month = DateCalc_Str2Int(buffer,  2);
                        *day   = DateCalc_Str2Int(buffer+2,2);
                        *year  = DateCalc_Str2Int(buffer+4,4);
                        break;
                    default:
                        return(false);
                        break;
                    }
                }
                else       /* case 1 : xxxxAAA999999xxxx */
                {          /*              0 j      i    */
                    *month = DateCalc_Decode_Month(buffer,j+1,lang);
                    buffer += j+1;
                    length -= j+1;
                    switch (length)
                    {
                    case 2:
                        *day  = DateCalc_Str2Int(buffer,  1);
                        *year = DateCalc_Str2Int(buffer+1,1);
                        break;
                    case 3:
                        *day  = DateCalc_Str2Int(buffer,  1);
                        *year = DateCalc_Str2Int(buffer+1,2);
                        break;
                    case 4:
                        *day  = DateCalc_Str2Int(buffer,  2);
                        *year = DateCalc_Str2Int(buffer+2,2);
                        break;
                    case 5:
                        *day  = DateCalc_Str2Int(buffer,  1);
                        *year = DateCalc_Str2Int(buffer+1,4);
                        break;
                    case 6:
                        *day  = DateCalc_Str2Int(buffer,  2);
                        *year = DateCalc_Str2Int(buffer+2,4);
                        break;
                    default:
                        return(false);
                        break;
                    }
                }
            }              /*              0  i  j    l         */
            else           /* case 2 : xxxxAAAxxxx9999xxxx _OR_ */
            {              /* case 3 : xxxxAAAxx99xx9999xx      */
                k = 0;     /*              0  i    j    l       */
                while (DateCalc_scan9(buffer,length,k,false)) k++;
                if (k >= i) /* ok, only digits */
                {
                    *month = DateCalc_Str2Int(buffer,i);
                }
                else       /* no, some non-digits */
                {
                    *month = DateCalc_Decode_Month(buffer,i,lang);
                    if (*month == 0) return(false);
                }
                buffer += i;
                length -= i;
                j -= i;
                k = j+1; /* remember start posn of day+year(2)/year(3) */
                i = 1;
                while (DateCalc_scanx(buffer,length,i,true)) i++;
                j--;
                while (DateCalc_scan9(buffer,length,j,true)) j--;
                if (j < i) /* case 2 : xxxxAAAxxxx9999xxxx */
                {          /*                j0   i   l    */
                    buffer += k;    /*            k        */
                    length -= k;
                    switch (length)
                    {
                    case 2:
                        *day  = DateCalc_Str2Int(buffer,  1);
                        *year = DateCalc_Str2Int(buffer+1,1);
                        break;
                    case 3:
                        *day  = DateCalc_Str2Int(buffer,  1);
                        *year = DateCalc_Str2Int(buffer+1,2);
                        break;
                    case 4:
                        *day  = DateCalc_Str2Int(buffer,  2);
                        *year = DateCalc_Str2Int(buffer+2,2);
                        break;
                    case 5:
                        *day  = DateCalc_Str2Int(buffer,  1);
                        *year = DateCalc_Str2Int(buffer+1,4);
                        break;
                    case 6:
                        *day  = DateCalc_Str2Int(buffer,  2);
                        *year = DateCalc_Str2Int(buffer+2,4);
                        break;
                    default:
                        return(false);
                        break;
                    }
                }
                else       /* case 3 : xxxxAAAxx99xx9999xx */
                {          /*                 0 ij  k   l  */
                    *year = DateCalc_Str2Int(buffer+k,length-k);
                    k = i;
                    while (DateCalc_scan9(buffer,length,k,false)) k++;
                    if (k > j)          /* ok, only digits */
                    {
                        *day = DateCalc_Str2Int(buffer+i,j-i+1);
                    }
                    else return(false); /* non-digits inside day */
                }
            }                 /* i < length */
        }
        else return(false); /* less than 3 chars in buffer */
    }
    else return(false); /* length <= 0 */
    *year = DateCalc_Moving_Window(*year);
    return( DateCalc_check_date(*year,*month,*day) );
}

Z_int DateCalc_Fixed_Window(Z_int year)
{
    if (year < 0) return(0);
    if (year < 100)
    {
        if (year < DateCalc_YEAR_OF_EPOCH) year += 100;
        year += DateCalc_CENTURY_OF_EPOCH;
    }
    return(year);
}

Z_int DateCalc_Moving_Window(Z_int year)
{
    time_t seconds;
    struct tm *date;
    Z_int  current;
    Z_int  century;

    if (year < 0) return(0);
    if (year < 100)
    {
        if ((time(&seconds) >= 0) and ((date = gmtime(&seconds)) != NULL))
        {
            current = (*date).tm_year + 1900;
            century = (Z_int)(current / 100);
            year += century * 100;
            if      (year <  current - 50) year += 100;
            else if (year >= current + 50) year -= 100;
        }
        else year = DateCalc_Fixed_Window(year);
    }
    return(year);
}

Z_int DateCalc_Compress(Z_int year, Z_int month, Z_int day)
{
    Z_int yy;

    if ((year >= DateCalc_EPOCH) and (year < (DateCalc_EPOCH + 100)))
    {
        yy = year;
        year -= DateCalc_EPOCH;
    }
    else
    {
        if ((year < 0) or (year > 99)) return(0);
        if (year < DateCalc_YEAR_OF_EPOCH)
        {
            yy = DateCalc_CENTURY_OF_EPOCH + 100 + year;
            year += 100 - DateCalc_YEAR_OF_EPOCH;
        }
        else
        {
            yy = DateCalc_CENTURY_OF_EPOCH + year;
            year -= DateCalc_YEAR_OF_EPOCH;
        }
    }
    if ((month < 1) or (month > 12)) return(0);
    if ((day < 1) or
        (day > DateCalc_Days_in_Month_[DateCalc_leap_year(yy)][month]))
        return(0);
    return( (year SHL 9) OR (month SHL 5) OR day );
}

boolean
DateCalc_uncompress(Z_int date,
                    Z_int *century, Z_int *year, Z_int *month, Z_int *day)
{
    if (date > 0)
    {
        *year  =  date SHR 9;
        *month = (date AND 0x01FF) SHR 5;
        *day   =  date AND 0x001F;

        if (*year < 100)
        {
            if (*year < 100-DateCalc_YEAR_OF_EPOCH)
            {
                *century = DateCalc_CENTURY_OF_EPOCH;
                *year += DateCalc_YEAR_OF_EPOCH;
            }
            else
            {
                *century = DateCalc_CENTURY_OF_EPOCH+100;
                *year -= 100-DateCalc_YEAR_OF_EPOCH;
            }
            return( DateCalc_check_date(*century+*year,*month,*day) );
        }
    }
    return(false);
}

boolean DateCalc_check_compressed(Z_int date)
{
    Z_int century;
    Z_int year;
    Z_int month;
    Z_int day;

    return( DateCalc_uncompress(date,&century,&year,&month,&day) );
}

charptr DateCalc_Compressed_to_Text(Z_int date, Z_int lang)
{
    Z_int   century;
    Z_int   year;
    Z_int   month;
    Z_int   day;
    charptr string;

    if ((lang < 1) or (lang > DateCalc_LANGUAGES)) lang = DateCalc_Language;
    string = (charptr) malloc(16);
    if (string == NULL) return(NULL);
    if (DateCalc_uncompress(date,&century,&year,&month,&day))
        sprintf((char *)string,"%02d-%.3s-%02d",day,
        DateCalc_Month_to_Text_[lang][month],year);
    else
        sprintf((char *)string,"??""-???""-??");
        /* prevent interpretation as trigraphs */
    return(string);
}

charptr DateCalc_Date_to_Text(Z_int year, Z_int month, Z_int day, Z_int lang)
{
    charptr string;

    if ((lang < 1) or (lang > DateCalc_LANGUAGES)) lang = DateCalc_Language;
    if (DateCalc_check_date(year,month,day) and
        ((string = (charptr) malloc(32)) != NULL))
    {
        if (DateCalc_Day_of_Week_Abbreviation_[lang][0][0] != '\0')
        {
            sprintf((char *)string,"%.3s %d-%.3s-%d",
                DateCalc_Day_of_Week_Abbreviation_[lang][DateCalc_Day_of_Week(year,month,day)],
                day,DateCalc_Month_to_Text_[lang][month],year);
            return(string);
        }
        else
        {
            sprintf((char *)string,"%.3s %d-%.3s-%d",
                DateCalc_Day_of_Week_to_Text_[lang][DateCalc_Day_of_Week(year,month,day)],
                day,DateCalc_Month_to_Text_[lang][month],year);
            return(string);
        }
    }
    return(NULL);
}

charptr DateCalc_English_Ordinal(charptr result, Z_int number)
{
    N_int length;
    N_int digit;

    sprintf((char *)result, "%d", number);
    if ((length = strlen((char *)result)))
    {
        if ( not
             (
               ( ((length > 1) and (result[length-2] != '1')) or (length == 1) )
               and
               ( (digit = (N_int)(result[length-1] XOR '0')) <= 3 )
             )
           )
        {
            digit = 0;
        }
        sprintf( (char *)(result+length), "%s",
            DateCalc_English_Ordinals_[digit] );
    }
    return(result);
}

charptr DateCalc_Date_to_Text_Long(Z_int year, Z_int month, Z_int day, Z_int lang)
{
    charptr string;
    blockdef(buffer,64);

    if ((lang < 1) or (lang > DateCalc_LANGUAGES)) lang = DateCalc_Language;
    if (DateCalc_check_date(year,month,day) and
        ((string = (charptr) malloc(64)) != NULL))
    {
        switch (lang)
        {
            case 1:
                sprintf(
                    (char *)string,
                    (char *)DateCalc_Date_Long_Format_[lang],
                    DateCalc_Day_of_Week_to_Text_[lang]
                        [DateCalc_Day_of_Week(year,month,day)],
                    DateCalc_Month_to_Text_[lang][month],
                    DateCalc_English_Ordinal(buffer,day),
                    year );
                break;
            case 12:
                sprintf(
                    (char *)string,
                    (char *)DateCalc_Date_Long_Format_[lang],
                    year,
                    DateCalc_Month_to_Text_[lang][month],
                    day,
                    DateCalc_Day_of_Week_to_Text_[lang]
                        [DateCalc_Day_of_Week(year,month,day)] );
                break;
            default:
                sprintf(
                    (char *)string,
                    (char *)DateCalc_Date_Long_Format_[lang],
                    DateCalc_Day_of_Week_to_Text_[lang]
                        [DateCalc_Day_of_Week(year,month,day)],
                    day,
                    DateCalc_Month_to_Text_[lang][month],
                    year );
                break;
        }
        return(string);
    }
    return(NULL);
}

charptr DateCalc_Calendar(Z_int year, Z_int month, boolean orthodox, Z_int lang)
{
    blockdef(buffer,64);
    charptr string;
    charptr cursor;
    Z_int first;
    Z_int last;
    Z_int day;

    if ((lang < 1) or (lang > DateCalc_LANGUAGES)) lang = DateCalc_Language;
    string = (charptr) malloc(256);
    if (string == NULL) return(NULL);
    cursor = string;
    DateCalc_Newline(&cursor,1);
    sprintf((char *)buffer,"%s %d",
        DateCalc_Month_to_Text_[lang][month],year);
    *buffer = DateCalc_ISO_UC(*buffer);
    DateCalc_Center(&cursor,buffer,27);
    if (DateCalc_Day_of_Week_Abbreviation_[lang][0][0] != '\0')
    {
        if (orthodox)
            sprintf((char *)cursor,"%3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s\n",
                DateCalc_Day_of_Week_Abbreviation_[lang][7],
                DateCalc_Day_of_Week_Abbreviation_[lang][1],
                DateCalc_Day_of_Week_Abbreviation_[lang][2],
                DateCalc_Day_of_Week_Abbreviation_[lang][3],
                DateCalc_Day_of_Week_Abbreviation_[lang][4],
                DateCalc_Day_of_Week_Abbreviation_[lang][5],
                DateCalc_Day_of_Week_Abbreviation_[lang][6]);
        else /* conform to ISO standard */
            sprintf((char *)cursor,"%3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s\n",
                DateCalc_Day_of_Week_Abbreviation_[lang][1],
                DateCalc_Day_of_Week_Abbreviation_[lang][2],
                DateCalc_Day_of_Week_Abbreviation_[lang][3],
                DateCalc_Day_of_Week_Abbreviation_[lang][4],
                DateCalc_Day_of_Week_Abbreviation_[lang][5],
                DateCalc_Day_of_Week_Abbreviation_[lang][6],
                DateCalc_Day_of_Week_Abbreviation_[lang][7]);
    }
    else
    {
        if (orthodox)
            sprintf((char *)cursor,"%3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s\n",
                DateCalc_Day_of_Week_to_Text_[lang][7],
                DateCalc_Day_of_Week_to_Text_[lang][1],
                DateCalc_Day_of_Week_to_Text_[lang][2],
                DateCalc_Day_of_Week_to_Text_[lang][3],
                DateCalc_Day_of_Week_to_Text_[lang][4],
                DateCalc_Day_of_Week_to_Text_[lang][5],
                DateCalc_Day_of_Week_to_Text_[lang][6]);
        else /* conform to ISO standard */
            sprintf((char *)cursor,"%3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s\n",
                DateCalc_Day_of_Week_to_Text_[lang][1],
                DateCalc_Day_of_Week_to_Text_[lang][2],
                DateCalc_Day_of_Week_to_Text_[lang][3],
                DateCalc_Day_of_Week_to_Text_[lang][4],
                DateCalc_Day_of_Week_to_Text_[lang][5],
                DateCalc_Day_of_Week_to_Text_[lang][6],
                DateCalc_Day_of_Week_to_Text_[lang][7]);
    }
    cursor += 28;
    first = DateCalc_Day_of_Week(year,month,1);
    last = DateCalc_Days_in_Month_[DateCalc_leap_year(year)][month];
    if (orthodox) { if (first == 7) first = 0; }
    else          { first--; }
    if (first) DateCalc_Blank(&cursor,(first<<2)-1);
    for ( day = 1; day <= last; day++, first++ )
    {
        if (first > 0)
        {
            if (first > 6)
            {
                first = 0;
                DateCalc_Newline(&cursor,1);
            }
            else DateCalc_Blank(&cursor,1);
        }
        sprintf((char *)cursor," %2d",day);
        cursor += 3;
    }
    DateCalc_Newline(&cursor,2);
    return(string);
}

void DateCalc_Dispose(charptr string)
{
    free((voidptr) string);
}

charptr DateCalc_Version(void)
{
    return( (charptr) "6.2" );
}

/*****************************************************************************/
/*  VERSION:  6.2                                                            */
/*****************************************************************************/
/*  VERSION HISTORY:                                                         */
/*****************************************************************************/
/*                                                                           */
/*    Version 6.1  15.10.09  Fixed Polish language entries.                  */
/*    Version 6.0  07.10.09  +: norm_delta_ymdhms, add_norm_delta_ymd[hms].  */
/*    Version 5.8  12.09.09  Added "norm_delta_ymd()".                       */
/*    Version 5.7  23.08.09  Fixed Dutch "oktober", Portuguese DOW abbrevs.  */
/*    Version 5.6  28.07.09  Made the module MacOS X compatible.             */
/*    Version 5.5  skipped due to an unauthorized upload by someone else.    */
/*    Version 5.4  03.10.04  Added compiler directives for C++.              */
/*    Version 5.3  29.09.02  No changes.                                     */
/*    Version 5.2  18.09.02  No changes.                                     */
/*    Version 5.1  08.09.02  Added conditional changes for MacOS/MacPerl.    */
/*    Version 5.0  10.10.01  New YMD/HMS functions, replaced <ctype.h>, ...  */
/*    Version 4.3  08.01.00  decode_date_??: (yy < 70 ? 20yy : 19yy)         */
/*    Version 4.2  07.09.98  No changes.                                     */
/*    Version 4.1  08.06.98  Fixed bug in "add_delta_ymd()".                 */
/*    Version 4.0  12.05.98  Major rework. Added multi-language support.     */
/*    Version 3.2  15.06.97  Added "week_of_year()".                         */
/*    Version 3.1  12.06.97  No significant changes.                         */
/*    Version 3.0  16.02.97  Changed conventions for unsuccessful returns.   */
/*    Version 2.3  22.11.96  Fixed unbalanced "malloc" and "free".           */
/*    Version 2.2  26.05.96  No significant changes.                         */
/*    Version 2.1  26.05.96  Fixed HH MM SS parameter checks.                */
/*    Version 2.0  25.05.96  Added time calculations. Major rework.          */
/*    Version 1.6  20.04.96  Not published.                                  */
/*    Version 1.5  14.03.96  No significant changes.                         */
/*    Version 1.4  11.02.96  No significant changes.                         */
/*    Version 1.3  10.12.95  Added "days_in_month()".                        */
/*    Version 1.2b 27.11.95  No significant changes.                         */
/*    Version 1.2a 21.11.95  Fix for type name clashes.                      */
/*    Version 1.1  18.11.95  Fix for type name clashes.                      */
/*    Version 1.01 16.11.95  Improved compliance w/ programming standards.   */
/*    Version 1.0  14.11.95  First version under UNIX (with Perl module).    */
/*    Version 0.9  01.11.93  First version of C library under MS-DOS.        */
/*                                                                           */
/*****************************************************************************/
/*  AUTHOR:                                                                  */
/*****************************************************************************/
/*                                                                           */
/*    Steffen Beyer                                                          */
/*    mailto:STBEY@cpan.org                                                  */
/*    http://www.engelschall.com/u/sb/download/                              */
/*                                                                           */
/*****************************************************************************/
/*  COPYRIGHT:                                                               */
/*****************************************************************************/
/*                                                                           */
/*    Copyright (c) 1993 - 2009 by Steffen Beyer.                            */
/*    All rights reserved.                                                   */
/*                                                                           */
/*****************************************************************************/
/*  LICENSE:                                                                 */
/*****************************************************************************/
/*                                                                           */
/*    This library is free software; you can redistribute it and/or          */
/*    modify it under the terms of the GNU Library General Public            */
/*    License as published by the Free Software Foundation; either           */
/*    version 2 of the License, or (at your option) any later version.       */
/*                                                                           */
/*    This library 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       */
/*    Library General Public License for more details.                       */
/*                                                                           */
/*    You should have received a copy of the GNU Library General Public      */
/*    License along with this library; if not, write to the                  */
/*    Free Software Foundation, Inc.,                                        */
/*    59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                  */
/*    or download a copy from ftp://ftp.gnu.org/pub/gnu/COPYING.LIB-2.0      */
/*                                                                           */
/*****************************************************************************/
#endif
