Skip to content

Commit

Permalink
std.time: include nano and microseconds in DateTime
Browse files Browse the repository at this point in the history
  • Loading branch information
Vexu committed Dec 14, 2023
1 parent f7b4297 commit 62c481f
Showing 1 changed file with 30 additions and 32 deletions.
62 changes: 30 additions & 32 deletions lib/std/time.zig
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,12 @@ pub fn localtime(allocator: std.mem.Allocator) LocalTimeError!TimeZone {

/// ISO 8601 compliant date and time representation.
pub const DateTime = struct {
/// nanoseconds, range 0 to 999
nanosecond: u16,

/// microseconds, range 0 to 999
microsecond: u16,

/// milliseconds, range 0 to 999
millisecond: u16,

Expand Down Expand Up @@ -110,7 +116,8 @@ pub const DateTime = struct {
/// year, year 0000 is equal to 1 BCE
year: i32,

utc_timestamp: i64,
/// UNIX timestamp in nanoseconds
nano_timestamp: i128,
tt: TimeZone.TimeType,

pub const Weekday = enum(u3) {
Expand Down Expand Up @@ -181,7 +188,7 @@ pub const DateTime = struct {

/// Get current date and time in the system's local time.
pub fn now(allocator: std.mem.Allocator) LocalTimeError!DateTime {
const utc_timestamp = timestamp();
const nano_timestamp = nanoTimestamp();

if (builtin.os.tag == .windows) {
var tzi: std.os.windows.TIME_ZONE_INFORMATION = undefined;
Expand All @@ -192,7 +199,7 @@ pub const DateTime = struct {
null,
);
if (rc != .SUCCESS) return error.LocalTimeUnavailable;
return fromTimestamp(utc_timestamp, .{
return fromTimestamp(nano_timestamp, .{
.name_data = .{
@intCast(tzi.StandardName[0]),
@intCast(tzi.StandardName[1]),
Expand All @@ -207,14 +214,15 @@ pub const DateTime = struct {
}

var sf = std.heap.stackFallback(4096, allocator);
var tz = try localtime(sf.allocator());
defer tz.deinit(sf.allocator());
const sf_allocator = sf.get();
var tz = try localtime(sf_allocator);
defer tz.deinit(sf_allocator);

return fromTimestamp(utc_timestamp, tz.project(utc_timestamp));
return fromTimestamp(nano_timestamp, tz.project(@intCast(@divFloor(nano_timestamp, ns_per_s))));
}

/// Convert timestamp in milliseconds to a DateTime.
pub fn fromTimestamp(utc_timestamp: i64, tt: TimeZone.TimeType) DateTime {
/// Convert UNIX timestamp in nanoseconds to a DateTime.
pub fn fromTimestamp(nano_timestamp: i128, tt: TimeZone.TimeType) DateTime {
// Ported from musl, which is licensed under the MIT license:
// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT

Expand All @@ -225,7 +233,10 @@ pub const DateTime = struct {
const days_per_100y = 365 * 100 + 24;
const days_per_4y = 365 * 4 + 1;

const seconds = @divTrunc(utc_timestamp, 1000) + tt.offset - leapoch;
const microseconds: i64 = @intCast(@divFloor(nano_timestamp, ns_per_us));
const milliseconds = @divFloor(microseconds, us_per_ms);

const seconds = @divTrunc(milliseconds, ms_per_s) + tt.offset - leapoch;
var days = @divTrunc(seconds, 86400);
var rem_seconds = @as(i32, @truncate(@rem(seconds, 86400)));
if (rem_seconds < 0) {
Expand Down Expand Up @@ -290,30 +301,17 @@ pub const DateTime = struct {
.hour = @intCast(@divTrunc(rem_seconds, 3600)),
.minute = @intCast(@rem(@divTrunc(rem_seconds, 60), 60)),
.second = @intCast(@rem(rem_seconds, 60)),
.millisecond = @intCast(@rem(utc_timestamp, 1000)),
.utc_timestamp = utc_timestamp,
.millisecond = @intCast(@rem(milliseconds, 1000)),
.microsecond = @intCast(@rem(microseconds, 1000)),
.nanosecond = @intCast(@rem(nano_timestamp, 1000)),
.nano_timestamp = nano_timestamp,
.tt = tt,
};
}

/// Compare two `DateTime`s.
pub fn order(self: DateTime, other: DateTime) std.math.Order {
var ord = std.math.order(self.year, other.year);
if (ord != .eq) return ord;

ord = std.math.order(self.year_day, other.year_day);
if (ord != .eq) return ord;

ord = std.math.order(self.hour, other.hour);
if (ord != .eq) return ord;

ord = std.math.order(self.minute, other.minute);
if (ord != .eq) return ord;

ord = std.math.order(self.second, other.second);
if (ord != .eq) return ord;

return std.math.order(self.millisecond, other.millisecond);
return std.math.order(self.nano_timestamp, other.nano_timestamp);
}

pub const default_fmt = "%Y-%m-%dT%H%c%M%c%S%z";
Expand Down Expand Up @@ -419,7 +417,7 @@ pub const DateTime = struct {
};

test "DateTime basic usage" {
const dt = DateTime.fromTimestamp(1560870105000, TimeZone.TimeType.UTC);
const dt = DateTime.fromTimestamp(1560870105 * ns_per_s, TimeZone.TimeType.UTC);

try testing.expect(dt.second == 45);
try testing.expect(dt.minute == 1);
Expand All @@ -432,7 +430,7 @@ test "DateTime basic usage" {
}

test "DateTime.format all" {
const dt = DateTime.fromTimestamp(1560816105000, TimeZone.TimeType.UTC);
const dt = DateTime.fromTimestamp(1560816105 * ns_per_s, TimeZone.TimeType.UTC);
var buf: [100]u8 = undefined;
const result = try std.fmt.bufPrint(&buf, "{%a %A %b %B %m %d %y %Y %I %p %H%c%M%c%S.%s %j %%}", .{dt});
try testing.expectEqualStrings("Tue Tuesday Jun June 06 18 19 2019 12 AM 00:01:45.000 169 %", result);
Expand All @@ -444,7 +442,7 @@ test "DateTime.format no format" {
.flags = 0,
.name_data = "EEST\x00\x00".*,
};
const dt = DateTime.fromTimestamp(1560870105000, EEST);
const dt = DateTime.fromTimestamp(1560870105 * ns_per_s, EEST);
var buf: [100]u8 = undefined;
const result = try std.fmt.bufPrint(&buf, "{}", .{dt});
try std.testing.expectEqualStrings("2019-06-18T18:01:45+0300", result);
Expand All @@ -469,7 +467,7 @@ pub fn timestamp() i64 {
/// before the epoch.
/// See `std.os.clock_gettime` for a POSIX timestamp.
pub fn milliTimestamp() i64 {
return @as(i64, @intCast(@divFloor(nanoTimestamp(), ns_per_ms)));
return @intCast(@divFloor(nanoTimestamp(), ns_per_ms));
}

/// Get a calendar timestamp, in microseconds, relative to UTC 1970-01-01.
Expand All @@ -478,7 +476,7 @@ pub fn milliTimestamp() i64 {
/// before the epoch.
/// See `std.os.clock_gettime` for a POSIX timestamp.
pub fn microTimestamp() i64 {
return @as(i64, @intCast(@divFloor(nanoTimestamp(), ns_per_us)));
return @intCast(@divFloor(nanoTimestamp(), ns_per_us));
}

/// Get a calendar timestamp, in nanoseconds, relative to UTC 1970-01-01.
Expand Down

0 comments on commit 62c481f

Please sign in to comment.