aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/source/operations/conversions/unitconvert.rst10
-rw-r--r--src/conversions/unitconvert.cpp19
-rw-r--r--src/iso19111/crs.cpp3
-rw-r--r--test/unit/gie_self_tests.cpp31
-rw-r--r--test/unit/test_operationfactory.cpp26
5 files changed, 78 insertions, 11 deletions
diff --git a/docs/source/operations/conversions/unitconvert.rst b/docs/source/operations/conversions/unitconvert.rst
index f1488d9a..13ca9228 100644
--- a/docs/source/operations/conversions/unitconvert.rst
+++ b/docs/source/operations/conversions/unitconvert.rst
@@ -158,6 +158,16 @@ Time units
In the table below all time units supported by PROJ are listed.
+ .. note::
+
+ When converting time units from a date-only format (`yyyymmdd`), PROJ
+ assumes a time value of 00:00 midnight. When converting time units
+ to a date-only format, PROJ rounds to the *nearest* date at 00:00
+ midnight. That is, any time values less than 12:00 noon will round to
+ 00:00 on the same day. Time values greater than or equal to 12:00 noon
+ will round to 00:00 on the following day.
+
+
+--------------+-----------------------------+
| Label | Name |
+==============+=============================+
diff --git a/src/conversions/unitconvert.cpp b/src/conversions/unitconvert.cpp
index d584d93f..991eb2e0 100644
--- a/src/conversions/unitconvert.cpp
+++ b/src/conversions/unitconvert.cpp
@@ -252,21 +252,22 @@ static double yyyymmdd_to_mjd(double yyyymmdd) {
/***********************************************************************/
static double mjd_to_yyyymmdd(double mjd) {
/************************************************************************
- Date given in YYYY-MM-DD format.
+ Date returned in YYYY-MM-DD format.
************************************************************************/
- double mjd_iter = 14 + 31;
- int year = 1859, month=0, day=0;
+ unsigned int date_iter = 14 + 31;
+ unsigned int year = 1859, month = 0, day = 0;
+ unsigned int date = (int) lround(mjd);
- for (; mjd >= mjd_iter; year++) {
- mjd_iter += days_in_year(year);
+ for (; date >= date_iter; year++) {
+ date_iter += days_in_year(year);
}
year--;
- mjd_iter -= days_in_year(year);
+ date_iter -= days_in_year(year);
- for (month=1; mjd_iter + days_in_month(year, month) <= mjd; month++)
- mjd_iter += days_in_month(year, month);
+ for (month=1; date_iter + days_in_month(year, month) <= date; month++)
+ date_iter += days_in_month(year, month);
- day = (int)(mjd - mjd_iter + 1);
+ day = date - date_iter + 1;
return year*10000.0 + month*100.0 + day;
}
diff --git a/src/iso19111/crs.cpp b/src/iso19111/crs.cpp
index 881aec0b..e4b8094f 100644
--- a/src/iso19111/crs.cpp
+++ b/src/iso19111/crs.cpp
@@ -4404,7 +4404,8 @@ void ProjectedCRS::addUnitConvertAndAxisSwap(io::PROJStringFormatter *formatter,
formatter->addParam("units", "m");
}
- if (!axisSpecFound && !formatter->getCRSExport()) {
+ if (!axisSpecFound &&
+ (!formatter->getCRSExport() || formatter->getLegacyCRSToCRSContext())) {
const auto &dir0 = axisList[0]->direction();
const auto &dir1 = axisList[1]->direction();
if (!(&dir0 == &cs::AxisDirection::EAST &&
diff --git a/test/unit/gie_self_tests.cpp b/test/unit/gie_self_tests.cpp
index 71df8fe1..5c14d747 100644
--- a/test/unit/gie_self_tests.cpp
+++ b/test/unit/gie_self_tests.cpp
@@ -618,7 +618,6 @@ static void test_time(const char *args, double tol, double t_in, double t_exp) {
// ---------------------------------------------------------------------------
TEST(gie, unitconvert_selftest) {
-
char args1[] = "+proj=unitconvert +t_in=decimalyear +t_out=decimalyear";
double in1 = 2004.25;
@@ -641,6 +640,36 @@ TEST(gie, unitconvert_selftest) {
test_time(args5, 1e-6, in5, in5);
}
+static void test_date(const char *args, double tol, double t_in, double t_exp) {
+ PJ_COORD in, out;
+ PJ *P = proj_create(PJ_DEFAULT_CTX, args);
+
+ ASSERT_TRUE(P != 0);
+
+ in = proj_coord(0.0, 0.0, 0.0, t_in);
+
+ out = proj_trans(P, PJ_FWD, in);
+ EXPECT_NEAR(out.xyzt.t, t_exp, tol);
+
+ proj_destroy(P);
+
+ proj_log_level(NULL, PJ_LOG_NONE);
+}
+
+TEST(gie, unitconvert_selftest_date) {
+ char args[] = "+proj=unitconvert +t_in=decimalyear +t_out=yyyymmdd";
+ test_date(args, 1e-6, 2022.0027, 20220102);
+ test_date(args, 1e-6, 1990.0, 19900101);
+ test_date(args, 1e-6, 2004.1612, 20040229);
+ test_date(args, 1e-6, 1899.999, 19000101);
+
+ strcpy(&args[18], "+t_in=yyyymmdd +t_out=decimalyear");
+ test_date(args, 1e-6, 20220102, 2022.0027397);
+ test_date(args, 1e-6, 19900101, 1990.0);
+ test_date(args, 1e-6, 20040229, 2004.1612022);
+ test_date(args, 1e-6, 18991231, 1899.9972603);
+}
+
static const char tc32_utm32[] = {
" +proj=horner"
" +ellps=intl"
diff --git a/test/unit/test_operationfactory.cpp b/test/unit/test_operationfactory.cpp
index 89c4e7c4..0c3ecae4 100644
--- a/test/unit/test_operationfactory.cpp
+++ b/test/unit/test_operationfactory.cpp
@@ -6569,6 +6569,32 @@ TEST(operation, createOperation_on_crs_with_bound_crs_and_wktext) {
// ---------------------------------------------------------------------------
+TEST(operation,
+ createOperation_fallback_to_proj4_strings_with_axis_inverted_projCRS) {
+ auto objSrc =
+ createFromUserInput("EPSG:2193", DatabaseContext::create(), false);
+ auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
+ ASSERT_TRUE(src != nullptr);
+
+ auto objDest = PROJStringParser().createFromPROJString(
+ "+proj=longlat +ellps=WGS84 +lon_wrap=180 +type=crs");
+ auto dest = nn_dynamic_pointer_cast<GeographicCRS>(objDest);
+ ASSERT_TRUE(dest != nullptr);
+
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dest));
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +proj=axisswap +order=2,1 "
+ "+step +inv +proj=tmerc +lat_0=0 +lon_0=173 +k=0.9996 "
+ "+x_0=1600000 +y_0=10000000 +ellps=GRS80 "
+ "+step +proj=longlat +ellps=WGS84 +lon_wrap=180 "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg");
+}
+
+// ---------------------------------------------------------------------------
+
TEST(operation, compoundCRS_to_proj_string_with_non_metre_height) {
auto objSrc =
createFromUserInput("EPSG:6318+5703", DatabaseContext::create(), false);