Add rfc_2822_date().
authorCarl Hetherington <cth@carlh.net>
Tue, 7 Jan 2025 19:46:02 +0000 (20:46 +0100)
committerCarl Hetherington <cth@carlh.net>
Thu, 9 Jan 2025 19:56:26 +0000 (20:56 +0100)
src/lib/util.cc
src/lib/util.h
test/util_test.cc

index 14839d80d4d06a5f4a5e70e828ff1abe0702d6a5..5b0c25cda12680052cff8f88e2334011c6de16dd 100644 (file)
@@ -78,8 +78,10 @@ LIBDCP_ENABLE_WARNINGS
 #include <unicode/unistr.h>
 #include <unicode/translit.h>
 #include <unicode/brkiter.h>
+#include <fmt/chrono.h>
 #include <fmt/format.h>
 #include <boost/algorithm/string.hpp>
+#include <boost/date_time/c_local_time_adjustor.hpp>
 #include <boost/range/algorithm/replace_if.hpp>
 #include <boost/thread.hpp>
 #include <boost/filesystem.hpp>
@@ -1207,3 +1209,20 @@ join_strings(vector<string> const& in, string const& separator)
        });
 }
 
+
+string
+rfc_2822_date(time_t time)
+{
+       auto const utc_now = boost::posix_time::second_clock::universal_time ();
+       auto const local_now = boost::date_time::c_local_adjustor<boost::posix_time::ptime>::utc_to_local (utc_now);
+       auto const offset = local_now - utc_now;
+
+       auto const hours = int(abs(offset.hours()));
+
+       auto tm = localtime(&time);
+
+       /* I tried using %z in the time formatter but it gave results like "Pacific Standard Time" instead +0800 on Windows */
+       return fmt::format("{:%a, %d %b %Y %H:%M:%S} {}{:02d}{:02d}", *tm, offset.hours() >= 0 ? "+" : "-", hours, int(offset.minutes()));
+}
+
+
index eaa705f5ee791b63c210a5b9d6c95db2bd953f6a..e70d6f90f27c55c52887ae0e3b053c7a6e44c2b3 100644 (file)
@@ -102,6 +102,7 @@ extern void capture_ffmpeg_logs();
 extern void setup_grok_library_path();
 #endif
 extern std::string join_strings(std::vector<std::string> const& in, std::string const& separator = " ");
+extern std::string rfc_2822_date(time_t time);
 
 
 template <class T>
index afcc4cfc9cb684e8a246bbf646de3d72c720d96a..f50a1620e22090fae73335117da7229a2f6ce49b 100644 (file)
 #include "lib/exceptions.h"
 #include "test.h"
 #include <dcp/certificate_chain.h>
-#include <boost/test/unit_test.hpp>
+#include <fmt/format.h>
 #include <boost/bind/bind.hpp>
+#include <boost/date_time/c_local_time_adjustor.hpp>
+#include <boost/test/unit_test.hpp>
+
 
 
 using std::list;
@@ -166,3 +169,58 @@ BOOST_AUTO_TEST_CASE(screen_names_to_string_test)
        BOOST_CHECK_EQUAL(screen_names_to_string({"Sheila", "Fred", "Jim", "1"}), "1, Fred, Jim, Sheila");
 }
 
+
+BOOST_AUTO_TEST_CASE(rfc_2822_date_test)
+{
+#ifdef DCPOMATIC_WINDOWS
+       auto result = setlocale(LC_TIME, "German");
+#endif
+#ifdef DCPOMATIC_OSX
+       auto result = setlocale(LC_TIME, "de_DE");
+#endif
+#ifdef DCPOMATIC_LINUX
+       auto result = setlocale(LC_TIME, "de_DE.UTF8");
+#endif
+       BOOST_REQUIRE(result);
+
+       auto const utc_now = boost::posix_time::second_clock::universal_time ();
+       auto const local_now = boost::date_time::c_local_adjustor<boost::posix_time::ptime>::utc_to_local (utc_now);
+       auto const offset = local_now - utc_now;
+
+       auto const hours = int(abs(offset.hours()));
+       auto const tz = fmt::format("{}{:02d}{:02d}", offset.hours() >= 0 ? "+" : "-", hours, int(offset.minutes()));
+
+       int constexpr day = 24 * 60 * 60;
+
+       /* This won't pass when running in all time zones, but it's really the overall format (and in particular
+        * the use of English for day and month names) that we want to check.
+        */
+
+       auto check_allowing_dst = [hours, tz](int day_index, string format) {
+               auto test = rfc_2822_date(day_index * day);
+               BOOST_CHECK(
+                       test == fmt::format(format, hours, tz) ||
+                       test == fmt::format(format, hours + 1, tz)
+               );
+       };
+
+       check_allowing_dst(0, "Thu, 01 Jan 1970 {:02d}:00:00 {}");
+       check_allowing_dst(1, "Fri, 02 Jan 1970 {:02d}:00:00 {}");
+       check_allowing_dst(2, "Sat, 03 Jan 1970 {:02d}:00:00 {}");
+       check_allowing_dst(3, "Sun, 04 Jan 1970 {:02d}:00:00 {}");
+       check_allowing_dst(4, "Mon, 05 Jan 1970 {:02d}:00:00 {}");
+       check_allowing_dst(5, "Tue, 06 Jan 1970 {:02d}:00:00 {}");
+       check_allowing_dst(6, "Wed, 07 Jan 1970 {:02d}:00:00 {}");
+       check_allowing_dst(39, "Mon, 09 Feb 1970 {:02d}:00:00 {}");
+       check_allowing_dst(89, "Tue, 31 Mar 1970 {:02d}:00:00 {}");
+       check_allowing_dst(109, "Mon, 20 Apr 1970 {:02d}:00:00 {}");
+       check_allowing_dst(134, "Fri, 15 May 1970 {:02d}:00:00 {}");
+       check_allowing_dst(158, "Mon, 08 Jun 1970 {:02d}:00:00 {}");
+       check_allowing_dst(182, "Thu, 02 Jul 1970 {:02d}:00:00 {}");
+       check_allowing_dst(221, "Mon, 10 Aug 1970 {:02d}:00:00 {}");
+       check_allowing_dst(247, "Sat, 05 Sep 1970 {:02d}:00:00 {}");
+       check_allowing_dst(300, "Wed, 28 Oct 1970 {:02d}:00:00 {}");
+       check_allowing_dst(314, "Wed, 11 Nov 1970 {:02d}:00:00 {}");
+       check_allowing_dst(363, "Wed, 30 Dec 1970 {:02d}:00:00 {}");
+}
+