Repository: conan-io/conan-center-index

Issue:
[package] date/2.4.1: header_only option
Please add a header_only option to 'date' recipe.


Discussion:

Resolving patch:
diff --git a/recipes/date/all/conanfile.py b/recipes/date/all/conanfile.py
--- a/recipes/date/all/conanfile.py
+++ b/recipes/date/all/conanfile.py
@@ -15,10 +15,12 @@ class DateConan(ConanFile):
     generators = "cmake",
     options = {"shared": [True, False],
                "fPIC": [True, False],
+               "header_only": [True, False],
                "use_system_tz_db": [True, False],
                "use_tz_db_in_dot": [True, False]}
     default_options = {"shared": False,
                        "fPIC": True,
+                       "header_only": False,
                        "use_system_tz_db": False,
                        "use_tz_db_in_dot": False}
 
@@ -52,6 +54,8 @@ def configure(self):
             tools.check_min_cppstd(self, "11")
 
     def requirements(self):
+        if self.options.header_only:
+            return
         if not self.options.use_system_tz_db:
             self.requires("libcurl/7.69.1")
 
@@ -63,18 +67,34 @@ def source(self):
     def build(self):
         for patch in self.conan_data["patches"][self.version]:
             tools.patch(**patch)
+        if self.options.header_only:
+            self.output.info("Header only package, skipping build")
+            return
         cmake = self._configure_cmake()
         cmake.build()
 
     def package(self):
         self.copy(pattern="LICENSE.txt", dst="licenses",
                   src=self._source_subfolder)
+        if self.options.header_only:
+            src = os.path.join(self._source_subfolder, "include", "date")
+            dst = os.path.join("include", "date")
+            self.copy(pattern="date.h", dst=dst, src=src)
+            self.copy(pattern="tz.h", dst=dst, src=src)
+            self.copy(pattern="iso_week.h", dst=dst, src=src)
+            self.copy(pattern="julian.h", dst=dst, src=src)
+            self.copy(pattern="islamic.h", dst=dst, src=src)
+            return
+
         cmake = self._configure_cmake()
         cmake.install()
         tools.rmdir(os.path.join(self.package_folder, "lib", "cmake"))
         tools.rmdir(os.path.join(self.package_folder, "CMake"))
 
     def package_info(self):
+        if self.options.header_only:
+            return
+
         self.cpp_info.libs = tools.collect_libs(self)
         if self.settings.os == "Linux":
             self.cpp_info.system_libs.append("pthread")
@@ -89,3 +109,7 @@ def package_info(self):
             defines.append("DATE_USE_DLL=1")
 
         self.cpp_info.defines.extend(defines)
+
+    def package_id(self):
+        if self.options.header_only:
+            self.info.header_only()


Test patch:
diff --git a/recipes/date/all/test_package/CMakeLists.txt b/recipes/date/all/test_package/CMakeLists.txt
--- a/recipes/date/all/test_package/CMakeLists.txt
+++ b/recipes/date/all/test_package/CMakeLists.txt
@@ -7,3 +7,6 @@ conan_basic_setup()
 add_executable(${PROJECT_NAME} test_package.cpp)
 target_link_libraries(${PROJECT_NAME} ${CONAN_LIBS})
 set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 11)
+if(DATE_HEADER_ONLY)
+  target_compile_definitions(${PROJECT_NAME} PRIVATE DATE_HEADER_ONLY)
+endif()
diff --git a/recipes/date/all/test_package/conanfile.py b/recipes/date/all/test_package/conanfile.py
--- a/recipes/date/all/test_package/conanfile.py
+++ b/recipes/date/all/test_package/conanfile.py
@@ -8,10 +8,11 @@ class TestPackageConan(ConanFile):
 
     def build(self):
         cmake = CMake(self)
+        cmake.definitions["DATE_HEADER_ONLY"] = self.options["date:header_only"]
         cmake.configure()
         cmake.build()
 
     def test(self):
         if not tools.cross_building(self.settings):
             bin_path = os.path.join("bin", "test_package")
-            self.run(bin_path, run_environment=True)
\ No newline at end of file
+            self.run(bin_path, run_environment=True)
diff --git a/recipes/date/all/test_package/test_package.cpp b/recipes/date/all/test_package/test_package.cpp
--- a/recipes/date/all/test_package/test_package.cpp
+++ b/recipes/date/all/test_package/test_package.cpp
@@ -1,9 +1,37 @@
+#include "date/date.h"
+#include "date/tz.h"
+
+#include <chrono>
 #include <cstdlib>
 #include <iostream>
-#include <chrono>
+#include <type_traits>
 
-#include "date/date.h"
-#include "date/tz.h"
+class ZoneOffset {
+public:
+    explicit ZoneOffset(std::chrono::minutes offset)
+        : _offset(offset) {}
+
+    template <class Duration>
+    auto to_local(date::sys_time<Duration> tp) const
+        -> date::local_time<typename std::common_type<Duration, std::chrono::minutes>::type> {
+        using namespace date;
+        using namespace std::chrono;
+        using LT = local_time<typename std::common_type<Duration, minutes>::type>;
+        return LT{(tp + _offset).time_since_epoch()};
+    }
+
+    template <class Duration>
+    auto to_sys(date::local_time<Duration> tp) const
+        -> date::sys_time<typename std::common_type<Duration, std::chrono::minutes>::type> {
+        using namespace date;
+        using namespace std::chrono;
+        using ST = sys_time<typename std::common_type<Duration, minutes>::type>;
+        return ST{(tp - _offset).time_since_epoch()};
+    }
+
+private:
+    std::chrono::minutes _offset;
+};
 
 int main() {
     using namespace std::chrono;
@@ -16,12 +44,19 @@ int main() {
     auto date3 = 22_d/March/2015;
     std::cout << date3 << '\n';
 
+    ZoneOffset p3_45{hours{3} + minutes{45}};
+    zoned_time<milliseconds, ZoneOffset*> zt{&p3_45, floor<milliseconds>(system_clock::now())};
+    std::cout << zt.get_sys_time() << " (sys time)\n";
+    std::cout << zt.get_local_time() << " (local time)\n";
+
+#ifndef DATE_HEADER_ONLY
     try {
         auto tz = date::current_zone()->name();
         std::cout << "timezone: " << tz << std::endl;
     } catch (const std::exception & e) {
          std::cout << "exception caught " << e.what() << std::endl;
     }
+#endif
 
     return EXIT_SUCCESS;
 }