GeographicLib
2.7
Toggle main menu visibility
Loading...
Searching...
No Matches
Utility.cpp
Go to the documentation of this file.
1
/**
2
* \file Utility.cpp
3
* \brief Implementation for GeographicLib::Utility class
4
*
5
* Copyright (c) Charles Karney (2011-2022) <karney@alum.mit.edu> and licensed
6
* under the MIT/X11 License. For more information, see
7
* https://geographiclib.sourceforge.io/
8
**********************************************************************/
9
10
#include <cstdlib>
11
#include <
GeographicLib/Utility.hpp
>
12
13
#if defined(_MSC_VER)
14
// Squelch warnings about unsafe use of getenv
15
# pragma warning (disable: 4996)
16
#endif
17
18
namespace
GeographicLib
{
19
20
using namespace
std;
21
22
int
Utility::day
(
int
y,
int
m,
int
d) {
23
// Convert from date to sequential day and vice versa
24
//
25
// Here is some code to convert a date to sequential day and vice
26
// versa. The sequential day is numbered so that January 1, 1 AD is day 1
27
// (a Saturday). So this is offset from the "Julian" day which starts the
28
// numbering with 4713 BC.
29
//
30
// This is inspired by a talk by John Conway at the John von Neumann
31
// National Supercomputer Center when he described his Doomsday algorithm
32
// for figuring the day of the week. The code avoids explicitly doing ifs
33
// (except for the decision of whether to use the Julian or Gregorian
34
// calendar). Instead the equivalent result is achieved using integer
35
// arithmetic. I got this idea from the routine for the day of the week
36
// in MACLisp (I believe that that routine was written by Guy Steele).
37
//
38
// There are three issues to take care of
39
//
40
// 1. the rules for leap years,
41
// 2. the inconvenient placement of leap days at the end of February,
42
// 3. the irregular pattern of month lengths.
43
//
44
// We deal with these as follows:
45
//
46
// 1. Leap years are given by simple rules which are straightforward to
47
// accommodate.
48
//
49
// 2. We simplify the calculations by moving January and February to the
50
// previous year. Here we internally number the months March-December,
51
// January, February as 0-9, 10, 11.
52
//
53
// 3. The pattern of month lengths from March through January is regular
54
// with a 5-month period—31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31. The
55
// 5-month period is 153 days long. Since February is now at the end of
56
// the year, we don't need to include its length in this part of the
57
// calculation.
58
bool
greg = gregorian(y, m, d);
59
y += (m + 9) / 12 - 1;
// Move Jan and Feb to previous year,
60
m = (m + 9) % 12;
// making March month 0.
61
return
62
(1461 * y) / 4
// Julian years converted to days. Julian year is 365 +
63
// 1/4 = 1461/4 days.
64
// Gregorian leap year corrections. The 2 offset with respect to the
65
// Julian calendar synchronizes the vernal equinox with that at the
66
// time of the Council of Nicea (325 AD).
67
+ (greg ? (y / 100) / 4 - (y / 100) + 2 : 0)
68
+ (153 * m + 2) / 5
// The zero-based start of the m'th month
69
+ d - 1
// The zero-based day
70
- 305;
// The number of days between March 1 and December 31.
71
// This makes 0001-01-01 day 1
72
}
73
74
int
Utility::day
(
int
y,
int
m,
int
d,
bool
check) {
75
int
s =
day
(y, m, d);
76
if
(!check)
77
return
s;
78
int
y1, m1, d1;
79
date
(s, y1, m1, d1);
80
if
(!(s > 0 && y == y1 && m == m1 && d == d1))
81
throw
GeographicErr
(
"Invalid date "
+
82
str
(y) +
"-"
+
str
(m) +
"-"
+
str
(d)
83
+ (s > 0 ?
"; use "
+
84
str
(y1) +
"-"
+
str
(m1) +
"-"
+
str
(d1) :
85
" before 0001-01-01"
));
86
return
s;
87
}
88
89
void
Utility::date
(
int
s,
int
& y,
int
& m,
int
& d) {
90
int
c = 0;
91
bool
greg = gregorian(s);
92
s += 305;
// s = 0 on March 1, 1BC
93
if
(greg) {
94
s -= 2;
// The 2 day Gregorian offset
95
// Determine century with the Gregorian rules for leap years. The
96
// Gregorian year is 365 + 1/4 - 1/100 + 1/400 = 146097/400 days.
97
c = (4 * s + 3) / 146097;
98
s -= (c * 146097) / 4;
// s = 0 at beginning of century
99
}
100
y = (4 * s + 3) / 1461;
// Determine the year using Julian rules.
101
s -= (1461 * y) / 4;
// s = 0 at start of year, i.e., March 1
102
y += c * 100;
// Assemble full year
103
m = (5 * s + 2) / 153;
// Determine the month
104
s -= (153 * m + 2) / 5;
// s = 0 at beginning of month
105
d = s + 1;
// Determine day of month
106
y += (m + 2) / 12;
// Move Jan and Feb back to original year
107
m = (m + 2) % 12 + 1;
// Renumber the months so January = 1
108
}
109
110
void
Utility::date
(
const
std::string& s,
int
& y,
int
& m,
int
& d) {
111
if
(s ==
"now"
) {
112
time_t t = time(0);
113
struct
tm* now = gmtime(&t);
114
y = now->tm_year + 1900;
115
m = now->tm_mon + 1;
116
d = now->tm_mday;
117
return
;
118
}
119
int
y1, m1 = 1, d1 = 1;
120
const
char
* digits =
"0123456789"
;
121
string::size_type p1 = s.find_first_not_of(digits);
122
if
(p1 == string::npos)
123
y1 =
val<int>
(s);
124
else
if
(s[p1] !=
'-'
)
125
throw
GeographicErr
(
"Delimiter not hyphen in date "
+ s);
126
else
if
(p1 == 0)
127
throw
GeographicErr
(
"Empty year field in date "
+ s);
128
else
{
129
y1 =
val<int>
(s.substr(0, p1));
130
if
(++p1 == s.size())
131
throw
GeographicErr
(
"Empty month field in date "
+ s);
132
string::size_type p2 = s.find_first_not_of(digits, p1);
133
if
(p2 == string::npos)
134
m1 =
val<int>
(s.substr(p1));
135
else
if
(s[p2] !=
'-'
)
136
throw
GeographicErr
(
"Delimiter not hyphen in date "
+ s);
137
else
if
(p2 == p1)
138
throw
GeographicErr
(
"Empty month field in date "
+ s);
139
else
{
140
m1 =
val<int>
(s.substr(p1, p2 - p1));
141
if
(++p2 == s.size())
142
throw
GeographicErr
(
"Empty day field in date "
+ s);
143
d1 =
val<int>
(s.substr(p2));
144
}
145
}
146
y = y1; m = m1; d = d1;
147
}
148
149
std::string
Utility::trim
(
const
std::string& s) {
150
unsigned
151
beg = 0,
152
end = unsigned(s.size());
153
while
(beg < end && isspace(s[beg]))
154
++beg;
155
while
(beg < end && isspace(s[end - 1]))
156
--end;
157
return
string(s, beg, end-beg);
158
}
159
160
int
Utility::lookup
(
const
std::string& s,
char
c) {
161
string::size_type r = s.find(
char
(toupper(c)));
162
return
r == string::npos ? -1 : int(r);
163
}
164
165
int
Utility::lookup
(
const
char
* s,
char
c) {
166
const
char
* p = strchr(s, toupper(c));
167
return
p != NULL ? int(p - s) : -1;
168
}
169
170
bool
Utility::ParseLine
(
const
std::string& line,
171
std::string& key, std::string& value,
172
char
equals,
char
comment) {
173
key.clear(); value.clear();
174
string::size_type n = comment ? line.find(comment) : line.size();
175
string
linea =
trim
(line.substr(0, n));
176
if
(linea.empty())
return
false
;
177
n = equals ? linea.find(equals) : linea.find_first_of(
" \t\n\v\f\r"
);
178
key =
trim
(linea.substr(0, n));
179
if
(key.empty())
return
false
;
180
if
(n != string::npos) value =
trim
(linea.substr(n + 1));
181
return
true
;
182
}
183
184
int
Utility::set_digits
(
int
ndigits) {
185
#if GEOGRAPHICLIB_PRECISION == 5
186
if
(ndigits <= 0) {
187
char
* digitenv = getenv(
"GEOGRAPHICLIB_DIGITS"
);
188
if
(digitenv)
189
ndigits = strtol(digitenv, NULL, 0);
190
if
(ndigits <= 0)
191
ndigits = 256;
192
}
193
#endif
194
return
Math::set_digits
(ndigits);
195
}
196
197
}
// namespace GeographicLib
Utility.hpp
Header for GeographicLib::Utility class.
GeographicLib::GeographicErr
Exception handling for GeographicLib.
Definition
Constants.hpp:344
GeographicLib::Math::set_digits
static int set_digits(int ndigits)
Definition
Math.cpp:28
GeographicLib::Utility::date
static void date(int s, int &y, int &m, int &d)
Definition
Utility.cpp:89
GeographicLib::Utility::lookup
static int lookup(const std::string &s, char c)
Definition
Utility.cpp:160
GeographicLib::Utility::ParseLine
static bool ParseLine(const std::string &line, std::string &key, std::string &value, char equals='\0', char comment='#')
Definition
Utility.cpp:170
GeographicLib::Utility::val
static T val(const std::string &s)
Definition
Utility.hpp:225
GeographicLib::Utility::set_digits
static int set_digits(int ndigits=0)
Definition
Utility.cpp:184
GeographicLib::Utility::trim
static std::string trim(const std::string &s)
Definition
Utility.cpp:149
GeographicLib::Utility::day
static int day(int y, int m=1, int d=1)
Definition
Utility.cpp:22
GeographicLib::Utility::str
static std::string str(T x, int p=-1)
Definition
Utility.hpp:161
GeographicLib
Namespace for GeographicLib.
Definition
Accumulator.cpp:12
src
Utility.cpp
Generated by
1.17.0