Skip to content

Commit ee3a0bd

Browse files
authored
Merge pull request #4692 from KinshukSS2/fix/localtime-thread-safety-and-leap-year
Refactor time parsing with thread-safe localtime and leap year fix
2 parents fc4c131 + 645954b commit ee3a0bd

File tree

4 files changed

+41
-34
lines changed

4 files changed

+41
-34
lines changed

src/param.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/* put parameters in linked list and retrieve */
22

3+
#include <ctime>
34
#include <ctype.h>
45
#include <stddef.h>
56
#include <stdio.h>
@@ -215,3 +216,40 @@ PROJVALUE pj_param(PJ_CONTEXT *ctx, paralist *pl, const char *opt) {
215216
}
216217
return value;
217218
}
219+
220+
/* Parse +t_final parameter with support for "now" keyword */
221+
double pj_parse_t_final(PJ *P) {
222+
if (!pj_param(P->ctx, P->params, "tt_final").i) {
223+
return 0.0;
224+
}
225+
226+
double t_final = pj_param(P->ctx, P->params, "dt_final").f;
227+
if (t_final != 0.0) {
228+
return t_final;
229+
}
230+
231+
/* Check if "now" was specified instead of a numeric value */
232+
const char *t_final_str = pj_param(P->ctx, P->params, "st_final").s;
233+
if (!t_final_str || strcmp("now", t_final_str) != 0) {
234+
return 0.0;
235+
}
236+
237+
/* Calculate t_final from current time */
238+
time_t now;
239+
struct tm date;
240+
time(&now);
241+
#ifdef _WIN32
242+
localtime_s(&date, &now);
243+
#else
244+
localtime_r(&now, &date);
245+
#endif
246+
247+
const int days_in_year =
248+
((date.tm_year + 1900) % 4 == 0 &&
249+
((date.tm_year + 1900) % 100 != 0 || (date.tm_year + 1900) % 400 == 0))
250+
? 366
251+
: 365;
252+
253+
return 1900.0 + date.tm_year +
254+
date.tm_yday / static_cast<double>(days_in_year);
255+
}

src/proj_internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -911,6 +911,7 @@ PROJVALUE PROJ_DLL pj_param(PJ_CONTEXT *ctx, paralist *, const char *);
911911
paralist PROJ_DLL *pj_param_exists(paralist *list, const char *parameter);
912912
paralist PROJ_DLL *pj_mkparam(const char *);
913913
paralist *pj_mkparam_ws(const char *str, const char **next_str);
914+
double pj_parse_t_final(PJ *P);
914915

915916
int PROJ_DLL pj_ell_set(PJ_CONTEXT *ctx, paralist *, double *, double *);
916917
int pj_datum_set(PJ_CONTEXT *, paralist *, PJ *);

src/transformations/hgridshift.cpp

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
#include <mutex>
55
#include <stddef.h>
66
#include <string.h>
7-
#include <time.h>
87

98
#include "grids.hpp"
109
#include "proj_internal.h"
@@ -162,22 +161,7 @@ PJ *PJ_TRANSFORMATION(hgridshift, 0) {
162161
return pj_hgridshift_destructor(P, PROJ_ERR_INVALID_OP_MISSING_ARG);
163162
}
164163

165-
/* TODO: Refactor into shared function that can be used */
166-
/* by both vgridshift and hgridshift */
167-
if (pj_param(P->ctx, P->params, "tt_final").i) {
168-
Q->t_final = pj_param(P->ctx, P->params, "dt_final").f;
169-
if (Q->t_final == 0) {
170-
/* a number wasn't passed to +t_final, let's see if it was "now" */
171-
/* and set the time accordingly. */
172-
if (!strcmp("now", pj_param(P->ctx, P->params, "st_final").s)) {
173-
time_t now;
174-
struct tm *date;
175-
time(&now);
176-
date = localtime(&now);
177-
Q->t_final = 1900.0 + date->tm_year + date->tm_yday / 365.0;
178-
}
179-
}
180-
}
164+
Q->t_final = pj_parse_t_final(P);
181165

182166
if (pj_param(P->ctx, P->params, "tt_epoch").i)
183167
Q->t_epoch = pj_param(P->ctx, P->params, "dt_epoch").f;

src/transformations/vgridshift.cpp

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
#include <mutex>
55
#include <stddef.h>
66
#include <string.h>
7-
#include <time.h>
87

98
#include "grids.hpp"
109
#include "proj_internal.h"
@@ -182,22 +181,7 @@ PJ *PJ_TRANSFORMATION(vgridshift, 0) {
182181
return pj_vgridshift_destructor(P, PROJ_ERR_INVALID_OP_MISSING_ARG);
183182
}
184183

185-
/* TODO: Refactor into shared function that can be used */
186-
/* by both vgridshift and hgridshift */
187-
if (pj_param(P->ctx, P->params, "tt_final").i) {
188-
Q->t_final = pj_param(P->ctx, P->params, "dt_final").f;
189-
if (Q->t_final == 0) {
190-
/* a number wasn't passed to +t_final, let's see if it was "now" */
191-
/* and set the time accordingly. */
192-
if (!strcmp("now", pj_param(P->ctx, P->params, "st_final").s)) {
193-
time_t now;
194-
struct tm *date;
195-
time(&now);
196-
date = localtime(&now);
197-
Q->t_final = 1900.0 + date->tm_year + date->tm_yday / 365.0;
198-
}
199-
}
200-
}
184+
Q->t_final = pj_parse_t_final(P);
201185

202186
if (pj_param(P->ctx, P->params, "tt_epoch").i)
203187
Q->t_epoch = pj_param(P->ctx, P->params, "dt_epoch").f;

0 commit comments

Comments
 (0)