Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added timezone support #34

Closed
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 27 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,35 @@ cmake_minimum_required(VERSION 3.6)
project(top)

option(LIBCRON_BUILD_TZ_CLOCK "Build timezone clock" OFF)
option(LIBCRON_MANUAL_TZ_DB "User will set TZ DB manually by invoking date::set_install in their code" OFF)

if(LIBCRON_BUILD_TZ_CLOCK)
set(BUILD_TZ_LIB ON CACHE BOOL "Build the tz library" FORCE)
add_subdirectory(libcron/externals/date)
add_library(date-tz)
target_sources(date-tz
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/libcron/externals/date/include/date/tz.h
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/libcron/externals/date/include/date/tz_private.h
${CMAKE_CURRENT_LIST_DIR}/libcron/externals/date/src/tz.cpp
)
target_include_directories(date-tz PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/libcron/externals/date/include)

if (LIBCRON_MANUAL_TZ_DB)
target_compile_definitions(date-tz PRIVATE AUTO_DOWNLOAD=0 HAS_REMOTE_API=0)
else()
find_package(CURL REQUIRED)
target_link_libraries(date-tz PRIVATE CURL::libcurl)
target_compile_definitions(date-tz PRIVATE AUTO_DOWNLOAD=1 HAS_REMOTE_API=1)
endif()

if (WIN32 AND BUILD_SHARED_LIBS)
target_compile_definitions(date-tz PUBLIC DATE_BUILD_DLL=1)
endif()

if(NOT MSVC)
find_package(Threads)
target_link_libraries(date-tz PUBLIC Threads::Threads)
endif()
endif()

add_subdirectory(libcron)
Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,14 +149,14 @@ else
If you want to use TzClock you have to set -DLIBCRON_BUILD_TZ_CLOCK=ON when building libcron. TzClock is a fully optional feature
if you don't enable it, it won't be build at all.

Using TzClock has the following side effects:
1. Date requires linkage to `libcurl`
2. First time TzClocks timezone lookup will occur it will download the most up to date timezone: "~/Downloads/tzdata" ("%homedrive%\%homepath%\downloads\tzdata" on Windows).
3. TzClock uses a `std::mutex` to protect the time zone in multithreaded envoirements.
4. This implementation might decrease performance a lot based on point 2 and 3.
By default when setting the time zone with `TzClock::set_time_zone`, date-tz will automatically download the neweset database version from [Time Zones](https://www.iana.org/time-zones).
This can be disabled with `-DLIBCRON_MANUAL_TZ_DB=ON`. If this is set user will be responsible of downloading timezone database.

[More Info about date-tz](https://howardhinnant.github.io/date/tz.html)
Setting database path / install path can be done with `date::set_install`. If not set path will default to: "~/Downloads/tzdata" ("%homedrive%\%homepath%\downloads\tzdata" on Windows).
Using TzClock without LIBCRON_MANUAL_TZ_DB requires liburl installed in your system. On Windows it will also require 7-Zip installed into the default location.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait, it requires 7-zip ? Meaning it will execute it to unpack? I'll have to pull the emergency break here. This library should not execute any application, too much of a security issue the user of this library doesn't have control over.

With that in mind, we'll have to settle with using a pre-existing DB and let the library user handle management of that file.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With that in mind, the TzClock can take a path to the DB as a constructor argument and call date:set_install, ensuring it is available before the construction of the clock.

TzClock by default protects it's time_zone with a `std::mutex` this can be disabled by setting LockType to libcron::NullLock.

[More Info about date-tz](https://howardhinnant.github.io/date/tz.html)
[Available Regions](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)

# Supported formatting
Expand Down
31 changes: 28 additions & 3 deletions libcron/include/libcron/CronClock.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ namespace libcron
};

#ifdef BUILD_TZ_CLOCK
template<typename LockType = std::mutex>
class TzClock : public ICronClock
{
public:
Expand All @@ -54,10 +55,34 @@ namespace libcron
return now + utc_offset(now);
}

bool set_time_zone(std::string_view tz_name);
std::chrono::seconds utc_offset(std::chrono::system_clock::time_point now) const override;
std::chrono::seconds utc_offset(std::chrono::system_clock::time_point now) const override
{
// If we don't have a timezone we use utc
using namespace std::chrono;
std::lock_guard<LockType> lock(time_zone_mtx);
if (time_zone)
return time_zone->get_info(now).offset;
else
return 0s;
}

bool set_time_zone(std::string_view tz_name)
{
const date::time_zone *new_zone{nullptr};
try
{
new_zone = date::locate_zone(tz_name);
}
catch (std::runtime_error &err)
{
return false;
}
std::lock_guard<LockType> lock(time_zone_mtx);
time_zone = new_zone;
return true;
}
private:
mutable std::mutex time_zone_mtx{};
mutable LockType time_zone_mtx{};
const date::time_zone* time_zone{nullptr};
};
#endif
Expand Down
31 changes: 0 additions & 31 deletions libcron/src/CronClock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,35 +36,4 @@ namespace libcron
#endif
return offset;
}

#ifdef BUILD_TZ_CLOCK
bool TzClock::set_time_zone(std::string_view tz_name)
{
const date::time_zone *new_zone{nullptr};

try
{
new_zone = date::locate_zone(tz_name);
}
catch (std::runtime_error &err)
{
return false;
}

std::lock_guard<std::mutex> lock(time_zone_mtx);
time_zone = new_zone;
return true;
}

std::chrono::seconds TzClock::utc_offset(std::chrono::system_clock::time_point now) const
{
using namespace std::chrono;
// If we don't have a timezone we use utc
std::lock_guard<std::mutex> lock(time_zone_mtx);
if (time_zone)
return time_zone->get_info(now).offset;
else
return 0s;
}
#endif
}