Skip to content

Commit 37ae9c4

Browse files
author
Зишан Мирза
committed
timezone implementation
1 parent f450da7 commit 37ae9c4

File tree

7 files changed

+270
-23
lines changed

7 files changed

+270
-23
lines changed

libc/src/time/CMakeLists.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,18 @@ add_object_library(
1414
libc.src.errno.errno
1515
)
1616

17+
add_object_library(
18+
timezone
19+
SRCS
20+
timezone.cpp
21+
HDRS
22+
timezone.h
23+
DEPENDS
24+
libc.include.time
25+
libc.src.__support.CPP.limits
26+
libc.src.errno.errno
27+
)
28+
1729
add_entrypoint_object(
1830
asctime
1931
SRCS
@@ -68,6 +80,7 @@ add_entrypoint_object(
6880
localtime.h
6981
DEPENDS
7082
.time_utils
83+
.timezone
7184
libc.hdr.types.time_t
7285
libc.include.time
7386
)

libc/src/time/time_utils.cpp

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,13 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "src/time/time_utils.h"
10+
#include "src/time/timezone.h"
1011
#include "src/__support/CPP/limits.h" // INT_MIN, INT_MAX
1112
#include "src/__support/common.h"
1213
#include "src/__support/macros/config.h"
14+
#include "src/__support/CPP/string_view.h"
1315
#include <stdio.h>
16+
#include <stdlib.h>
1417

1518
namespace LIBC_NAMESPACE_DECL {
1619
namespace time_utils {
@@ -29,9 +32,10 @@ static int64_t computeRemainingYears(int64_t daysPerYears,
2932

3033
volatile int file_usage = 0;
3134

32-
void release_file(FILE *fp) {
35+
void release_file(FILE *fp, char *timezone) {
3336
file_usage = 0;
3437
fclose(fp);
38+
free(timezone);
3539
}
3640

3741
void acquire_file(FILE *fp, char *timezone, size_t timezone_size) {
@@ -43,7 +47,7 @@ void acquire_file(FILE *fp, char *timezone, size_t timezone_size) {
4347
}
4448

4549
if (fgets(timezone, (int)timezone_size, fp) == NULL) {
46-
release_file(fp);
50+
release_file(fp, timezone);
4751
}
4852
}
4953

@@ -150,27 +154,25 @@ int64_t update_from_seconds(int64_t total_seconds, struct tm *tm) {
150154
if (years > INT_MAX || years < INT_MIN)
151155
return time_utils::out_of_range();
152156

153-
char timezone[TimeConstants::TIMEZONE_SIZE];
154-
157+
char *timezone = (char *)malloc(sizeof(char) * TimeConstants::TIMEZONE_SIZE);
158+
timezone = getenv("TZ");
155159
FILE *fp = NULL;
156-
fp = fopen("/etc/timezone", "rb");
157-
if (fp == NULL) {
158-
// TODO: implement getting timezone from `TZ` environment variable and
159-
// storing the value in `timezone`
160-
} else {
160+
if (timezone == NULL) {
161+
timezone = (char *)realloc(timezone, sizeof(char) * TimeConstants::TIMEZONE_SIZE);
162+
fp = fopen("/etc/timezone", "rb");
163+
if (fp == NULL) {
164+
return time_utils::out_of_range();
165+
}
166+
161167
acquire_file(fp, timezone, TimeConstants::TIMEZONE_SIZE);
162168
}
163169

164-
if (file_usage == 0) {
165-
release_file(fp);
170+
if (fp != NULL && file_usage == 0) {
171+
release_file(fp, timezone);
166172
return time_utils::out_of_range();
167173
}
168174

169-
// UTC = 0
170-
int offset = 0;
171-
// TODO: Add more timezones
172-
if (internal::same_string(timezone, "Europe/Berlin") == 0)
173-
offset = 1;
175+
int offset = timezone::get_timezone_offset(timezone);
174176

175177
// All the data (years, month and remaining days) was calculated from
176178
// March, 2000. Thus adjust the data to be from January, 1900.
@@ -189,12 +191,17 @@ int64_t update_from_seconds(int64_t total_seconds, struct tm *tm) {
189191
static_cast<int>(remainingSeconds % TimeConstants::SECONDS_PER_MIN);
190192

191193
set_dst(tm);
192-
if (tm->tm_isdst > 0) {
194+
if (tm->tm_isdst > 0 && offset != 0) {
193195
tm->tm_hour += 1;
194196
}
195-
tm->tm_hour += offset;
196197

197-
release_file(fp);
198+
if (offset != 0) {
199+
tm->tm_hour += offset;
200+
}
201+
202+
if (file_usage == 1) {
203+
release_file(fp, timezone);
204+
}
198205

199206
return 0;
200207
}

libc/src/time/timezone.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
//===-- Implementation of timezone functions ------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "src/time/time_utils.h"
10+
#include "src/time/timezone.h"
11+
#include "src/__support/CPP/limits.h" // INT_MIN, INT_MAX
12+
#include "src/__support/common.h"
13+
#include "src/__support/macros/config.h"
14+
#include "src/__support/CPP/string_view.h"
15+
16+
#define BUF_SIZE 1024
17+
18+
namespace LIBC_NAMESPACE_DECL {
19+
namespace timezone {
20+
21+
using LIBC_NAMESPACE::time_utils::TimeConstants;
22+
23+
#include <stdio.h>
24+
#include <stdlib.h>
25+
26+
int get_timezone_offset(char *timezone) {
27+
int offset = 0;
28+
LIBC_NAMESPACE::cpp::string_view tz(timezone);
29+
30+
if (tz.starts_with("America")) {
31+
if (tz.ends_with("San_Francisco")) {
32+
offset = -8;
33+
}
34+
35+
if (tz.starts_with("America/New_York")) {
36+
offset = -5;
37+
}
38+
}
39+
40+
if (tz.starts_with("Europe")) {
41+
offset = 1;
42+
43+
if (tz.ends_with("Moscow")) {
44+
offset = 2;
45+
}
46+
}
47+
48+
return offset;
49+
}
50+
51+
} // namespace timezone
52+
} // namespace LIBC_NAMESPACE_DECL

libc/src/time/timezone.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//===-- Implementation of timezone functions ------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_LIBC_SRC_TIME_TIMEZONE_H
10+
#define LLVM_LIBC_SRC_TIME_TIMEZONE_H
11+
12+
#include <stddef.h> // For size_t.
13+
14+
#include "src/__support/CPP/limits.h"
15+
#include "src/__support/common.h"
16+
#include "src/__support/macros/config.h"
17+
#include "src/__support/CPP/string_view.h"
18+
#include "src/errno/libc_errno.h"
19+
#include "src/time/mktime.h"
20+
21+
#include <stdint.h>
22+
23+
namespace LIBC_NAMESPACE_DECL {
24+
namespace timezone {
25+
26+
#define TZ_HEADER "TZif"
27+
28+
extern int get_timezone_offset(char *timezone);
29+
30+
} // namespace timezone
31+
} // namespace LIBC_NAMESPACE_DECL
32+
33+
#endif // LLVM_LIBC_SRC_TIME_TIMEZONE_H

libc/test/src/time/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ add_libc_unittest(
4646
libc.hdr.types.time_t
4747
libc.src.time.ctime
4848
libc.src.time.time_utils
49+
libc.src.time.timezone
4950
)
5051

5152
add_libc_unittest(
@@ -64,6 +65,7 @@ add_libc_unittest(
6465
libc.hdr.types.time_t
6566
libc.src.time.ctime_r
6667
libc.src.time.time_utils
68+
libc.src.time.timezone
6769
)
6870

6971
add_libc_unittest(
@@ -82,6 +84,7 @@ add_libc_unittest(
8284
libc.hdr.types.time_t
8385
libc.src.time.localtime
8486
libc.src.time.time_utils
87+
libc.src.time.timezone
8588
)
8689

8790
add_libc_unittest(
@@ -100,6 +103,7 @@ add_libc_unittest(
100103
libc.hdr.types.time_t
101104
libc.src.time.localtime_r
102105
libc.src.time.time_utils
106+
libc.src.time.timezone
103107
)
104108

105109
add_libc_unittest(
@@ -118,6 +122,7 @@ add_libc_unittest(
118122
libc.hdr.types.time_t
119123
libc.src.time.localtime_s
120124
libc.src.time.time_utils
125+
libc.src.time.timezone
121126
)
122127

123128
add_libc_test(

libc/test/src/time/localtime_r_test.cpp

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,27 @@
99
#include "src/time/localtime_r.h"
1010
#include "src/time/time_utils.h"
1111
#include "test/UnitTest/Test.h"
12-
#include "test/src/time/TmHelper.h"
1312

14-
using LIBC_NAMESPACE::time_utils::TimeConstants;
13+
#include <string.h>
14+
15+
extern char **environ;
16+
17+
void set_env_var(const char* env) {
18+
int i = 0;
19+
if (environ[i] != NULL) {
20+
i++;
21+
}
22+
23+
environ[i] = (char*)malloc(strlen(env)+1);
24+
if (environ[i] != nullptr) {
25+
memcpy(environ[i], env, strlen(env)+1);
26+
environ[i+1] = nullptr;
27+
}
28+
}
1529

1630
TEST(LlvmLibcLocaltimeR, ValidUnixTimestamp0) {
31+
set_env_var("TZ=Europe/Berlin");
32+
1733
struct tm input;
1834
time_t t_ptr = 0;
1935
struct tm *result = LIBC_NAMESPACE::localtime_r(&t_ptr, &input);
@@ -40,6 +56,8 @@ TEST(LlvmLibcLocaltimeR, ValidUnixTimestamp0) {
4056
}
4157

4258
TEST(LlvmLibcLocaltimeR, ValidUnixTimestamp32Int) {
59+
set_env_var("TZ=Europe/Berlin");
60+
4361
time_t t_ptr = 2147483647;
4462
struct tm input = (struct tm){.tm_sec = 0,
4563
.tm_min = 0,
@@ -74,6 +92,8 @@ TEST(LlvmLibcLocaltimeR, ValidUnixTimestamp32Int) {
7492
}
7593

7694
TEST(LlvmLibcLocaltimeR, ValidUnixTimestamp32IntDst) {
95+
set_env_var("TZ=Europe/Berlin");
96+
7797
time_t t_ptr = 1627225465;
7898
struct tm input = (struct tm){.tm_sec = 0,
7999
.tm_min = 0,

0 commit comments

Comments
 (0)