mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 00:47:45 +00:00
LibC: Implement tzset with time zone awareness in accordance with POSIX
This commit is contained in:
parent
6095500263
commit
b1ea585149
2 changed files with 100 additions and 5 deletions
|
@ -10,6 +10,25 @@
|
||||||
|
|
||||||
const auto expected_epoch = "Thu Jan 1 00:00:00 1970\n"sv;
|
const auto expected_epoch = "Thu Jan 1 00:00:00 1970\n"sv;
|
||||||
|
|
||||||
|
class TimeZoneGuard {
|
||||||
|
public:
|
||||||
|
TimeZoneGuard()
|
||||||
|
: m_tz(getenv("TZ"))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~TimeZoneGuard()
|
||||||
|
{
|
||||||
|
if (m_tz)
|
||||||
|
setenv("TZ", m_tz, 1);
|
||||||
|
else
|
||||||
|
unsetenv("TZ");
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
char const* m_tz { nullptr };
|
||||||
|
};
|
||||||
|
|
||||||
TEST_CASE(asctime)
|
TEST_CASE(asctime)
|
||||||
{
|
{
|
||||||
time_t epoch = 0;
|
time_t epoch = 0;
|
||||||
|
@ -41,3 +60,48 @@ TEST_CASE(ctime_r)
|
||||||
|
|
||||||
EXPECT_EQ(expected_epoch, StringView(result));
|
EXPECT_EQ(expected_epoch, StringView(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE(tzset)
|
||||||
|
{
|
||||||
|
TimeZoneGuard guard;
|
||||||
|
|
||||||
|
auto set_tz = [](char const* tz) {
|
||||||
|
setenv("TZ", tz, 1);
|
||||||
|
tzset();
|
||||||
|
};
|
||||||
|
|
||||||
|
set_tz("UTC");
|
||||||
|
EXPECT_EQ(timezone, 0);
|
||||||
|
EXPECT_EQ(altzone, 0);
|
||||||
|
EXPECT_EQ(daylight, 0);
|
||||||
|
EXPECT_EQ(tzname[0], "UTC"sv);
|
||||||
|
EXPECT_EQ(tzname[1], "UTC"sv);
|
||||||
|
|
||||||
|
set_tz("America/New_York");
|
||||||
|
EXPECT_EQ(timezone, 5 * 60 * 60);
|
||||||
|
EXPECT_EQ(altzone, 4 * 60 * 60);
|
||||||
|
EXPECT_EQ(daylight, 1);
|
||||||
|
EXPECT_EQ(tzname[0], "EST"sv);
|
||||||
|
EXPECT_EQ(tzname[1], "EDT"sv);
|
||||||
|
|
||||||
|
set_tz("America/Phoenix");
|
||||||
|
EXPECT_EQ(timezone, 7 * 60 * 60);
|
||||||
|
EXPECT_EQ(altzone, 7 * 60 * 60);
|
||||||
|
EXPECT_EQ(daylight, 0);
|
||||||
|
EXPECT_EQ(tzname[0], "MST"sv);
|
||||||
|
EXPECT_EQ(tzname[1], "MST"sv);
|
||||||
|
|
||||||
|
set_tz("America/Asuncion");
|
||||||
|
EXPECT_EQ(timezone, 4 * 60 * 60);
|
||||||
|
EXPECT_EQ(altzone, 3 * 60 * 60);
|
||||||
|
EXPECT_EQ(daylight, 1);
|
||||||
|
EXPECT_EQ(tzname[0], "-04"sv);
|
||||||
|
EXPECT_EQ(tzname[1], "-03"sv);
|
||||||
|
|
||||||
|
set_tz("CET");
|
||||||
|
EXPECT_EQ(timezone, -1 * 60 * 60);
|
||||||
|
EXPECT_EQ(altzone, -2 * 60 * 60);
|
||||||
|
EXPECT_EQ(daylight, 1);
|
||||||
|
EXPECT_EQ(tzname[0], "CET"sv);
|
||||||
|
EXPECT_EQ(tzname[1], "CEST"sv);
|
||||||
|
}
|
||||||
|
|
|
@ -11,7 +11,9 @@
|
||||||
#include <LibTimeZone/TimeZone.h>
|
#include <LibTimeZone/TimeZone.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <sys/times.h>
|
#include <sys/times.h>
|
||||||
|
@ -358,15 +360,44 @@ long altzone;
|
||||||
char* tzname[2];
|
char* tzname[2];
|
||||||
int daylight;
|
int daylight;
|
||||||
|
|
||||||
|
static char __tzname_standard[TZNAME_MAX];
|
||||||
|
static char __tzname_daylight[TZNAME_MAX];
|
||||||
constexpr const char* __utc = "UTC";
|
constexpr const char* __utc = "UTC";
|
||||||
|
|
||||||
void tzset()
|
void tzset()
|
||||||
{
|
{
|
||||||
// FIXME: Here we pretend we are in UTC+0.
|
// FIXME: Actually parse the TZ environment variable, described here:
|
||||||
|
// https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08
|
||||||
|
StringView time_zone;
|
||||||
|
|
||||||
|
if (char* tz = getenv("TZ"); tz != nullptr)
|
||||||
|
time_zone = tz;
|
||||||
|
else
|
||||||
|
time_zone = TimeZone::current_time_zone();
|
||||||
|
|
||||||
|
auto set_default_values = []() {
|
||||||
timezone = 0;
|
timezone = 0;
|
||||||
|
altzone = 0;
|
||||||
daylight = 0;
|
daylight = 0;
|
||||||
tzname[0] = const_cast<char*>(__utc);
|
tzname[0] = const_cast<char*>(__utc);
|
||||||
tzname[1] = const_cast<char*>(__utc);
|
tzname[1] = const_cast<char*>(__utc);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (auto offsets = TimeZone::get_named_time_zone_offsets(time_zone, AK::Time::now_realtime()); offsets.has_value()) {
|
||||||
|
if (!offsets->at(0).name.copy_characters_to_buffer(__tzname_standard, TZNAME_MAX))
|
||||||
|
return set_default_values();
|
||||||
|
if (!offsets->at(1).name.copy_characters_to_buffer(__tzname_daylight, TZNAME_MAX))
|
||||||
|
return set_default_values();
|
||||||
|
|
||||||
|
// timezone and altzone are seconds west of UTC, i.e. the offsets are negated.
|
||||||
|
timezone = -offsets->at(0).seconds;
|
||||||
|
altzone = -offsets->at(1).seconds;
|
||||||
|
daylight = timezone != altzone;
|
||||||
|
tzname[0] = __tzname_standard;
|
||||||
|
tzname[1] = __tzname_daylight;
|
||||||
|
} else {
|
||||||
|
set_default_values();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clock_t clock()
|
clock_t clock()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue