Skip to content

Commit 55cc7f5

Browse files
authored
Transport ZonedDateTimes (#76)
Encode and decode ZonedDateTime types, both those with numeric based offsets (such as 60 minutes), and named timezones (such as [America/New_York].) Technically, a struct has been changed that would be breaking, but as this couldn't be used in transport we know that no clients were actually using it. This also updates the version to 1.5.0.
1 parent 0f6968c commit 55cc7f5

File tree

10 files changed

+129
-26
lines changed

10 files changed

+129
-26
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ if(WASM)
1919
set(CMAKE_TOOLCHAIN_FILE "${CMAKE_SOURCE_DIR}/wasm/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake")
2020
endif()
2121

22-
project(mgclient VERSION 1.4.6)
22+
project(mgclient VERSION 1.5.0)
2323
# Minor version increase can also mean ABI incompatibility with previous
2424
# versions. IMPORTANT: Take care of the SO version manually.
2525
set(mgclient_SOVERSION 2)

include/mgclient.h

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -946,9 +946,9 @@ mg_date_time_zone_id_seconds(const mg_date_time_zone_id *date_time_zone_id);
946946
MGCLIENT_EXPORT int64_t
947947
mg_date_time_zone_id_nanoseconds(const mg_date_time_zone_id *date_time_zone_id);
948948

949-
/// Returns time zone represented by the identifier.
950-
MGCLIENT_EXPORT int64_t
951-
mg_date_time_zone_id_tz_id(const mg_date_time_zone_id *date_time_zone_id);
949+
/// Returns time zone name.
950+
MGCLIENT_EXPORT const mg_string *mg_date_time_zone_id_timezone_name(
951+
const mg_date_time_zone_id *date_time_zone_id);
952952

953953
/// Creates a copy of the given date and time.
954954
///
@@ -960,6 +960,17 @@ MGCLIENT_EXPORT mg_date_time_zone_id *mg_date_time_zone_id_copy(
960960
MGCLIENT_EXPORT void mg_date_time_zone_id_destroy(
961961
mg_date_time_zone_id *date_time_zone_id);
962962

963+
/// Creates mg_date_time from seconds, nanoseconds and timezone offset.
964+
/// \return a pointer to mg_date_time or NULL if an error occurred.
965+
MGCLIENT_EXPORT mg_date_time *mg_date_time_make(int64_t seconds,
966+
int64_t nanoseconds,
967+
int32_t tz_offset_minutes);
968+
969+
/// Creates mg_date_time_zone_id from seconds, nanoseconds, and timezone name.
970+
/// \return a pointer to mg_date_time_zone_id or NULL if an error occurred.
971+
MGCLIENT_EXPORT mg_date_time_zone_id *mg_date_time_zone_id_make(
972+
int64_t seconds, int64_t nanoseconds, const char *timezone_name);
973+
963974
/// Creates mg_local_date_time from seconds and nanoseconds.
964975
/// \return a pointer to mg_local_date_time or NULL if an error occurred.
965976
MGCLIENT_EXPORT mg_local_date_time *mg_local_date_time_make(

mgclient_cpp/include/mgclient-value.hpp

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ TDest MemcpyCast(TSrc src) {
4343
std::memcpy(&dest, &src, sizeof(src));
4444
return dest;
4545
}
46+
4647
} // namespace detail
4748

4849
// Forward declarations:
@@ -1041,7 +1042,10 @@ class DateTimeZoneId final {
10411042
/// Returns nanoseconds since midnight.
10421043
int64_t nanoseconds() const { return mg_date_time_zone_id_nanoseconds(ptr_); }
10431044
/// Returns time zone represented by the identifier.
1044-
int64_t tzId() const { return mg_date_time_zone_id_tz_id(ptr_); }
1045+
std::string_view timezoneName() const {
1046+
const mg_string *name = mg_date_time_zone_id_timezone_name(ptr_);
1047+
return std::string_view{mg_string_data(name), mg_string_size(name)};
1048+
}
10451049

10461050
ConstDateTimeZoneId AsConstDateTimeZoneId() const;
10471051

@@ -1072,7 +1076,10 @@ class ConstDateTimeZoneId final {
10721076
return mg_date_time_zone_id_nanoseconds(const_ptr_);
10731077
}
10741078
/// Returns time zone represented by the identifier.
1075-
int64_t tzId() const { return mg_date_time_zone_id_tz_id(const_ptr_); }
1079+
std::string_view timezoneName() const {
1080+
const mg_string *name = mg_date_time_zone_id_timezone_name(const_ptr_);
1081+
return std::string_view{mg_string_data(name), mg_string_size(name)};
1082+
}
10761083

10771084
bool operator==(const ConstDateTimeZoneId &other) const;
10781085
bool operator==(const DateTimeZoneId &other) const;
@@ -1681,6 +1688,14 @@ inline Value::Type ConvertType(mg_value_type type) {
16811688

16821689
inline bool AreValuesEqual(const mg_value *value1, const mg_value *value2);
16831690

1691+
inline bool AreStringsEqual(const mg_string *s1, const mg_string *s2) {
1692+
if (s1 == s2) return true;
1693+
if (!s1 || !s2) return false;
1694+
return mg_string_size(s1) == mg_string_size(s2) &&
1695+
memcmp(mg_string_data(s1), mg_string_data(s2), mg_string_size(s1)) ==
1696+
0;
1697+
}
1698+
16841699
inline bool AreListsEqual(const mg_list *list1, const mg_list *list2) {
16851700
if (list1 == list2) {
16861701
return true;
@@ -1840,8 +1855,9 @@ inline bool AreDateTimeZoneIdsEqual(
18401855
mg_date_time_zone_id_seconds(date_time_zone_id2) &&
18411856
mg_date_time_zone_id_nanoseconds(date_time_zone_id1) ==
18421857
mg_date_time_zone_id_nanoseconds(date_time_zone_id2) &&
1843-
mg_date_time_zone_id_tz_id(date_time_zone_id1) ==
1844-
mg_date_time_zone_id_tz_id(date_time_zone_id2);
1858+
detail::AreStringsEqual(
1859+
mg_date_time_zone_id_timezone_name(date_time_zone_id1),
1860+
mg_date_time_zone_id_timezone_name(date_time_zone_id2));
18451861
}
18461862

18471863
inline bool AreLocalDateTimesEqual(const mg_local_date_time *local_date_time1,

src/mgsession-decoder.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -714,7 +714,11 @@ int mg_session_read_date_time_zone_id(
714714
goto cleanup;
715715
}
716716

717-
status = mg_session_read_integer(session, &date_time_zone_id_tmp->tz_id);
717+
status =
718+
mg_session_read_string(session, &date_time_zone_id_tmp->timezone_name);
719+
if (status != 0) {
720+
goto cleanup;
721+
}
718722

719723
*date_time_zone_id = date_time_zone_id_tmp;
720724
return 0;

src/mgsession-encoder.c

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,30 @@ int mg_session_write_local_date_time(mg_session *session,
157157
return 0;
158158
}
159159

160+
int mg_session_write_date_time(mg_session *session, const mg_date_time *dt) {
161+
MG_RETURN_IF_FAILED(
162+
mg_session_write_uint8(session, (uint8_t)(MG_MARKER_TINY_STRUCT3)));
163+
MG_RETURN_IF_FAILED(mg_session_write_uint8(session, MG_SIGNATURE_DATE_TIME));
164+
MG_RETURN_IF_FAILED(mg_session_write_integer(session, dt->seconds));
165+
MG_RETURN_IF_FAILED(mg_session_write_integer(session, dt->nanoseconds));
166+
MG_RETURN_IF_FAILED(
167+
mg_session_write_integer(session, dt->tz_offset_minutes * 60));
168+
return 0;
169+
}
170+
171+
int mg_session_write_date_time_zone_id(mg_session *session,
172+
const mg_date_time_zone_id *dtz) {
173+
MG_RETURN_IF_FAILED(
174+
mg_session_write_uint8(session, (uint8_t)(MG_MARKER_TINY_STRUCT3)));
175+
MG_RETURN_IF_FAILED(
176+
mg_session_write_uint8(session, MG_SIGNATURE_DATE_TIME_ZONE_ID));
177+
MG_RETURN_IF_FAILED(mg_session_write_integer(session, dtz->seconds));
178+
MG_RETURN_IF_FAILED(mg_session_write_integer(session, dtz->nanoseconds));
179+
MG_RETURN_IF_FAILED(mg_session_write_string2(
180+
session, dtz->timezone_name->size, dtz->timezone_name->data));
181+
return 0;
182+
}
183+
160184
int mg_session_write_duration(mg_session *session, const mg_duration *dur) {
161185
MG_RETURN_IF_FAILED(
162186
mg_session_write_uint8(session, (uint8_t)(MG_MARKER_TINY_STRUCT4)));
@@ -228,12 +252,10 @@ int mg_session_write_value(mg_session *session, const mg_value *value) {
228252
case MG_VALUE_TYPE_LOCAL_TIME:
229253
return mg_session_write_local_time(session, value->local_time_v);
230254
case MG_VALUE_TYPE_DATE_TIME:
231-
mg_session_set_error(session, "tried to send value of type 'date_time'");
232-
return MG_ERROR_INVALID_VALUE;
255+
return mg_session_write_date_time(session, value->date_time_v);
233256
case MG_VALUE_TYPE_DATE_TIME_ZONE_ID:
234-
mg_session_set_error(session,
235-
"tried to send value of type 'date_time_zone_id'");
236-
return MG_ERROR_INVALID_VALUE;
257+
return mg_session_write_date_time_zone_id(session,
258+
value->date_time_zone_id_v);
237259
case MG_VALUE_TYPE_LOCAL_DATE_TIME:
238260
return mg_session_write_local_date_time(session,
239261
value->local_date_time_v);

src/mgvalue.c

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,9 @@ mg_date_time_zone_id *mg_date_time_zone_id_alloc(mg_allocator *allocator) {
134134
return NULL;
135135
}
136136
mg_date_time_zone_id *date_time_zone_id = (mg_date_time_zone_id *)block;
137+
date_time_zone_id->seconds = 0;
138+
date_time_zone_id->nanoseconds = 0;
139+
date_time_zone_id->timezone_name = NULL;
137140
return date_time_zone_id;
138141
}
139142

@@ -1279,9 +1282,9 @@ int64_t mg_date_time_zone_id_nanoseconds(
12791282
return date_time_zone_id->nanoseconds;
12801283
}
12811284

1282-
int64_t mg_date_time_zone_id_tz_id(
1285+
const mg_string *mg_date_time_zone_id_timezone_name(
12831286
const mg_date_time_zone_id *date_time_zone_id) {
1284-
return date_time_zone_id->tz_id;
1287+
return date_time_zone_id->timezone_name;
12851288
}
12861289

12871290
int64_t mg_local_date_time_seconds(const mg_local_date_time *local_date_time) {
@@ -1442,7 +1445,14 @@ mg_date_time_zone_id *mg_date_time_zone_id_copy_ca(
14421445
if (!date_time_zone_id) {
14431446
return NULL;
14441447
}
1445-
memcpy(date_time_zone_id, src, sizeof(mg_date_time_zone_id));
1448+
date_time_zone_id->seconds = src->seconds;
1449+
date_time_zone_id->nanoseconds = src->nanoseconds;
1450+
date_time_zone_id->timezone_name =
1451+
mg_string_copy_ca(src->timezone_name, allocator);
1452+
if (!date_time_zone_id->timezone_name) {
1453+
mg_date_time_zone_id_destroy_ca(date_time_zone_id, allocator);
1454+
return NULL;
1455+
}
14461456
return date_time_zone_id;
14471457
}
14481458

@@ -1456,6 +1466,7 @@ void mg_date_time_zone_id_destroy_ca(mg_date_time_zone_id *date_time_zone_id,
14561466
if (!date_time_zone_id) {
14571467
return;
14581468
}
1469+
mg_string_destroy_ca(date_time_zone_id->timezone_name, allocator);
14591470
mg_allocator_free(allocator, date_time_zone_id);
14601471
}
14611472

@@ -1657,6 +1668,39 @@ mg_local_time *mg_local_time_make(int64_t nanoseconds) {
16571668
return lt;
16581669
}
16591670

1671+
mg_date_time *mg_date_time_make(int64_t seconds, int64_t nanoseconds,
1672+
int32_t tz_offset_minutes) {
1673+
mg_date_time *dt = mg_date_time_alloc(&mg_system_allocator);
1674+
if (!dt) {
1675+
return NULL;
1676+
}
1677+
dt->seconds = seconds;
1678+
dt->nanoseconds = nanoseconds;
1679+
dt->tz_offset_minutes = tz_offset_minutes;
1680+
return dt;
1681+
}
1682+
1683+
mg_date_time_zone_id *mg_date_time_zone_id_make(int64_t seconds,
1684+
int64_t nanoseconds,
1685+
const char *timezone_name) {
1686+
mg_date_time_zone_id *dt_zone_id =
1687+
mg_date_time_zone_id_alloc(&mg_system_allocator);
1688+
if (!dt_zone_id) {
1689+
return NULL;
1690+
}
1691+
1692+
mg_string *tz_name = mg_string_make(timezone_name);
1693+
if (!tz_name) {
1694+
mg_date_time_zone_id_destroy_ca(dt_zone_id, &mg_system_allocator);
1695+
return NULL;
1696+
}
1697+
1698+
dt_zone_id->seconds = seconds;
1699+
dt_zone_id->nanoseconds = nanoseconds;
1700+
dt_zone_id->timezone_name = tz_name;
1701+
return dt_zone_id;
1702+
}
1703+
16601704
mg_local_date_time *mg_local_date_time_make(int64_t seconds,
16611705
int64_t nanoseconds) {
16621706
mg_local_date_time *ldt = mg_local_date_time_alloc(&mg_system_allocator);
@@ -1814,7 +1858,7 @@ int mg_local_date_time_equal(const mg_local_date_time *lhs,
18141858
int mg_date_time_zone_id_equal(const mg_date_time_zone_id *lhs,
18151859
const mg_date_time_zone_id *rhs) {
18161860
return lhs->seconds == rhs->seconds && lhs->nanoseconds == rhs->nanoseconds &&
1817-
lhs->tz_id == rhs->tz_id;
1861+
mg_string_equal(lhs->timezone_name, rhs->timezone_name);
18181862
}
18191863

18201864
int mg_duration_equal(const mg_duration *lhs, const mg_duration *rhs) {

src/mgvalue.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ typedef struct mg_date_time {
9494
typedef struct mg_date_time_zone_id {
9595
int64_t seconds;
9696
int64_t nanoseconds;
97-
int64_t tz_id;
97+
mg_string *timezone_name;
9898
} mg_date_time_zone_id;
9999

100100
typedef struct mg_local_date_time {

tests/bolt-testdata.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -445,13 +445,14 @@ std::vector<ValueTestParam> DateTimeZoneIdTestCases() {
445445

446446
date_time_zone_id->seconds = 1;
447447
date_time_zone_id->nanoseconds = 1;
448-
date_time_zone_id->tz_id = 1;
448+
date_time_zone_id->timezone_name = mg_string_make("Europe/Zagreb");
449449

450450
std::string encoded_date_time_zone_id;
451451
encoded_date_time_zone_id += "\xB3\x66"s;
452452
encoded_date_time_zone_id += "\x01"s;
453453
encoded_date_time_zone_id += "\x01"s;
454-
encoded_date_time_zone_id += "\x01"s;
454+
encoded_date_time_zone_id += "\x8D"s;
455+
encoded_date_time_zone_id += "Europe/Zagreb"s;
455456

456457
inputs.push_back({mg_value_make_date_time_zone_id(date_time_zone_id),
457458
encoded_date_time_zone_id});

tests/encoder.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,9 @@ INSTANTIATE_TEST_CASE_P(LocalTime, ValueTest,
298298
INSTANTIATE_TEST_CASE_P(LocalDateTime, ValueTest,
299299
::testing::ValuesIn(LocalDateTimeTestCases()), );
300300

301+
INSTANTIATE_TEST_CASE_P(DateTime, ValueTest,
302+
::testing::ValuesIn(DateTimeTestCases()), );
303+
301304
INSTANTIATE_TEST_CASE_P(Duration, ValueTest,
302305
::testing::ValuesIn((DurationTestCases())), );
303306

tests/value.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -522,22 +522,24 @@ TEST(Value, DateTimeZoneId) {
522522
mg_date_time_zone_id_alloc(&mg_system_allocator);
523523
date_time_zone_id->seconds = 1;
524524
date_time_zone_id->nanoseconds = 1;
525-
date_time_zone_id->tz_id = 1;
525+
date_time_zone_id->timezone_name = mg_string_make("Europe/Zagreb");
526526
EXPECT_EQ(mg_date_time_zone_id_seconds(date_time_zone_id),
527527
static_cast<int64_t>(1));
528528
EXPECT_EQ(mg_date_time_zone_id_nanoseconds(date_time_zone_id),
529529
static_cast<int64_t>(1));
530-
EXPECT_EQ(mg_date_time_zone_id_tz_id(date_time_zone_id),
531-
static_cast<int64_t>(1));
530+
const mg_string *tz_name =
531+
mg_date_time_zone_id_timezone_name(date_time_zone_id);
532+
EXPECT_TRUE(Equal(tz_name, "Europe/Zagreb"s));
532533
mg_date_time_zone_id *date_time_zone_id2 =
533534
mg_date_time_zone_id_copy(date_time_zone_id);
534535
mg_date_time_zone_id_destroy(date_time_zone_id);
535536
EXPECT_EQ(mg_date_time_zone_id_seconds(date_time_zone_id2),
536537
static_cast<int64_t>(1));
537538
EXPECT_EQ(mg_date_time_zone_id_nanoseconds(date_time_zone_id2),
538539
static_cast<int64_t>(1));
539-
EXPECT_EQ(mg_date_time_zone_id_tz_id(date_time_zone_id2),
540-
static_cast<int64_t>(1));
540+
const mg_string *tz_name2 =
541+
mg_date_time_zone_id_timezone_name(date_time_zone_id2);
542+
EXPECT_TRUE(Equal(tz_name2, "Europe/Zagreb"s));
541543
mg_date_time_zone_id_destroy(date_time_zone_id2);
542544
}
543545
}

0 commit comments

Comments
 (0)