1 /*
2    Hebcal - A Jewish Calendar Generator
3    Copyright (C) 1994-2004  Danny Sadinoff
4    Portions Copyright (c) 2002 Michael J. Radwin. All Rights Reserved.
5 
6    https://github.com/hebcal/hebcal
7 
8    This program is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public License
10    as published by the Free Software Foundation; either version 2
11    of the License, or (at your option) any later version.
12 
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 
22    Danny Sadinoff can be reached at
23    danny@sadinoff.com
24  */
25 
26 
27 #include <stdio.h>
28 #include "danlib.h"
29 #include <time.h>
30 #include <string.h>
31 #include "myerror.h"
32 #include "greg.h"
33 
34 /* greg.c gregorian calendar module for hebrew calendar program
35    By Danny Sadinoff
36    (C) 1992
37 
38  */
39 
40 const char *eMonths[] =
41 {
42     "UNUSED",
43     "January", "February", "March", "April", "May", "June", "July",
44     "August", "September", "October", "November", "December"
45 };
46 
47 int MonthLengths[][13] =
48 {
49     {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
50     {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
51 };
52 
53 const char *ShortDayNames[] =
54 {
55     "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
56 };
57 
58 
59 /*
60  *Return the day number within the year of the date DATE.
61  *For example, dayOfYear({1,1,1987}) returns the value 1
62  *while dayOfYear({12,31,1980}) returns 366.
63  */
64 
65 
dayOfYear(date_t d)66 int dayOfYear( date_t d )
67 {
68     int dOY = d.dd + 31 * (d.mm - 1);
69     if (d.mm > FEB)
70     {
71         dOY -= (4 * d.mm + 23) / 10;
72         if (LEAP (d.yy))
73             dOY++;
74     }
75     return dOY;
76 }
77 
78 
79 /*
80  * The number of days elapsed between the Gregorian date 12/31/1 BC and DATE.
81  * The Gregorian date Sunday, December 31, 1 BC is imaginary.
82  */
greg2abs(date_t d)83 long int greg2abs( date_t d )			/* "absolute date" */
84 {
85     return ((long) dayOfYear (d)	/* days this year */
86             + 365L * (long) (d.yy - 1)	/* + days in prior years */
87             + (long) ((d.yy - 1) / 4	/* + Julian Leap years */
88                       - (d.yy - 1) / 100	/* - century years */
89                       + (d.yy - 1) / 400));	/* + Gregorian leap years */
90 }
91 
92 /*
93  * See the footnote on page 384 of ``Calendrical Calculations, Part II:
94  * Three Historical Calendars'' by E. M. Reingold,  N. Dershowitz, and S. M.
95  * Clamen, Software--Practice and Experience, Volume 23, Number 4
96  * (April, 1993), pages 383-404 for an explanation.
97  */
abs2greg(long theDate)98 date_t abs2greg( long theDate )
99 {
100   int day, year, month, mlen;
101   date_t d;
102   long int d0, n400, d1, n100, d2, n4, d3, n1;
103 
104   d0 = theDate - 1L;
105   n400 = d0 / 146097L;
106   d1 = d0 % 146097L;
107   n100 = d1 / 36524L;
108   d2 = d1 % 36524L;
109   n4 = d2 / 1461L;
110   d3 = d2 % 1461L;
111   n1 = d3 / 365L;
112 
113   day = (int) ((d3 % 365L) + 1L);
114   year = (int) (400L * n400 + 100L * n100 + 4L * n4 + n1);
115 
116   if (4L == n100 || 4L == n1)
117     {
118       d.mm = 12;
119       d.dd = 31;
120       d.yy = year;
121       return d;
122     }
123   else
124     {
125       year++;
126       month = 1;
127       while ((mlen = MonthLengths[LEAP (year)][month]) < day)
128 	{
129 	  day -= mlen;
130 	  month++;
131 	}
132       d.yy = year;
133       d.mm = month;
134       d.dd = day;
135       return d;
136     }
137 }
138 
incDate(date_t * dt,long n)139 void incDate (date_t *dt, long n)			/* increments dt by n days */
140 {
141   *dt = abs2greg (greg2abs (*dt) + n);
142 }
143 
144 
dayOfWeek(date_t d1)145 int dayOfWeek(date_t d1)			/* sunday = 0 */
146 {
147   return (int) (greg2abs (d1) % 7L);
148 }
149 
setDate(date_t * d)150 void setDate ( date_t *d )
151 {
152 /*
153    asctime() converts a time value contained in a tm  structure
154    to a 26-character string of the form:
155    Sun Sep 16 01:03:52 1973\n\0
156    Each field  has  a  constant  width.   asctime()  returns  a
157    pointer to the string.
158  */
159 
160 /*
161 FIX: removing these decls, but need to start doing compilation platofrm checks to ensure that these aren't necessary.
162 time_t time ();
163     char *ctime( const time_t * );
164 */
165     time_t secs = time (NULL);
166     char *timestr = ctime (&secs);
167 
168 /* portability has driven me to truly shameful code.
169    please forgive this.
170  */
171     sscanf (timestr + 20, "%d", &d->yy);
172     d->mm = lookup_string( timestr + 4, eMonths, 13, 3 );
173     sscanf (timestr + 8, "%d", &d->dd);
174 }
175 
176 
177 /** Returns the absolute date of the DAYNAME on or before absolute DATE.
178  * DAYNAME=0 means Sunday, DAYNAME=1 means Monday, and so on.
179 
180 
181  * Note: Applying this function to d+6 gives us the DAYNAME on or after an
182  * absolute day d.  Similarly, applying it to d+3 gives the DAYNAME nearest to
183  * absolute date d, applying it to d-1 gives the DAYNAME previous to absolute
184  * date d, and applying it to d+7 gives the DAYNAME following absolute date d.
185 
186 **/
day_on_or_before(int day_of_week,long date)187 long day_on_or_before( int day_of_week, long date)
188 {
189   return date - ((date - (long) day_of_week) % 7L);
190 }
191 
192 
193 
194 /** (defun calendar-nth-named-day (n dayname month year &optional day)
195    "The date of Nth DAYNAME in MONTH, YEAR before/after optional DAY.
196    A DAYNAME of 0 means Sunday, 1 means Monday, and so on.  If N<0,
197    return the Nth DAYNAME before MONTH DAY, YEAR (inclusive).
198    If N>0, return the Nth DAYNAME after MONTH DAY, YEAR (inclusive).
199 
200    If DAY is omitted, it defaults to 1 if N>0, and MONTH's last day otherwise.
201    (calendar-gregorian-from-absolute
202    (if (> n 0)
203    (+ (* 7 (1- n))
204    (calendar-dayname-on-or-before
205    dayname
206    (+ 6 (calendar-absolute-from-gregorian
207    (list month (or day 1) year)))))
208    (+ (* 7 (1+ n))
209    (calendar-dayname-on-or-before
210    dayname
211    (calendar-absolute-from-gregorian
212    (list month
213    (or day (calendar-last-day-of-month month year))
214    year)))))))
215  */
216