Skip to content

Commit

Permalink
[date] Hotfix date#611 to v3.0.0 and v2.4.1
Browse files Browse the repository at this point in the history
* Add patches for v3.0.0 and v2.4.1 that hotfix the changes present in
  HowardHinnant/date#611 on to these older versions. This will allow all
  versions of date currently on CCI to utilise the tz package as a data
  source for the timezone database.

  Some additional modification of the build system was required in these
  patches to ensure a consistent interface across versions. Only the
  minimal changes necessary to introduce desired features were made,
  preserving deficiencies associated with older versions of date.
  • Loading branch information
samuel-emrys committed Dec 21, 2023
1 parent 6a8e364 commit 7a12d26
Show file tree
Hide file tree
Showing 3 changed files with 725 additions and 0 deletions.
8 changes: 8 additions & 0 deletions recipes/date/all/conandata.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ patches:
- patch_file: "patches/cmake-3.0.0.patch"
patch_description: "Disable string view to workaround clang 5 not having it"
patch_type: "portability"
- patch_file: "patches/load-tzdb-from-envvar-and-windows-binary-db-support-3.0.0.patch"
patch_description: "Allow TZDB to be loaded by envvar and add ability for windows to read zic-compiled binary db"
patch_type: "portability"
patch_source: "https://github.com/HowardHinnant/date/pull/611"
"2.4.1":
- patch_file: "patches/0001-fix-uwp.patch"
patch_description: "Fix Universal Windows Platform (UWP) unhandled exception support. See https://github.com/microsoft/vcpkg/pull/8151#issuecomment-531175393."
Expand All @@ -31,3 +35,7 @@ patches:
- patch_file: "patches/string_view.patch"
patch_description: "Disable string view to workaround clang 5 not having it"
patch_type: "portability"
- patch_file: "patches/load-tzdb-from-envvar-and-windows-binary-db-support-2.4.1.patch"
patch_description: "Allow TZDB to be loaded by envvar and add ability for windows to read zic-compiled binary db"
patch_type: "portability"
patch_source: "https://github.com/HowardHinnant/date/pull/611"
Original file line number Diff line number Diff line change
@@ -0,0 +1,359 @@
From 7505317a4b5397f70e9007c871a73245a4f60417 Mon Sep 17 00:00:00 2001
From: John McCann Cunniff Jr <[email protected]>
Date: Tue, 20 Oct 2020 12:54:56 -0400
Subject: [PATCH] ADD windows support for USE_SYSTEM_TZ_DB

---
CMakeLists.txt | 23 ++++---
include/date/tz.h | 3 -
src/tz.cpp | 170 ++++++++++++++++++++++++++++++++++++----------
3 files changed, 149 insertions(+), 47 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7bc93df..ac989c8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -23,6 +23,7 @@ function( print_option OPT )
endfunction( )

