calendar.c 7.03 KB
Newer Older
1
#include <limits.h>
Uwe Schulzweida's avatar
Uwe Schulzweida committed
2

3
#include "cdi.h"  		/* CALENDAR_ */
4
#include "calendar.h"
5
#include "error.h"
6
#include "timebase.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
7
8


9
10
11
static const int month_360[12] = {30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30};
static const int month_365[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
static const int month_366[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
Uwe Schulzweida's avatar
Uwe Schulzweida committed
12
13


14
15
int calendar_dpy(int calendar)
{
16
  int daysperyear = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
17

18
19
20
  if      ( calendar == CALENDAR_360DAYS ) daysperyear = 360;
  else if ( calendar == CALENDAR_365DAYS ) daysperyear = 365;
  else if ( calendar == CALENDAR_366DAYS ) daysperyear = 366;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
21

22
  return daysperyear;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
23
24
25
}


26
int days_per_month(int calendar, int year, int month)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
27
{
28
  int daysperyear = calendar_dpy(calendar);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
29

30
31
32
33
34
35
  const int *dpm = (daysperyear == 360) ? month_360 : ((daysperyear == 365) ? month_365 : month_366);

  int dayspermonth = ( month >= 1 && month <= 12 ) ? dpm[month-1] : 0;

  if (daysperyear == 0 && month == 2)
    dayspermonth = ((year%4 == 0 && year%100 != 0) || year%400 == 0) ? 29 : 28;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
36

37
  return dayspermonth;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
38
39
40
}


41
int days_per_year(int calendar, int year)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
42
{
43
  int daysperyear = calendar_dpy(calendar);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
44

45
  if (daysperyear == 0)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
46
    {
47
      if (year == 1582 && (calendar == CALENDAR_STANDARD || calendar == CALENDAR_GREGORIAN))
Uwe Schulzweida's avatar
Uwe Schulzweida committed
48
        daysperyear = 355;
49
      else if ((year%4 == 0 && year%100 != 0) || year%400 == 0)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
50
        daysperyear = 366;
51
      else
Uwe Schulzweida's avatar
Uwe Schulzweida committed
52
        daysperyear = 365;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
53
54
    }

55
  return daysperyear;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
56
57
58
}


59
static void decode_day(int dpy, int days, int *year, int *month, int *day)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
60
{
61
62
  *year = (days-1) / dpy;
  days -= (*year*dpy);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
63

64
  const int *dpm = NULL;
65
66
67
  if      ( dpy == 360 ) dpm = month_360;
  else if ( dpy == 365 ) dpm = month_365;
  else if ( dpy == 366 ) dpm = month_366;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
68

69
  int i = 0;
70
71
72
73
74
75
  if ( dpm )
    for ( i = 0; i < 12; i++ )
      {
	if ( days > dpm[i] ) days -= dpm[i];
	else break;
      }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
76

77
78
  *month = i + 1;
  *day   = days;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
79
80
81
}


82
static int64_t encode_day(int dpy, int year, int month, int day)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
83
{
84
  int64_t rval = (int64_t)dpy * year + day;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
85

86
  const int *dpm = NULL;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
87
88
89
  if      ( dpy == 360 ) dpm = month_360;
  else if ( dpy == 365 ) dpm = month_365;
  else if ( dpy == 366 ) dpm = month_366;
90

91
  if ( dpm ) for ( int i = 0; i < month-1; i++ ) rval += dpm[i];
92
  if ( rval > LONG_MAX || rval < LONG_MIN ) Error("Unhandled date: %lld", rval);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
93

94
  return rval;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
95
96
97
}


98
void encode_caldaysec(int calendar, int year, int month, int day, int hour, int minute, int second,
99
		      int64_t *julday, int *secofday)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
100
{
101
  const int dpy = calendar_dpy(calendar);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
102

103
  if ( dpy == 360 || dpy == 365 || dpy == 366 )
104
    *julday = encode_day(dpy, year, month, day);
105
  else
106
    *julday = encode_julday(calendar, year, month, day);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
107

108
  *secofday = hour*3600 + minute*60 + second;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
109
110
111
}


112
void decode_caldaysec(int calendar, int64_t julday, int secofday,
113
		      int *year, int *month, int *day, int *hour, int *minute, int *second)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
114
{
115
  const int dpy = calendar_dpy(calendar);
116
117

  if ( dpy == 360 || dpy == 365 || dpy == 366 )
118
    decode_day(dpy, julday, year, month, day);
119
  else
120
    decode_julday(calendar, julday, year, month, day);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
121

122
123
124
  *hour   = secofday/3600;
  *minute = secofday/60 - *hour*60;
  *second = secofday - *hour*3600 - *minute*60;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
125
126
127
}


128
129
#ifdef TEST
static int date_to_calday(int calendar, int date)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
130
{
131
  const int dpy = calendar_dpy(calendar);
132

133
  int year, month, day;
134
135
  cdiDecodeDate(date, &year, &month, &day);

136
  int calday;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
137
  if ( dpy == 360 || dpy == 365 || dpy == 366 )
138
    calday = encode_day(dpy, year, month, day);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
139
  else
140
    calday = encode_julday(calendar, year, month, day);
141

142
  return calday;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
143
144
145
}


146
static int calday_to_date(int calendar, int calday)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
147
{
148
  int year, month, day;
149
  const int dpy = calendar_dpy(calendar);
150

Uwe Schulzweida's avatar
Uwe Schulzweida committed
151
  if ( dpy == 360 || dpy == 365 || dpy == 366 )
152
    decode_day(dpy, calday, &year, &month, &day);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
153
  else
154
    decode_julday(calendar, calday, &year, &month, &day);
155

156
  const int date = cdiEncodeDate(year, month, day);
157

158
  return date;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
159
160
}

161

Uwe Schulzweida's avatar
Uwe Schulzweida committed
162
163
int main(void)
{
164
165
  int calendar = CALENDAR_STANDARD;
  int nmin;
166
167
  int64_t vdate0, vdate;
  int vtime0, vtime;
168
169
  int ijulinc;
  int i, j = 0;
170
  int year, mon, day, hour, minute, second;
171
172
173
174
175
176
  int calday, secofday;

  /* 1 - Check valid range of years */

  nmin = 11000;
  vdate0 = -80001201;
177
  vtime0 = 120500;
178

Uwe Schulzweida's avatar
Uwe Schulzweida committed
179
  printf("start time: %8ld %4d\n", vdate0, vtime0);
180
181
182

  for ( i = 0; i < nmin; i++ )
    {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
183
184
      cdiDecodeDate(vdate0, &year, &mon, &day);
      cdiDecodeTime(vtime0, &hour, &minute, &second);
185
186
187
188
189
190
191
192

      calday  = date_to_calday(calendar, vdate0);
      secofday = time_to_sec(vtime0);

      vdate = calday_to_date(calendar, calday);
      vtime = sec_to_time(secofday);

      if ( vdate0 != vdate || vtime0 != vtime )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
193
	printf("%4d %8ld %4d %8ld %4d %9d %9d\n",
194
195
196
	       ++j, vdate0, vtime0, vdate, vtime, calday, secofday);

      year++;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
197
198
      vdate0 = cdiEncodeDate(year, mon, day);
      vtime0 = cdiEncodeTime(hour, minute, second);
199
200
    }

Uwe Schulzweida's avatar
Uwe Schulzweida committed
201
  printf("stop time: %8ld %4d\n", vdate0, vtime0);
202
203
204
205
206
207
208
209

  /* 2 - Check time increment of one minute */

  nmin = 120000;
  ijulinc = 60;
  vdate0 = 20001201;
  vtime0 = 0;

Uwe Schulzweida's avatar
Uwe Schulzweida committed
210
  printf("start time: %8ld %4d\n", vdate0, vtime0);
211
212
213
214
215

  calday = date_to_calday(calendar, vdate0);
  secofday = time_to_sec(vtime0);
  for ( i = 0; i < nmin; i++ )
    {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
216
217
      cdiDecodeDate(vdate0, &year, &mon, &day);
      cdiDecodeTime(vtime0, &hour, &minute, &second);
218

219
      if ( ++minute >= 60 )
220
	{
221
	  minute = 0;
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
	  if ( ++hour >= 24 )
	    {
	      hour = 0;
	      if ( ++day >= 32 )
		{
		  day = 1;
		  if ( ++mon >= 13 )
		    {
		      mon = 1;
		      year++;
		    }
		}
	    }
	}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
237
238
      vdate0 = cdiEncodeDate(year, mon, day);
      vtime0 = cdiEncodeTime(hour, minute, second);
239
240
241
242
243
244

      julday_add_seconds(ijulinc, &calday, &secofday);

      vdate = calday_to_date(calendar, calday);
      vtime = sec_to_time(secofday);
      if ( vdate0 != vdate || vtime0 != vtime )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
245
	printf("%4d %8ld %4d %8ld %4d %9d %9d\n",
246
247
248
	       ++j, vdate0, vtime0, vdate, vtime, calday, secofday);
    }

Uwe Schulzweida's avatar
Uwe Schulzweida committed
249
  printf("stop time: %8ld %4d\n", vdate0, vtime0);
250

Uwe Schulzweida's avatar
Uwe Schulzweida committed
251
  return 0;
252
253
254
255
256
257
258
259
260
261
}
#endif


#ifdef TEST2
int main(void)
{
  int calendar = CALENDAR_STANDARD;
  int i;
  int calday, secofday;
262
  int year, month, day, hour, minute, second;
263
264
  int value = 30;
  int factor = 86400;
265

266
  calendar = CALENDAR_360DAYS;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
267

268
  year=1979; month=1; day=15; hour=12; minute=30; second = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
269

270
  printf("calendar = %d\n", calendar);
271
  printf("%d/%02d/%02d %02d:%02d:%02d\n", year, month, day, hour, minute, second);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
272

273
  encode_caldaysec(calendar, year, month, day, hour, minute, second, &calday, &secofday);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
274

275
276
  decode_caldaysec(calendar, calday, secofday, &year, &month, &day, &hour, &minute, &second);
  printf("%d/%02d/%02d %02d:%02d:%02d   %d %d\n", year, month, day, hour, minute, second, calday, secofday);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
277
278
279

  for ( i = 0; i < 420; i++ )
    {
280

281
282
      decode_caldaysec(calendar, calday, secofday, &year, &month, &day, &hour, &minute, &second);
      printf("%2d %d/%02d/%02d %02d:%02d:%02d\n", i, year, month, day, hour, minute, second);
283
      julday_add_seconds(value*factor, &calday, &secofday);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
284
285
    }

Uwe Schulzweida's avatar
Uwe Schulzweida committed
286
  return 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
287
}
288
#endif
289
290
291
292
293
294
295
296
297
/*
 * Local Variables:
 * c-file-style: "Java"
 * c-basic-offset: 2
 * indent-tabs-mode: nil
 * show-trailing-whitespace: t
 * require-trailing-newline: t
 * End:
 */