bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
date_proc.cc
1// -*- mode: c++; c-basic-offset:4 -*-
2
3// This file is part of ff_handler a FreeForm API handler for the OPeNDAP
4// DAP2 data server.
5
6// Copyright (c) 2005 OPeNDAP, Inc.
7// Author: James Gallagher <jgallagher@opendap.org>
8//
9// This is free software; you can redistribute it and/or modify it under the
10// terms of the GNU Lesser General Public License as published by the Free
11// Software Foundation; either version 2.1 of the License, or (at your
12// option) any later version.
13//
14// This software is distributed in the hope that it will be useful, but
15// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
17// License for more details.
18//
19// You should have received a copy of the GNU Lesser General Public
20// License along with this library; if not, write to the Free Software
21// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22//
23// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
24
25// These functions handle date translation between Julian and Gregorian
26// formats. 8/12/93 jhrg
27//
28// This code was originally copied from one of the ACM's code libraries and
29// used in the browsed image server. That version was written in C.
30
31
32#include "config_ff.h"
33
34static char rcsid[]not_used = {
35 "$Id$" };
36
37#include <cassert>
38
39#include <libdap/Error.h>
40
41using namespace libdap;
42
43// You have to add one to days[1] if the year is a leap year. Since the month
44// number in a Gregorian date is ones-based, fill element zero below to
45// avoid gratuitous subtractions of the index value. Note that the fill
46// value is never used. 9/4/98 jhrg
47static int
48 days_arr[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
49
52int is_leap(int year)
53{
54 return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
55}
56
59double days_in_year(int year)
60{
61 return is_leap(year) ? 366.0 : 365.0;
62}
63
64static inline int days(int year, int month)
65{
66 if (!(year > 0) || !(month > 0 && month < 13))
67 throw Error(malformed_expr, "Date year or month is bad.");
68
69 if (month == 2 && is_leap(year))
70 return 29;
71 else
72 return days_arr[month];
73}
74
86long julian_day(int year, int month, int day)
87{
88 if (!(year > 0))
89 throw Error(malformed_expr, "A date's year must be greater the zero.");
90 if (!(month > 0 && month < 13))
91 throw Error(malformed_expr,
92 "A date's month must be between zero and thirteen.");
93
94 if (!(day > 0 && day <= days(year, month)))
95 throw Error(malformed_expr,
96 "A date's day must be between zero and 28-31, depending on the month.");
97
98 long jdn;
99
100 jdn = (long) year * 367 + month * 275 / 9 - (year + (month > 2)) * 7 / 4
101 - ((year - (month < 3)) / 100 + 1) * 3 / 4 + day + 1721029L;
102
103 return (jdn);
104}
105
121void gregorian_date(double jd, int *year, int *month, int *day, int *hours,
122 int *minutes, double *seconds)
123{
124 assert(jd> 0.0);
125
126 long j = (long) jd;
127 double tmp, frac = jd - j;
128
129 if (frac >= 0.5) {
130 frac = frac - 0.5;
131 j++;
132 }
133 else {
134 frac = frac + 0.5;
135 }
136
137 j -= 1721119L;
138 *year = (4L * j - 1L) / 146097L;
139 j = 4L * j - 1L - 146097L * *year;
140 *day = j / 4L;
141 j = (4L * *day + 3L) / 1461L;
142 *day = 4L * *day + 3L - 1461L * j;
143 *day = (*day + 4L) / 4L;
144 *month = (5L * *day - 3L) / 153L;
145 *day = 5L * *day - 3 - 153L * *month;
146 *day = (*day + 5L) / 5L;
147 *year = 100L * *year + j;
148 if (*month < 10) {
149 *month += 3;
150 }
151 else {
152 *month -= 9;
153 *year += 1;
154 }
155 tmp = 3600.0 * (frac * 24.0);
156 *hours = (int) (tmp / 3600.0);
157 tmp = tmp - *hours * 3600.0;
158 *minutes = (int) (tmp / 60.0);
159 *seconds = tmp - *minutes * 60.0;
160}
161
169int month_day_to_days(int year, int month, int day)
170{
171 if (!(year > 0))
172 throw Error(malformed_expr, "A date's year must be greater the zero.");
173 if (!(month > 0 && month < 13))
174 throw Error(malformed_expr,
175 "A date's month must be between zero and thirteen.");
176
177 if (!(day > 0 && day <= days(year, month)))
178 throw Error(malformed_expr,
179 "A date's day must be between zero and 28-31, depending on the month.");
180
181 int ddd = day;
182
183 while (--month)
184 ddd += days(year, month);
185
186 return ddd;
187}
188
189// Note this could be implemented using days_arr[] defined at the top of this
190// file. 5/23/2001 jhrg
191int days_in_month(int year, int month)
192{
193 //int daysInYear;
194 int daysInMonth; // ... might want to remove the temporary
195 // variable and just return the value from
196 // the switch. Although the temp makes
197 // debugging easier. 5/23/2001 jhrg
198
199 switch (month) {
200 case 1:
201 case 3:
202 case 5:
203 case 7:
204 case 8:
205 case 10:
206 case 12:
207 daysInMonth = 31;
208 break;
209 case 2:
210 //daysInYear = (year % 4) && !(year % 100) && (year % 400) ? 366 : 365;
211 daysInMonth = (is_leap(year)) ? 29 : 28;
212 break;
213 case 4:
214 case 6:
215 case 9:
216 case 11:
217 daysInMonth = 30;
218 break;
219 default:
220 // Added. 5/23/2001 jhrg
221 throw Error("Months must be numbered between 1 and 12 inclusive.");
222 break;
223 }
224 return daysInMonth;
225}
226
237
238void days_to_month_day(int year, int ddd, int *month, int *day)
239{
240 assert(year> 0);
241 assert(ddd> 0 && ddd <= 365 + is_leap(year));
242
243 *month = 1;
244
245 while (ddd > days(year, *month))
246 ddd -= days(year, (*month)++);
247
248 *day = ddd;
249}
250
256
257int dayofweek(double j)
258{
259 long jd = (long) j;
260 if (j - jd >= 0.5)
261 jd++;
262
263 return (jd + 1) % 7;
264}
265