print_option( USE_SYSTEM_TZ_DB )
+print_option( MANUAL_TZ_DB )
print_option( USE_TZ_DB_IN_DOT )
print_option( BUILD_SHARED_LIBS )
print_option( ENABLE_DATE_TESTING )
@@ -45,20 +46,26 @@ set( HEADER_FILES

add_library( tz ${HEADER_FILES} ${SOURCE_FOLDER}/tz.cpp )

-if( USE_SYSTEM_TZ_DB )
+if( USE_SYSTEM_TZ_DB OR MANUAL_TZ_DB )
target_compile_definitions( tz PRIVATE -DUSE_AUTOLOAD=0 )
target_compile_definitions( tz PRIVATE -DHAS_REMOTE_API=0 )
- # cannot set USE_OS_TZDB to 1 on Windows
- if( NOT WIN32 )
- target_compile_definitions( tz PUBLIC -DUSE_OS_TZDB=1 )
- endif( )
else( )
target_compile_definitions( tz PRIVATE -DUSE_AUTOLOAD=1 )
target_compile_definitions( tz PRIVATE -DHAS_REMOTE_API=1 )
- target_compile_definitions( tz PUBLIC -DUSE_OS_TZDB=0 )
- find_package( CURL REQUIRED )
+endif( )
+
+if ( USE_SYSTEM_TZ_DB AND NOT MANUAL_TZ_DB )
+ target_compile_definitions( tz PRIVATE -DINSTALL=. )
+ target_compile_definitions( tz PUBLIC -DUSE_OS_TZDB=1 )
+else( )
+ target_compile_definitions( tz PUBLIC USE_OS_TZDB=0 )
+endif( )
+
+if( NOT USE_SYSTEM_TZ_DB AND NOT MANUAL_TZ_DB )
+ find_package( CURL REQUIRED )
+ include_directories( SYSTEM ${CURL_INCLUDE_DIRS} )
set( OPTIONAL_LIBRARIES CURL::libcurl )
-endif()
+endif( )

if( BUILD_SHARED_LIBS )
target_compile_definitions( tz PRIVATE -DDATE_BUILD_DLL=1 )
diff --git a/include/date/tz.h b/include/date/tz.h
index 9840e7b..53f4a56 100644
--- a/include/date/tz.h
+++ b/include/date/tz.h
@@ -83,9 +83,6 @@ static_assert(HAS_REMOTE_API == 0 ? AUTO_DOWNLOAD == 0 : true,
#endif

#if USE_OS_TZDB
-# ifdef _WIN32
-# error "USE_OS_TZDB can not be used on Windows"
-# endif
# ifndef MISSING_LEAP_SECONDS
# ifdef __APPLE__
# define MISSING_LEAP_SECONDS 1
diff --git a/src/tz.cpp b/src/tz.cpp
index f4a819b..0cde872 100644
--- a/src/tz.cpp
+++ b/src/tz.cpp
@@ -81,6 +81,10 @@
# endif // __MINGW32__

# include <windows.h>
+# include <regex>
+# if !defined(S_ISDIR) && defined(S_IFMT) && defined(_S_IFDIR)
+# define S_ISDIR(m) (((m) & S_IFMT) == _S_IFDIR)
+# endif
#endif // _WIN32

#include "date/tz_private.h"
@@ -92,7 +96,12 @@
#endif

#if USE_OS_TZDB
-# include <dirent.h>
+# if !WIN32
+# include <dirent.h>
+# else
+# include <windef.h>
+# include <fstream>
+# endif
#endif
#include <algorithm>
#include <cctype>
@@ -276,6 +285,14 @@ access_install()
#undef STRINGIZE
#endif // !INSTALL

+ {
+ static char* tz_local_env = getenv("TZDATA");
+ if (tz_local_env != nullptr) {
+ static std::string tz_local_env_s = tz_local_env;
+ return tz_local_env_s;
+ }
+ }
+
return install;
}

@@ -318,7 +335,6 @@ CONSTCD14 const sys_seconds min_seconds = sys_days(min_year/min_day);

#endif // USE_OS_TZDB

-#ifndef _WIN32

static
std::string
@@ -330,6 +346,16 @@ discover_tz_dir()
CONSTDATA auto tz_dir_default = "/usr/share/zoneinfo";
CONSTDATA auto tz_dir_buildroot = "/usr/share/zoneinfo/uclibc";

+ {
+ // TZDIR is from the posix naming
+ // https://man7.org/linux/man-pages/man3/tzset.3.html
+ static char* tz_local_env = getenv("TZDATA");
+ if (tz_local_env != nullptr) {
+ static std::string tz_local_env_s = tz_local_env;
+ return tz_local_env_s;
+ }
+ }
+
// Check special path which is valid for buildroot with uclibc builds
if(stat(tz_dir_buildroot, &sb) == 0 && S_ISDIR(sb.st_mode))
return tz_dir_buildroot;
@@ -369,7 +395,6 @@ get_tz_dir()
return tz_dir;
}

-#endif

// +-------------------+
// | End Configuration |
@@ -443,7 +468,31 @@ get_tzdb_list()
return tz_db;
}

-#if !USE_OS_TZDB
+static
+std::string
+parse3(std::istream& in)
+{
+ std::string r(3, ' ');
+ ws(in);
+ r[0] = static_cast<char>(in.get());
+ r[1] = static_cast<char>(in.get());
+ r[2] = static_cast<char>(in.get());
+ return r;
+}
+
+static
+unsigned
+parse_month(std::istream& in)
+{
+ CONSTDATA char*const month_names[] =
+ {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+ auto s = parse3(in);
+ auto m = std::find(std::begin(month_names), std::end(month_names), s) - month_names;
+ if (m >= std::end(month_names) - std::begin(month_names))
+ throw std::runtime_error("oops: bad month name: " + s);
+ return static_cast<unsigned>(++m);
+}

#ifdef _WIN32

@@ -655,19 +704,9 @@ load_timezone_mappings_from_xml_file(const std::string& input_path)

#endif // _WIN32

-// Parsing helpers

-static
-std::string
-parse3(std::istream& in)
-{
- std::string r(3, ' ');
- ws(in);
- r[0] = static_cast<char>(in.get());
- r[1] = static_cast<char>(in.get());
- r[2] = static_cast<char>(in.get());
- return r;
-}
+#if !USE_OS_TZDB
+// Parsing helpers

static
unsigned
@@ -682,20 +721,6 @@ parse_dow(std::istream& in)
return static_cast<unsigned>(dow);
}

