fix: instant/duration complete tc39 alignment
This commit is contained in:
parent
7c4cb5a3ca
commit
6ff4ef1298
8 changed files with 245 additions and 70 deletions
221
src/Duration.zig
221
src/Duration.zig
|
|
@ -2,15 +2,35 @@ const std = @import("std");
|
|||
const abi = @import("abi.zig");
|
||||
const temporal = @import("temporal.zig");
|
||||
|
||||
const PlainDate = @import("PlainDate.zig");
|
||||
const PlainDateTime = @import("PlainDateTime.zig");
|
||||
const ZonedDateTime = @import("ZonedDateTime.zig");
|
||||
|
||||
const Duration = @This();
|
||||
|
||||
pub const RoundingOptions = temporal.RoundingOptions;
|
||||
pub const ToStringOptions = temporal.ToStringRoundingOptions;
|
||||
pub const ToStringRoundingOptions = temporal.ToStringRoundingOptions;
|
||||
pub const Unit = temporal.Unit;
|
||||
pub const RoundingMode = temporal.RoundingMode;
|
||||
pub const Sign = temporal.Sign;
|
||||
|
||||
pub const RoundingOptions = struct {
|
||||
largest_unit: ?Unit = null,
|
||||
smallest_unit: ?Unit = null,
|
||||
rounding_mode: ?RoundingMode = null,
|
||||
rounding_increment: ?u32 = null,
|
||||
relative_to: ?RelativeTo = null,
|
||||
|
||||
pub fn toCApi(self: RoundingOptions) abi.c.RoundingOptions {
|
||||
return .{
|
||||
.largest_unit = abi.toUnitOption(temporal.toCUnit(self.largest_unit)),
|
||||
.smallest_unit = abi.toUnitOption(temporal.toCUnit(self.smallest_unit)),
|
||||
.rounding_mode = abi.toRoundingModeOption(temporal.toCRoundingMode(self.rounding_mode)),
|
||||
.increment = abi.toOption(abi.c.OptionU32, self.rounding_increment),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/// Partial duration specification for creating Duration objects.
|
||||
/// This is a wrapper around the C API type to avoid exposing C types directly.
|
||||
pub const PartialDuration = struct {
|
||||
|
|
@ -52,23 +72,30 @@ const ZonedDateTimeRef = struct {
|
|||
};
|
||||
|
||||
/// Relative-to context for duration operations.
|
||||
pub const RelativeTo = struct {
|
||||
plain_date: ?PlainDateRef = null,
|
||||
zoned_date_time: ?ZonedDateTimeRef = null,
|
||||
pub const RelativeTo = union(enum) {
|
||||
plain_date: PlainDate,
|
||||
plain_date_time: PlainDateTime,
|
||||
zoned_date_time: ZonedDateTime,
|
||||
|
||||
fn toCApi(self: RelativeTo) abi.c.RelativeTo {
|
||||
return .{
|
||||
.date = if (self.plain_date) |pd| pd._inner else null,
|
||||
.zoned = if (self.zoned_date_time) |zdt| zdt._inner else null,
|
||||
};
|
||||
switch (self) {
|
||||
.plain_date => |pd| return .{ .date = pd._inner },
|
||||
.zoned_date_time => |zdt| return .{ .zoned = zdt._inner },
|
||||
.plain_date_time => |pdt| return .{ .date = (pdt.toPlainDate() catch unreachable)._inner },
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// Options for Duration.total() providing unit and relative-to context.
|
||||
pub const TotalOptions = struct {
|
||||
unit: Unit,
|
||||
relative_to: ?RelativeTo = null,
|
||||
};
|
||||
|
||||
pub const CompareOptions = struct {
|
||||
relative_to: ?RelativeTo = null,
|
||||
};
|
||||
|
||||
_inner: *abi.c.Duration,
|
||||
|
||||
/// Construct a Duration from years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, and nanoseconds.
|
||||
|
|
@ -99,18 +126,54 @@ pub fn init(
|
|||
));
|
||||
}
|
||||
|
||||
/// Parse an ISO 8601 duration string (Temporal.Duration.from).
|
||||
pub fn from(text: []const u8) !Duration {
|
||||
const view = abi.toDiplomatStringView(text);
|
||||
return wrapDuration(abi.c.temporal_rs_Duration_from_utf8(view));
|
||||
/// The Temporal.Duration.from() static method creates a new Temporal.Duration object from one of the following:
|
||||
/// - A Temporal.Duration instance, which creates a copy of the instance.
|
||||
/// - An ISO 8601 string representing a duration.
|
||||
/// - A @Temporal.Duration.PartialDuration struct containing at least one of the following properties:
|
||||
/// - days
|
||||
/// - hours
|
||||
/// - microseconds
|
||||
/// - milliseconds
|
||||
/// - minutes
|
||||
/// - months
|
||||
/// - nanoseconds
|
||||
/// - seconds
|
||||
/// - weeks
|
||||
/// - years
|
||||
/// The resulting duration must not have mixed signs, so all of these properties must have the same sign (or zero). Missing properties are treated as zero.
|
||||
pub fn from(info: anytype) !Duration {
|
||||
const T = @TypeOf(info);
|
||||
|
||||
if (T == Duration) return info.clone();
|
||||
if (T == PartialDuration) return fromPartialDuration(info);
|
||||
|
||||
// Handle string types (both literals and slices)
|
||||
const type_info = @typeInfo(T);
|
||||
switch (type_info) {
|
||||
.pointer => {
|
||||
const ptr = type_info.pointer;
|
||||
const ChildType = switch (@typeInfo(ptr.child)) {
|
||||
.array => |arr| arr.child,
|
||||
else => ptr.child,
|
||||
};
|
||||
|
||||
if (ChildType == u8) return fromUtf8(info);
|
||||
if (ChildType == u16) return fromUtf16(info);
|
||||
},
|
||||
else => @compileError("from() expects a Duration, []const u8, or []const u16, or Temporal.Duration.PartialDuration"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse an ISO 8601 UTF-16 duration string.
|
||||
fn fromUtf16(text: []const u16) !Duration {
|
||||
inline fn fromUtf16(text: []const u16) !Duration {
|
||||
const view = abi.toDiplomatString16View(text);
|
||||
return wrapDuration(abi.c.temporal_rs_Duration_from_utf16(view));
|
||||
}
|
||||
|
||||
inline fn fromUtf8(text: []const u8) !Duration {
|
||||
const view = abi.toDiplomatStringView(text);
|
||||
return wrapDuration(abi.c.temporal_rs_Duration_from_utf8(view));
|
||||
}
|
||||
|
||||
/// Create a Duration from a partial duration (where some fields may be omitted).
|
||||
fn fromPartialDuration(partial: PartialDuration) !Duration {
|
||||
return wrapDuration(abi.c.temporal_rs_Duration_from_partial_duration(partial.toCApi()));
|
||||
|
|
@ -204,8 +267,9 @@ pub fn subtract(self: Duration, other: Duration) !Duration {
|
|||
}
|
||||
|
||||
/// Round the duration according to the specified options (Temporal.Duration.prototype.round).
|
||||
pub fn round(self: Duration, options: RoundingOptions, relative_to: RelativeTo) !Duration {
|
||||
return wrapDuration(abi.c.temporal_rs_Duration_round(self._inner, options.toCApi(), relative_to.toCApi()));
|
||||
pub fn round(self: Duration, options: RoundingOptions) !Duration {
|
||||
const rel = if (options.relative_to) |r| r.toCApi() else abi.c.RelativeTo{ .date = null, .zoned = null };
|
||||
return wrapDuration(abi.c.temporal_rs_Duration_round(self._inner, options.toCApi(), rel));
|
||||
}
|
||||
|
||||
/// Round the duration with an explicit provider.
|
||||
|
|
@ -214,8 +278,9 @@ fn roundWithProvider(self: Duration, options: RoundingOptions, relative_to: Rela
|
|||
}
|
||||
|
||||
/// Compare two durations (Temporal.Duration.compare).
|
||||
pub fn compare(self: Duration, other: Duration, relative_to: RelativeTo) !i8 {
|
||||
const res = abi.c.temporal_rs_Duration_compare(self._inner, other._inner, relative_to.toCApi());
|
||||
pub fn compare(self: Duration, other: Duration, options: CompareOptions) !i8 {
|
||||
const rel = if (options.relative_to) |r| r.toCApi() else abi.c.RelativeTo{ .date = null, .zoned = null };
|
||||
const res = abi.c.temporal_rs_Duration_compare(self._inner, other._inner, rel);
|
||||
return try abi.extractResult(res);
|
||||
}
|
||||
|
||||
|
|
@ -304,32 +369,54 @@ test init {
|
|||
}
|
||||
|
||||
test from {
|
||||
// P1Y2M3DT4H5M6.789S = 1 year, 2 months, 3 days, 4 hours, 5 minutes, 6.789 seconds
|
||||
const dur = try Duration.from("P1Y2M3DT4H5M6.789S");
|
||||
defer dur.deinit();
|
||||
{ // P1Y2M3DT4H5M6.789S = 1 year, 2 months, 3 days, 4 hours, 5 minutes, 6.789 seconds
|
||||
const dur = try Duration.from("P1Y2M3DT4H5M6.789S");
|
||||
defer dur.deinit();
|
||||
|
||||
try std.testing.expectEqual(@as(i64, 1), dur.years());
|
||||
try std.testing.expectEqual(@as(i64, 2), dur.months());
|
||||
try std.testing.expectEqual(@as(i64, 3), dur.days());
|
||||
try std.testing.expectEqual(@as(i64, 4), dur.hours());
|
||||
try std.testing.expectEqual(@as(i64, 5), dur.minutes());
|
||||
try std.testing.expectEqual(@as(i64, 6), dur.seconds());
|
||||
try std.testing.expectEqual(@as(i64, 1), dur.years());
|
||||
try std.testing.expectEqual(@as(i64, 2), dur.months());
|
||||
try std.testing.expectEqual(@as(i64, 3), dur.days());
|
||||
try std.testing.expectEqual(@as(i64, 4), dur.hours());
|
||||
try std.testing.expectEqual(@as(i64, 5), dur.minutes());
|
||||
try std.testing.expectEqual(@as(i64, 6), dur.seconds());
|
||||
|
||||
// from-time
|
||||
// PT2H30M = 2 hours, 30 minutes
|
||||
const dur_time = try Duration.from("PT2H30M");
|
||||
defer dur_time.deinit();
|
||||
// from-time
|
||||
// PT2H30M = 2 hours, 30 minutes
|
||||
const dur_time = try Duration.from("PT2H30M");
|
||||
defer dur_time.deinit();
|
||||
|
||||
try std.testing.expectEqual(@as(i64, 0), dur_time.years());
|
||||
try std.testing.expectEqual(@as(i64, 2), dur_time.hours());
|
||||
try std.testing.expectEqual(@as(i64, 30), dur_time.minutes());
|
||||
try std.testing.expectEqual(@as(i64, 0), dur_time.years());
|
||||
try std.testing.expectEqual(@as(i64, 2), dur_time.hours());
|
||||
try std.testing.expectEqual(@as(i64, 30), dur_time.minutes());
|
||||
|
||||
// from-negative
|
||||
const dur_negative = try Duration.from("-P1D");
|
||||
defer dur_negative.deinit();
|
||||
// from-negative
|
||||
const dur_negative = try Duration.from("-P1D");
|
||||
defer dur_negative.deinit();
|
||||
|
||||
try std.testing.expectEqual(@as(i64, -1), dur_negative.days());
|
||||
try std.testing.expectEqual(Sign.negative, dur_negative.sign());
|
||||
try std.testing.expectEqual(@as(i64, -1), dur_negative.days());
|
||||
try std.testing.expectEqual(Sign.negative, dur_negative.sign());
|
||||
}
|
||||
{
|
||||
const partial = PartialDuration{
|
||||
.hours = 3,
|
||||
.minutes = 45,
|
||||
};
|
||||
|
||||
const dur = try Duration.from(partial);
|
||||
defer dur.deinit();
|
||||
|
||||
try std.testing.expectEqual(@as(i64, 3), dur.hours());
|
||||
try std.testing.expectEqual(@as(i64, 45), dur.minutes());
|
||||
}
|
||||
{
|
||||
const dur1 = try Duration.from("PT1H");
|
||||
defer dur1.deinit();
|
||||
const dur2 = try Duration.from(dur1);
|
||||
defer dur2.deinit();
|
||||
|
||||
try std.testing.expectEqual(@as(i64, 1), dur2.hours());
|
||||
try std.testing.expectEqual(@as(i64, 0), dur2.minutes());
|
||||
}
|
||||
}
|
||||
|
||||
test blank {
|
||||
|
|
@ -353,6 +440,17 @@ test add {
|
|||
try std.testing.expectEqual(@as(i64, 30), result.minutes());
|
||||
}
|
||||
|
||||
test compare {
|
||||
const dur1 = try Duration.from("PT1H");
|
||||
defer dur1.deinit();
|
||||
const dur2 = try Duration.from("PT30M");
|
||||
defer dur2.deinit();
|
||||
|
||||
const result = try dur1.compare(dur2, .{});
|
||||
|
||||
try std.testing.expectEqual(@as(i8, 1), result);
|
||||
}
|
||||
|
||||
test subtract {
|
||||
const dur1 = try Duration.from("PT2H");
|
||||
defer dur1.deinit();
|
||||
|
|
@ -432,6 +530,51 @@ test clone {
|
|||
try std.testing.expectEqual(dur.hours(), cloned.hours());
|
||||
}
|
||||
|
||||
test round {
|
||||
{
|
||||
const dur = try Duration.from("PT1H30M");
|
||||
defer dur.deinit();
|
||||
|
||||
const rounded = try dur.round(.{
|
||||
.smallest_unit = .hour,
|
||||
.relative_to = .{
|
||||
.plain_date_time = try PlainDateTime.init(2024, 1, 1, 12, 0, 0, 0, 0, 0),
|
||||
},
|
||||
});
|
||||
defer rounded.deinit();
|
||||
|
||||
try std.testing.expectEqual(@as(i64, 2), rounded.hours());
|
||||
try std.testing.expectEqual(@as(i64, 0), rounded.minutes());
|
||||
}
|
||||
|
||||
{
|
||||
const dur = try Duration.from("PT1H30M");
|
||||
defer dur.deinit();
|
||||
|
||||
const rounded = try dur.round(.{
|
||||
.smallest_unit = .hour,
|
||||
.relative_to = .{
|
||||
.plain_date = try PlainDate.init(2024, 1, 1),
|
||||
},
|
||||
});
|
||||
defer rounded.deinit();
|
||||
|
||||
try std.testing.expectEqual(@as(i64, 2), rounded.hours());
|
||||
try std.testing.expectEqual(@as(i64, 0), rounded.minutes());
|
||||
}
|
||||
|
||||
{
|
||||
const dur = try Duration.from("PT1H30M");
|
||||
defer dur.deinit();
|
||||
|
||||
const rounded = try dur.round(.{ .smallest_unit = .hour });
|
||||
defer rounded.deinit();
|
||||
|
||||
try std.testing.expectEqual(@as(i64, 2), rounded.hours());
|
||||
try std.testing.expectEqual(@as(i64, 0), rounded.minutes());
|
||||
}
|
||||
}
|
||||
|
||||
test total {
|
||||
{
|
||||
const dur = try Duration.init(0, 0, 0, 0, 1, 30, 0, 0, 0, 0);
|
||||
|
|
|
|||
|
|
@ -48,8 +48,6 @@ pub const ToStringOptions = struct {
|
|||
};
|
||||
|
||||
_inner: *abi.c.Instant,
|
||||
epoch_milliseconds: i64,
|
||||
epoch_nanoseconds: i128,
|
||||
|
||||
/// Construct from epoch nanoseconds (Temporal.Instant.fromEpochNanoseconds).
|
||||
pub fn init(epoch_ns: i128) !Instant {
|
||||
|
|
@ -193,7 +191,15 @@ fn toZonedDateTimeIsoWithProvider(self: Instant, zone: TimeZone, provider: *cons
|
|||
/// Clone the underlying instant.
|
||||
fn clone(self: Instant) Instant {
|
||||
const ptr = abi.c.temporal_rs_Instant_clone(self._inner) orelse unreachable;
|
||||
return .{ ._inner = ptr, .epoch_milliseconds = abi.c.temporal_rs_Instant_epoch_milliseconds(ptr), .epoch_nanoseconds = abi.fromI128Nanoseconds(abi.c.temporal_rs_Instant_epoch_nanoseconds(ptr)) };
|
||||
return .{ ._inner = ptr };
|
||||
}
|
||||
|
||||
pub fn epochMilliseconds(self: Instant) i64 {
|
||||
return abi.c.temporal_rs_Instant_epoch_milliseconds(self._inner);
|
||||
}
|
||||
|
||||
pub fn epochNanoseconds(self: Instant) i128 {
|
||||
return abi.fromI128Nanoseconds(abi.c.temporal_rs_Instant_epoch_nanoseconds(self._inner));
|
||||
}
|
||||
|
||||
pub fn deinit(self: Instant) void {
|
||||
|
|
@ -206,8 +212,6 @@ fn wrapInstant(res: anytype) !Instant {
|
|||
const ptr = (try abi.extractResult(res)) orelse return abi.TemporalError.Generic;
|
||||
return .{
|
||||
._inner = ptr,
|
||||
.epoch_milliseconds = abi.c.temporal_rs_Instant_epoch_milliseconds(ptr),
|
||||
.epoch_nanoseconds = abi.fromI128Nanoseconds(abi.c.temporal_rs_Instant_epoch_nanoseconds(ptr)),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -258,7 +262,7 @@ test init {
|
|||
const inst = try Instant.init(epoch_ns);
|
||||
defer inst.deinit();
|
||||
|
||||
try std.testing.expectEqual(epoch_ns, inst.epoch_nanoseconds);
|
||||
try std.testing.expectEqual(epoch_ns, inst.epochNanoseconds());
|
||||
}
|
||||
|
||||
test fromEpochNanoseconds {
|
||||
|
|
@ -271,8 +275,8 @@ test fromEpochNanoseconds {
|
|||
const min_inst = try Instant.fromEpochNanoseconds(min_ns);
|
||||
defer min_inst.deinit();
|
||||
|
||||
try std.testing.expectEqual(max_ns, max_inst.epoch_nanoseconds);
|
||||
try std.testing.expectEqual(min_ns, min_inst.epoch_nanoseconds);
|
||||
try std.testing.expectEqual(max_ns, max_inst.epochNanoseconds());
|
||||
try std.testing.expectEqual(min_ns, min_inst.epochNanoseconds());
|
||||
|
||||
try std.testing.expectError(error.RangeError, Instant.fromEpochNanoseconds(max_ns + 1));
|
||||
try std.testing.expectError(error.RangeError, Instant.fromEpochNanoseconds(min_ns - 1));
|
||||
|
|
@ -282,13 +286,13 @@ test from {
|
|||
// Test parsing from UTF-8 string
|
||||
const inst = try Instant.from("2024-03-15T14:30:45.123Z");
|
||||
defer inst.deinit();
|
||||
try std.testing.expectEqual(@as(i64, 1_710_513_045_123), inst.epoch_milliseconds);
|
||||
try std.testing.expectEqual(@as(i64, 1_710_513_045_123), inst.epochMilliseconds());
|
||||
|
||||
// Test creating from another Instant
|
||||
const inst2 = try Instant.from(inst);
|
||||
defer inst2.deinit();
|
||||
try std.testing.expectEqual(inst.epoch_milliseconds, inst2.epoch_milliseconds);
|
||||
try std.testing.expectEqual(inst.epoch_nanoseconds, inst2.epoch_nanoseconds);
|
||||
try std.testing.expectEqual(inst.epochMilliseconds(), inst2.epochMilliseconds());
|
||||
try std.testing.expectEqual(inst.epochNanoseconds(), inst2.epochNanoseconds());
|
||||
try std.testing.expect(Instant.equals(inst, inst2));
|
||||
}
|
||||
|
||||
|
|
@ -301,7 +305,7 @@ test fromUtf16 {
|
|||
const inst = try Instant.fromUtf16(utf16);
|
||||
defer inst.deinit();
|
||||
|
||||
try std.testing.expectEqual(@as(i64, 1_710_513_045_123), inst.epoch_milliseconds);
|
||||
try std.testing.expectEqual(@as(i64, 1_710_513_045_123), inst.epochMilliseconds());
|
||||
}
|
||||
|
||||
test subtract {
|
||||
|
|
@ -313,11 +317,11 @@ test subtract {
|
|||
|
||||
const added = try base.add(&dur);
|
||||
defer added.deinit();
|
||||
try std.testing.expectEqual(@as(i64, 5_400_000), added.epoch_milliseconds);
|
||||
try std.testing.expectEqual(@as(i64, 5_400_000), added.epochMilliseconds());
|
||||
|
||||
const subbed = try added.subtract(&dur);
|
||||
defer subbed.deinit();
|
||||
try std.testing.expectEqual(@as(i64, 0), subbed.epoch_milliseconds);
|
||||
try std.testing.expectEqual(@as(i64, 0), subbed.epochMilliseconds());
|
||||
}
|
||||
|
||||
test compare {
|
||||
|
|
@ -410,7 +414,7 @@ test round {
|
|||
const rounded = try inst.round(opts);
|
||||
defer rounded.deinit();
|
||||
|
||||
const ns = rounded.epoch_nanoseconds;
|
||||
const ns = rounded.epochNanoseconds();
|
||||
try std.testing.expectEqual(@as(i128, 1_609_459_245_000_000_000), ns);
|
||||
}
|
||||
|
||||
|
|
@ -421,7 +425,7 @@ test clone {
|
|||
const cloned = inst.clone();
|
||||
defer cloned.deinit();
|
||||
|
||||
try std.testing.expectEqual(inst.epoch_milliseconds, cloned.epoch_milliseconds);
|
||||
try std.testing.expectEqual(inst.epochMilliseconds(), cloned.epochMilliseconds());
|
||||
}
|
||||
|
||||
test toString {
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ fn currentParts() CurrentParts {
|
|||
test instant {
|
||||
const inst = try instant();
|
||||
defer inst.deinit();
|
||||
try std.testing.expect(inst.epoch_nanoseconds > 0);
|
||||
try std.testing.expect(inst.epochNanoseconds() > 0);
|
||||
}
|
||||
|
||||
test plainDateISO {
|
||||
|
|
|
|||
|
|
@ -44,10 +44,10 @@ pub const ToZonedDateTimeOptions = struct {
|
|||
_inner: *abi.c.PlainDate,
|
||||
|
||||
pub fn init(year_val: i32, month_val: u8, day_val: u8) !PlainDate {
|
||||
return initWithCalendar(year_val, month_val, day_val, "iso8601");
|
||||
return calInit(year_val, month_val, day_val, "iso8601");
|
||||
}
|
||||
|
||||
pub fn initWithCalendar(year_val: i32, month_val: u8, day_val: u8, calendar: []const u8) !PlainDate {
|
||||
pub fn calInit(year_val: i32, month_val: u8, day_val: u8, calendar: []const u8) !PlainDate {
|
||||
const cal_view = abi.toDiplomatStringView(calendar);
|
||||
const cal_result = abi.c.temporal_rs_AnyCalendarKind_parse_temporal_calendar_string(cal_view);
|
||||
const cal_kind = try abi.extractResult(cal_result);
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ pub const WithOptions = struct {
|
|||
microsecond: ?u16 = null,
|
||||
nanosecond: ?u16 = null,
|
||||
};
|
||||
const PartialDateTime = struct {};
|
||||
|
||||
// Constructor - creates a PlainDateTime with all parameters
|
||||
pub fn init(
|
||||
|
|
@ -75,7 +76,7 @@ pub fn init(
|
|||
));
|
||||
}
|
||||
|
||||
pub fn initWithCalendar(
|
||||
pub fn calInit(
|
||||
year_val: i32,
|
||||
month_val: u8,
|
||||
day_val: u8,
|
||||
|
|
@ -105,8 +106,37 @@ pub fn initWithCalendar(
|
|||
}
|
||||
|
||||
// Parse from string
|
||||
pub fn from(s: []const u8) !PlainDateTime {
|
||||
return fromUtf8(s);
|
||||
pub fn from(info: anytype) !PlainDateTime {
|
||||
const T = @TypeOf(info);
|
||||
|
||||
if (T == PlainDateTime) return info.clone();
|
||||
if (T == PartialDateTime) return fromPartial(info);
|
||||
|
||||
// Handle string types (both literals and slices)
|
||||
const type_info = @typeInfo(T);
|
||||
switch (type_info) {
|
||||
.pointer => {
|
||||
const ptr = type_info.pointer;
|
||||
const ChildType = switch (@typeInfo(ptr.child)) {
|
||||
.array => |arr| arr.child,
|
||||
else => ptr.child,
|
||||
};
|
||||
|
||||
if (ChildType == u8) return fromUtf8(info);
|
||||
if (ChildType == u16) return fromUtf16(info);
|
||||
},
|
||||
else => @compileError("from() expects a Duration, []const u8, or []const u16, or Temporal.Duration.PartialDuration"),
|
||||
}
|
||||
}
|
||||
|
||||
fn fromPartial(info: PartialDateTime) !PlainDateTime {
|
||||
_ = info;
|
||||
return error.NotImplemented;
|
||||
// return abi.c.temporal_rs_PlainDateTime_from_partial(.{
|
||||
// .date = .{
|
||||
// .
|
||||
// }
|
||||
// }, overflow: struct_ArithmeticOverflow_option)
|
||||
}
|
||||
|
||||
fn fromUtf8(utf8: []const u8) !PlainDateTime {
|
||||
|
|
|
|||
|
|
@ -202,10 +202,7 @@ pub fn subtract(self: ZonedDateTime, duration: Duration) !ZonedDateTime {
|
|||
/// Convert to Instant
|
||||
pub fn toInstant(self: ZonedDateTime) !Instant {
|
||||
const instant_ptr = abi.c.temporal_rs_ZonedDateTime_to_instant(self._inner) orelse return error.TemporalError;
|
||||
const epoch_ms = abi.c.temporal_rs_Instant_epoch_milliseconds(instant_ptr);
|
||||
const epoch_ns_parts = abi.c.temporal_rs_Instant_epoch_nanoseconds(instant_ptr);
|
||||
const epoch_ns = abi.fromI128Nanoseconds(epoch_ns_parts);
|
||||
return .{ ._inner = instant_ptr, .epoch_milliseconds = epoch_ms, .epoch_nanoseconds = epoch_ns };
|
||||
return .{ ._inner = instant_ptr };
|
||||
}
|
||||
|
||||
/// Convert to JSON string (ISO 8601 format)
|
||||
|
|
@ -502,7 +499,7 @@ test toInstant {
|
|||
const instant = try zdt.toInstant();
|
||||
defer instant.deinit();
|
||||
|
||||
try std.testing.expectEqual(@as(i64, 1609459200000), instant.epoch_milliseconds);
|
||||
try std.testing.expectEqual(@as(i64, 1609459200000), instant.epochMilliseconds());
|
||||
}
|
||||
|
||||
test toPlainDate {
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ test Duration {
|
|||
"ToStringRoundingOptions",
|
||||
"Sign",
|
||||
"TotalOptions",
|
||||
"CompareOptions",
|
||||
};
|
||||
|
||||
try assertDecls(Duration, checks);
|
||||
|
|
@ -142,7 +143,7 @@ test PlainDate {
|
|||
const checks = .{
|
||||
// Constructor
|
||||
"init",
|
||||
"initWithCalendar",
|
||||
"calInit",
|
||||
|
||||
// Static methods
|
||||
"compare",
|
||||
|
|
@ -200,7 +201,7 @@ test PlainDateTime {
|
|||
const checks = .{
|
||||
// Constructor
|
||||
"init", // Temporal.PlainDateTime()
|
||||
"initWithCalendar",
|
||||
"calInit",
|
||||
|
||||
// Static methods
|
||||
"compare",
|
||||
|
|
|
|||
|
|
@ -159,10 +159,10 @@ pub const ToStringRoundingOptions = struct {
|
|||
}
|
||||
};
|
||||
|
||||
fn toCUnit(opt: ?Unit) ?c.Unit {
|
||||
pub fn toCUnit(opt: ?Unit) ?c.Unit {
|
||||
return if (opt) |u| @as(c.Unit, @intCast(u.toCApi())) else null;
|
||||
}
|
||||
|
||||
fn toCRoundingMode(opt: ?RoundingMode) ?c.RoundingMode {
|
||||
pub fn toCRoundingMode(opt: ?RoundingMode) ?c.RoundingMode {
|
||||
return if (opt) |m| @as(c.RoundingMode, @intCast(m.toCApi())) else null;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue