const std = @import("std"); const abi = @import("abi.zig"); const t = @import("temporal.zig"); const PlainDate = @import("PlainDate.zig"); /// # Temporal.PlainMonthDay /// /// The `Temporal.PlainMonthDay` object represents a month and day in a calendar, with no year or time. /// /// See: [Temporal.PlainMonthDay](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay) const PlainMonthDay = @This(); _inner: *abi.c.PlainMonthDay, // Type definitions for API compatibility pub const CalendarDisplay = enum { auto, always, never, critical, }; pub const ToStringOptions = struct { calendar_display: ?CalendarDisplay = null, }; pub const WithOptions = struct { month_code: ?[]const u8 = null, day: ?u8 = null, }; // Helper to wrap PlainMonthDay pointer fn wrapPlainMonthDay(result: anytype) !PlainMonthDay { const ptr = (try abi.extractResult(result)) orelse return abi.TemporalError.Generic; return .{ ._inner = ptr }; } /// Creates a new PlainMonthDay from the given month, day, and optional calendar. /// Equivalent to the Temporal.PlainMonthDay constructor. /// /// See: [Temporal.PlainMonthDay](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/PlainMonthDay) pub fn init(month_val: u8, day_val: u8, calendar: ?[]const u8) !PlainMonthDay { const cal_kind = if (calendar) |cal| blk: { const cal_view = abi.toDiplomatStringView(cal); const cal_result = abi.c.temporal_rs_AnyCalendarKind_parse_temporal_calendar_string(cal_view); break :blk try abi.extractResult(cal_result); } else abi.c.AnyCalendarKind_Iso; const overflow = abi.c.ArithmeticOverflow_Constrain; const ref_year = abi.c.OptionI32{ .is_ok = false }; return wrapPlainMonthDay(abi.c.temporal_rs_PlainMonthDay_try_new_with_overflow( month_val, day_val, cal_kind, overflow, ref_year, )); } /// Parses a PlainMonthDay from a string. /// /// See: [Temporal.PlainMonthDay.from](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/from) pub fn from(s: []const u8) !PlainMonthDay { return fromUtf8(s); } fn fromUtf8(utf8: []const u8) !PlainMonthDay { const view = abi.toDiplomatStringView(utf8); return wrapPlainMonthDay(abi.c.temporal_rs_PlainMonthDay_from_utf8(view)); } fn fromUtf16(utf16: []const u16) !PlainMonthDay { const view = abi.toDiplomatString16View(utf16); return wrapPlainMonthDay(abi.c.temporal_rs_PlainMonthDay_from_utf16(view)); } // Comparison /// Returns true if this PlainMonthDay is equal to another (same date and calendar). /// /// See: [Temporal.PlainMonthDay.equals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/equals) pub fn equals(self: PlainMonthDay, other: PlainMonthDay) bool { return abi.c.temporal_rs_PlainMonthDay_equals(self._inner, other._inner); } // Property accessors /// Returns the calendar identifier used to interpret the internal ISO 8601 date. /// /// See: [Temporal.PlainMonthDay.calendarId](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/calendarId) pub fn calendarId(self: PlainMonthDay, allocator: std.mem.Allocator) ![]u8 { const calendar_ptr = abi.c.temporal_rs_PlainMonthDay_calendar(self._inner) orelse return error.TemporalError; const cal_id_view = abi.c.temporal_rs_Calendar_identifier(calendar_ptr); return try allocator.dupe(u8, cal_id_view.data[0..cal_id_view.len]); } /// Returns the 1-based day index in the month of this date. /// /// See: [Temporal.PlainMonthDay.day](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/day) pub fn day(self: PlainMonthDay) u8 { return abi.c.temporal_rs_PlainMonthDay_day(self._inner); } /// Returns the calendar-specific string representing the month of this date. /// /// See: [Temporal.PlainMonthDay.monthCode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/monthCode) pub fn monthCode(self: PlainMonthDay, allocator: std.mem.Allocator) ![]const u8 { var write = abi.DiplomatWrite.init(allocator); defer write.deinit(); abi.c.temporal_rs_PlainMonthDay_month_code(self._inner, &write.inner); return try write.toOwnedSlice(); } // Modification /// Returns a new PlainMonthDay with some fields replaced by new values. /// /// See: [Temporal.PlainMonthDay.with](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/with) pub fn with(self: PlainMonthDay, options: WithOptions) !PlainMonthDay { // Build month_code view const month_code_view = if (options.month_code) |mc| abi.toDiplomatStringView(mc) else abi.c.DiplomatStringView{ .data = null, .len = 0 }; // Build partial date with only the fields we want to modify const partial_date = abi.c.PartialDate{ .year = .{ .is_ok = false }, .month = .{ .is_ok = false }, .day = if (options.day) |d| abi.toOption(abi.c.OptionU8, d) else .{ .is_ok = false }, .month_code = month_code_view, .era = .{ .data = null, .len = 0 }, .era_year = .{ .is_ok = false }, .calendar = abi.c.AnyCalendarKind_Iso, }; const overflow = abi.c.ArithmeticOverflow_option{ .is_ok = true, .unnamed_0 = .{ .ok = abi.c.ArithmeticOverflow_Constrain }, }; return wrapPlainMonthDay(abi.c.temporal_rs_PlainMonthDay_with( self._inner, partial_date, overflow, )); } // Conversion /// Returns a PlainDate representing this month-day and a supplied year in the same calendar system. /// /// See: [Temporal.PlainMonthDay.toPlainDate](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/toPlainDate) pub fn toPlainDate(self: PlainMonthDay, year: i32) !PlainDate { const partial_date = abi.c.PartialDate_option{ .is_ok = true, .unnamed_0 = .{ .ok = .{ .year = abi.toOption(abi.c.OptionI32, year), .month = .{ .is_ok = false }, .day = .{ .is_ok = false }, .month_code = .{ .data = null, .len = 0 }, .era = .{ .data = null, .len = 0 }, .era_year = .{ .is_ok = false }, .calendar = abi.c.AnyCalendarKind_Iso, }, }, }; const result = abi.c.temporal_rs_PlainMonthDay_to_plain_date(self._inner, partial_date); const ptr = (try abi.extractResult(result)) orelse return abi.TemporalError.Generic; return PlainDate{ ._inner = ptr }; } // String conversions /// Returns a string representing this month-day in RFC 9557 format. /// /// See: [Temporal.PlainMonthDay.toString](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/toString) pub fn toString(self: PlainMonthDay, allocator: std.mem.Allocator) ![]u8 { return toStringWithOptions(self, allocator, .{}); } fn toStringWithOptions(self: PlainMonthDay, allocator: std.mem.Allocator, options: ToStringOptions) ![]u8 { _ = options; var write = abi.DiplomatWrite.init(allocator); defer write.deinit(); const display = abi.c.DisplayCalendar_Auto; abi.c.temporal_rs_PlainMonthDay_to_ixdtf_string(self._inner, display, &write.inner); return try write.toOwnedSlice(); } /// Returns a string representing this month-day in RFC 9557 format (ISO 8601). /// /// See: [Temporal.PlainMonthDay.toJSON](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/toJSON) pub fn toJSON(self: PlainMonthDay, allocator: std.mem.Allocator) ![]u8 { return toString(self, allocator); } /// Returns a language-sensitive string representation of this month-day. /// /// See: [Temporal.PlainMonthDay.toLocaleString](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/toLocaleString) pub fn toLocaleString(self: PlainMonthDay, allocator: std.mem.Allocator) ![]u8 { return toString(self, allocator); } /// Throws an error; valueOf() is not supported for PlainMonthDay. /// /// See: [Temporal.PlainMonthDay.valueOf](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/valueOf) pub fn valueOf(self: PlainMonthDay) !void { _ = self; return error.ValueError; } test init { const md = try init(12, 25, null); try std.testing.expectEqual(@as(u8, 25), md.day()); const month_code = try md.monthCode(std.testing.allocator); defer std.testing.allocator.free(month_code); try std.testing.expect(month_code.len > 0); } test from { const md = try from("12-25"); try std.testing.expectEqual(@as(u8, 25), md.day()); } test equals { { const md1 = try init(12, 25, null); const md2 = try init(12, 25, null); try std.testing.expect(md1.equals(md2)); } { const md1 = try init(12, 25, null); const md2 = try init(12, 24, null); try std.testing.expect(!md1.equals(md2)); } } test toPlainDate { const md = try init(12, 25, null); const date = try md.toPlainDate(2024); try std.testing.expectEqual(@as(i32, 2024), date.year()); try std.testing.expectEqual(@as(u8, 25), date.day()); } test toString { const md = try init(12, 25, null); const str = try md.toString(std.testing.allocator); defer std.testing.allocator.free(str); try std.testing.expect(str.len > 0); } test toJSON { const md = try init(12, 25, null); const str = try md.toJSON(std.testing.allocator); defer std.testing.allocator.free(str); try std.testing.expect(str.len > 0); } test with { // Test modifying day const md1 = try init(12, 25, null); const md2 = try md1.with(.{ .day = 31 }); try std.testing.expectEqual(@as(u8, 31), md2.day()); // Test modifying month_code const md3 = try init(12, 25, null); const md4 = try md3.with(.{ .month_code = "M01" }); const month_code = try md4.monthCode(std.testing.allocator); defer std.testing.allocator.free(month_code); try std.testing.expectEqualStrings("M01", month_code); try std.testing.expectEqual(@as(u8, 25), md4.day()); // Test modifying both const md5 = try init(6, 15, null); const md6 = try md5.with(.{ .month_code = "M12", .day = 1 }); const month_code2 = try md6.monthCode(std.testing.allocator); defer std.testing.allocator.free(month_code2); try std.testing.expectEqualStrings("M12", month_code2); try std.testing.expectEqual(@as(u8, 1), md6.day()); } test toLocaleString { const md = try init(12, 25, null); const str = try md.toLocaleString(std.testing.allocator); defer std.testing.allocator.free(str); try std.testing.expect(str.len > 0); try std.testing.expect(std.mem.indexOf(u8, str, "12") != null or std.mem.indexOf(u8, str, "25") != null); } test calendarId { const md = try init(12, 25, null); const cal_id = try md.calendarId(std.testing.allocator); defer std.testing.allocator.free(cal_id); try std.testing.expectEqualStrings("iso8601", cal_id); } test day { const md = try init(12, 25, null); try std.testing.expectEqual(@as(u8, 25), md.day()); } test monthCode { const md = try init(12, 25, null); const code = try md.monthCode(std.testing.allocator); defer std.testing.allocator.free(code); try std.testing.expectEqualStrings("M12", code); } test valueOf { const md = try init(12, 25, null); try std.testing.expectError(error.ValueError, md.valueOf()); }