-static
-unsigned
-parse_month(std::istream& in)
-{
- CONSTDATA char*const month_names[] =
- {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
- auto s = parse3(in);
- auto m = std::find(std::begin(month_names), std::end(month_names), s) - month_names;
- if (m >= std::end(month_names) - std::begin(month_names))
- throw std::runtime_error("oops: bad month name: " + s);
- return static_cast<unsigned>(++m);
-}
-
static
std::chrono::seconds
parse_unsigned_time(std::istream& in)
@@ -1710,9 +1735,15 @@ time_zone::time_zone(const std::string& s, detail::undocumented)

enum class endian
{
- native = __BYTE_ORDER__,
+#ifdef _WIN32
+ little = 0,
+ big = 1,
+ native = little
+#else
little = __ORDER_LITTLE_ENDIAN__,
- big = __ORDER_BIG_ENDIAN__
+ big = __ORDER_BIG_ENDIAN__,
+ native = __BYTE_ORDER__
+#endif
};

static
@@ -2018,8 +2049,10 @@ time_zone::init_impl()
{
using namespace std;
using namespace std::chrono;
- auto name = get_tz_dir() + ('/' + name_);
- std::ifstream inf(name);
+ auto name = get_tz_dir() + (folder_delimiter + name_);
+ // Some platforms will open the inf stream in text mode. Specify binary
+ // to avoid confusion.
+ std::ifstream inf(name, std::ios::in | std::ios::binary);
if (!inf.is_open())
throw std::runtime_error{"Unable to open " + name};
inf.exceptions(std::ios::failbit | std::ios::badbit);
@@ -2630,8 +2663,10 @@ init_tzdb()
//Iterate through folders
std::queue<std::string> subfolders;
subfolders.emplace(get_tz_dir());
- struct dirent* d;
+
struct stat s;
+#if !WIN32 // !WIN32
+ struct dirent* d;
while (!subfolders.empty())
{
auto dirname = std::move(subfolders.front());
@@ -2648,8 +2683,11 @@ init_tzdb()
strcmp(d->d_name, "iso3166.tab") == 0 ||
strcmp(d->d_name, "right") == 0 ||
strcmp(d->d_name, "+VERSION") == 0 ||
+ strcmp(d->d_name, "version") == 0 ||
strcmp(d->d_name, "zone.tab") == 0 ||
strcmp(d->d_name, "zone1970.tab") == 0 ||
+ strcmp(d->d_name, "tzdata.zi") == 0 ||
+ strcmp(d->d_name, "leapseconds") == 0 ||
strcmp(d->d_name, "leap-seconds.list") == 0 )
continue;
auto subname = dirname + folder_delimiter + d->d_name;
@@ -2671,6 +2709,56 @@ init_tzdb()
}
closedir(dir);
}
+#else // WIN32
+ // POSIX dirent is not availible in Visual C++
+ // Use Windows file API instead
+ WIN32_FIND_DATA hFindData;
+ while (!subfolders.empty())
+ {
+ auto dirname = std::move(subfolders.front());
+ subfolders.pop();
+ HANDLE hFind = FindFirstFile((dirname + "\\\\*").c_str(), &hFindData);
+ if (hFind == INVALID_HANDLE_VALUE)
+ {
+ continue;
+ }
+
+ do
+ {
+ // Ignore these files:
+ if (hFindData.cFileName[0] == '.' || // curdir, prevdir, hidden
+ memcmp(hFindData.cFileName, "posix", 5) == 0 || // starts with posix
+ strcmp(hFindData.cFileName, "Factory") == 0 ||
+ strcmp(hFindData.cFileName, "iso3166.tab") == 0 ||
+ strcmp(hFindData.cFileName, "right") == 0 ||
+ strcmp(hFindData.cFileName, "+VERSION") == 0 ||
+ strcmp(hFindData.cFileName, "zone.tab") == 0 ||
+ strcmp(hFindData.cFileName, "zone1970.tab") == 0 ||
+ strcmp(hFindData.cFileName, "tzdata.zi") == 0 ||
+ strcmp(hFindData.cFileName, "leapseconds") == 0 ||
+ strcmp(hFindData.cFileName, "leap-seconds.list") == 0 )
+ {
+ continue;
+ }
+ auto subname = dirname + folder_delimiter + hFindData.cFileName;
+ if(stat(subname.c_str(), &s) == 0)
+ {
+ if(S_ISDIR(s.st_mode))
+ {
+ subfolders.push(subname);
+ }
+ else
+ {
+ std::string zone = subname.substr(get_tz_dir().size()+1);
+ db->zones.emplace_back(zone,
+ detail::undocumented{});
+ }
+ }
+ }
+ while (FindNextFile(hFind, &hFindData ));
+ FindClose(hFind);
+ }
+#endif // WIN32
db->zones.shrink_to_fit();
std::sort(db->zones.begin(), db->zones.end());
# if !MISSING_LEAP_SECONDS
@@ -3528,7 +3616,17 @@ locate_zone(std::string_view tz_name)
locate_zone(const std::string& tz_name)
#endif
{
- return get_tzdb().locate_zone(tz_name);
+ return get_tzdb().locate_zone(
+#if WIN32 && USE_OS_TZDB
+ // When USE_OS_TZDB=ON, the tz_name needs to be a valid path.
+ // For timezone labeling consistency in Windows, switch "/" to "\".
+ // This will allow for tz_name to have consistent naming regardless of
+ // if USE_OS_TZDB is ON.
+ std::regex_replace(tz_name, std::regex("\\/"), "\\")
+#else
+ tz_name
+#endif
+ );
}

#if USE_OS_TZDB
--
2.24.3 (Apple Git-128)

Loading

0 comments on commit 7a12d26

Please sign in to comment.