wip
This commit is contained in:
parent
15fb429788
commit
40fc6a8d41
3 changed files with 668 additions and 113 deletions
136
flake.lock
136
flake.lock
|
@ -1,18 +1,19 @@
|
||||||
{
|
{
|
||||||
"nodes": {
|
"nodes": {
|
||||||
"bash": {
|
"flake-compat": {
|
||||||
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1697126158,
|
"lastModified": 1673956053,
|
||||||
"narHash": "sha256-XoRmgs8U78oVMVzk4riJpkmXaX1Pk2Ya/wYMmTYt2mA=",
|
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
|
||||||
"ref": "refs/heads/main",
|
"owner": "edolstra",
|
||||||
"rev": "443dc212854202ddf2bb3bf29ad6d6c1f8829ff6",
|
"repo": "flake-compat",
|
||||||
"revCount": 11,
|
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
|
||||||
"type": "git",
|
"type": "github"
|
||||||
"url": "https://git.ocjtech.us/jeff/nixos-bash-prompt-builder.git"
|
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"type": "git",
|
"owner": "edolstra",
|
||||||
"url": "https://git.ocjtech.us/jeff/nixos-bash-prompt-builder.git"
|
"repo": "flake-compat",
|
||||||
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"flake-utils": {
|
"flake-utils": {
|
||||||
|
@ -20,11 +21,11 @@
|
||||||
"systems": "systems"
|
"systems": "systems"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1694529238,
|
"lastModified": 1701680307,
|
||||||
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
|
"narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "flake-utils",
|
"repo": "flake-utils",
|
||||||
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
|
"rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -33,6 +34,54 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"flake-utils_2": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1659877975,
|
||||||
|
"narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"gitignore": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"zls",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1694102001,
|
||||||
|
"narHash": "sha256-vky6VPK1n1od6vXbqzOXnekrQpTL4hbPAwUhT5J9c9E=",
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "gitignore.nix",
|
||||||
|
"rev": "9e21c80adf67ebcb077d75bd5e7d724d21eeafd6",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "gitignore.nix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"langref": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"narHash": "sha256-mYdDCBdNEIeMbavdhSo8qXqW+3fqPC8BAich7W3umrI=",
|
||||||
|
"type": "file",
|
||||||
|
"url": "https://raw.githubusercontent.com/ziglang/zig/63bd2bff12992aef0ce23ae4b344e9cb5d65f05d/doc/langref.html.in"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"type": "file",
|
||||||
|
"url": "https://raw.githubusercontent.com/ziglang/zig/63bd2bff12992aef0ce23ae4b344e9cb5d65f05d/doc/langref.html.in"
|
||||||
|
}
|
||||||
|
},
|
||||||
"make-shell": {
|
"make-shell": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1634940815,
|
"lastModified": 1634940815,
|
||||||
|
@ -50,11 +99,11 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1697059129,
|
"lastModified": 1702312524,
|
||||||
"narHash": "sha256-9NJcFF9CEYPvHJ5ckE8kvINvI84SZZ87PvqMbH6pro0=",
|
"narHash": "sha256-gkZJRDBUCpTPBvQk25G0B7vfbpEYM5s5OZqghkjZsnE=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "5e4c2ada4fcd54b99d56d7bd62f384511a7e2593",
|
"rev": "a9bf124c46ef298113270b1f84a164865987a91c",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -65,10 +114,11 @@
|
||||||
},
|
},
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"bash": "bash",
|
|
||||||
"flake-utils": "flake-utils",
|
"flake-utils": "flake-utils",
|
||||||
"make-shell": "make-shell",
|
"make-shell": "make-shell",
|
||||||
"nixpkgs": "nixpkgs"
|
"nixpkgs": "nixpkgs",
|
||||||
|
"zig": "zig",
|
||||||
|
"zls": "zls"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"systems": {
|
"systems": {
|
||||||
|
@ -85,6 +135,56 @@
|
||||||
"repo": "default",
|
"repo": "default",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"zig": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-compat": "flake-compat",
|
||||||
|
"flake-utils": "flake-utils_2",
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1702772729,
|
||||||
|
"narHash": "sha256-y29/F6sZHDXefE+e84DOVfU5rCoTPyH0q5QCrNxRG64=",
|
||||||
|
"owner": "mitchellh",
|
||||||
|
"repo": "zig-overlay",
|
||||||
|
"rev": "1a7d61cc7d3ec69ea418e373a4582bfc765469e3",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "mitchellh",
|
||||||
|
"repo": "zig-overlay",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"zls": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": [
|
||||||
|
"flake-utils"
|
||||||
|
],
|
||||||
|
"gitignore": "gitignore",
|
||||||
|
"langref": "langref",
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"zig-overlay": [
|
||||||
|
"zig"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1702566669,
|
||||||
|
"narHash": "sha256-z7Uq+hXr0CWA4uBZjg+t8FEQkCV0CtGnP0RCgzrjnxo=",
|
||||||
|
"owner": "zigtools",
|
||||||
|
"repo": "zls",
|
||||||
|
"rev": "9476a1d47034954367be026b6609062aaefa16ba",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "zigtools",
|
||||||
|
"repo": "zls",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"root": "root",
|
"root": "root",
|
||||||
|
|
57
flake.nix
57
flake.nix
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
description = "zig-ha";
|
description = "zig-datetime";
|
||||||
|
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs = {
|
nixpkgs = {
|
||||||
|
@ -8,45 +8,50 @@
|
||||||
flake-utils = {
|
flake-utils = {
|
||||||
url = "github:numtide/flake-utils";
|
url = "github:numtide/flake-utils";
|
||||||
};
|
};
|
||||||
bash = {
|
|
||||||
url = "git+https://git.ocjtech.us/jeff/nixos-bash-prompt-builder.git";
|
|
||||||
};
|
|
||||||
make-shell = {
|
make-shell = {
|
||||||
url = "github:ursi/nix-make-shell";
|
url = "github:ursi/nix-make-shell";
|
||||||
};
|
};
|
||||||
|
zig = {
|
||||||
|
url = "github:mitchellh/zig-overlay";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
};
|
||||||
|
zls = {
|
||||||
|
url = "github:zigtools/zls";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
inputs.zig-overlay.follows = "zig";
|
||||||
|
inputs.flake-utils.follows = "flake-utils";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = { self, nixpkgs, flake-utils, bash, ... }@inputs:
|
outputs = {
|
||||||
|
self,
|
||||||
|
nixpkgs,
|
||||||
|
flake-utils,
|
||||||
|
zig,
|
||||||
|
zls,
|
||||||
|
...
|
||||||
|
} @ inputs:
|
||||||
flake-utils.lib.eachDefaultSystem (
|
flake-utils.lib.eachDefaultSystem (
|
||||||
system:
|
system: let
|
||||||
let
|
|
||||||
pkgs = import nixpkgs {
|
pkgs = import nixpkgs {
|
||||||
inherit system;
|
inherit system;
|
||||||
};
|
};
|
||||||
in
|
in {
|
||||||
{
|
devShells.default = let
|
||||||
devShells.default =
|
project = "zig-datetime";
|
||||||
let
|
make-shell = import inputs.make-shell {
|
||||||
project = "zig-datetime";
|
inherit system;
|
||||||
prompt = (
|
pkgs = pkgs;
|
||||||
bash.build_ps1_prompt
|
};
|
||||||
bash.ansi_normal_blue
|
in
|
||||||
"${project} - ${bash.username}@${bash.hostname_short}: ${bash.current_working_directory}"
|
|
||||||
"${project}:${bash.current_working_directory}"
|
|
||||||
);
|
|
||||||
make-shell = import inputs.make-shell {
|
|
||||||
inherit system;
|
|
||||||
pkgs = pkgs;
|
|
||||||
};
|
|
||||||
in
|
|
||||||
make-shell {
|
make-shell {
|
||||||
packages = [
|
packages = [
|
||||||
pkgs.zon2nix
|
pkgs.zon2nix
|
||||||
pkgs.zig_0_11
|
zig.packages.${pkgs.system}.master
|
||||||
pkgs.zls
|
zls.packages.${pkgs.system}.zls
|
||||||
];
|
];
|
||||||
env = {
|
env = {
|
||||||
PS1 = prompt;
|
name = project;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
588
src/main.zig
588
src/main.zig
|
@ -1,5 +1,93 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
|
// https://www.nist.gov/pml/owm/metric-si-prefixes
|
||||||
|
|
||||||
|
pub const SIPrefix = enum(i8) {
|
||||||
|
quetta = 30,
|
||||||
|
ronna = 27,
|
||||||
|
yotta = 24,
|
||||||
|
zetta = 21,
|
||||||
|
exa = 18,
|
||||||
|
peta = 15,
|
||||||
|
tera = 12,
|
||||||
|
giga = 9,
|
||||||
|
mega = 6,
|
||||||
|
kilo = 3,
|
||||||
|
hecto = 2,
|
||||||
|
deka = 1,
|
||||||
|
deci = -1,
|
||||||
|
centi = -2,
|
||||||
|
milli = -3,
|
||||||
|
micro = -6,
|
||||||
|
nano = -9,
|
||||||
|
pico = -12,
|
||||||
|
femto = -15,
|
||||||
|
atto = -18,
|
||||||
|
zepto = -21,
|
||||||
|
yocto = -24,
|
||||||
|
ronto = -27,
|
||||||
|
quecto = -30,
|
||||||
|
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
pub fn exponent(self: Self) i8 {
|
||||||
|
return @intFromEnum(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn symbol(self: Self) []const u8 {
|
||||||
|
return switch (self) {
|
||||||
|
.quetta => "Q",
|
||||||
|
.ronna => "R",
|
||||||
|
.yotta => "Y",
|
||||||
|
.zetta => "Z",
|
||||||
|
.exa => "E",
|
||||||
|
.peta => "P",
|
||||||
|
.tera => "T",
|
||||||
|
.giga => "G",
|
||||||
|
.mega => "M",
|
||||||
|
.kilo => "k",
|
||||||
|
.hecto => "h",
|
||||||
|
.deka => "da",
|
||||||
|
.deci => "d",
|
||||||
|
.centi => "c",
|
||||||
|
.milli => "m",
|
||||||
|
.micro => "µ",
|
||||||
|
.nano => "n",
|
||||||
|
.pico => "p",
|
||||||
|
.femto => "f",
|
||||||
|
.atto => "a",
|
||||||
|
.zepto => "z",
|
||||||
|
.yocto => "y",
|
||||||
|
.ronto => "r",
|
||||||
|
.quecto => "q",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn convert(from: i8, to: i8, value: i128) struct { result: i128, remainder: i128 } {
|
||||||
|
const exponent = from - to;
|
||||||
|
if (exponent == 0) return value;
|
||||||
|
if (exponent < 0) {
|
||||||
|
const factor = std.math.pow(i128, 10, @abs(exponent));
|
||||||
|
const remainder = @rem(value, factor);
|
||||||
|
const result = @divTrunc(value, factor);
|
||||||
|
return .{ result, remainder };
|
||||||
|
}
|
||||||
|
if (exponent > 0) {
|
||||||
|
const factor = std.math.pow(i128, 10, exponent);
|
||||||
|
return .{ factor * value, 0 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// test "convert-1" {
|
||||||
|
// const result = convert(.milli, .micro, 1);
|
||||||
|
// try std.testing.expectEqual(i128, result.result, 1000);
|
||||||
|
// try std.testing.expectEqual(i128, result.remainder, 0);
|
||||||
|
// }
|
||||||
|
// pub fn conversionFactor(from: i8, to: i8) !i30 {
|
||||||
|
// if (from < to) return error.InvalidConversion;
|
||||||
|
// if (from == to) return 1;
|
||||||
|
// }
|
||||||
pub const Day = u6;
|
pub const Day = u6;
|
||||||
|
|
||||||
pub const Month = enum(u4) {
|
pub const Month = enum(u4) {
|
||||||
|
@ -179,6 +267,24 @@ pub fn writeTwelveHour(hour: Hour, case: enum { lower, upper }, writer: anytype)
|
||||||
|
|
||||||
pub const Nanosecond = u30;
|
pub const Nanosecond = u30;
|
||||||
|
|
||||||
|
fn readInt(text: []const u8, maxlen: usize) []const u8 {
|
||||||
|
if (text.len == 0) return text[0..0];
|
||||||
|
|
||||||
|
for (0..@min(text.len, maxlen)) |i| {
|
||||||
|
if (!std.ascii.isDigit(text[i])) return text[0 .. i - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return text[0..maxlen];
|
||||||
|
}
|
||||||
|
|
||||||
|
fn readFrac(text: []const u8, length: usize) !Nanosecond {
|
||||||
|
if (length == 0) return error.TooShort;
|
||||||
|
if (length > 9) return error.TooLong;
|
||||||
|
const v = readInt(text, length);
|
||||||
|
if (v.len != length) return error.TooShort;
|
||||||
|
return try std.fmt.parseInt(Nanosecond, v, 10) * try std.math.powi(Nanosecond, 10, 9 - @as(Nanosecond, @intCast(length)));
|
||||||
|
}
|
||||||
|
|
||||||
// https://github.com/nektro/zig-time
|
// https://github.com/nektro/zig-time
|
||||||
|
|
||||||
pub const DateTime = struct {
|
pub const DateTime = struct {
|
||||||
|
@ -193,7 +299,7 @@ pub const DateTime = struct {
|
||||||
|
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
pub fn format(self: Self, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
|
pub fn formatX(self: Self, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
|
||||||
_ = options;
|
_ = options;
|
||||||
|
|
||||||
if (fmt.len == 0) @compileError("DateTime: format string can't be empty");
|
if (fmt.len == 0) @compileError("DateTime: format string can't be empty");
|
||||||
|
@ -258,7 +364,7 @@ pub const DateTime = struct {
|
||||||
if (self.year < 0) {
|
if (self.year < 0) {
|
||||||
try writer.writeAll("-");
|
try writer.writeAll("-");
|
||||||
}
|
}
|
||||||
try writer.print("{d:0>4}", .{std.math.absCast(self.year)});
|
try writer.print("{d:0>4}", .{@abs(self.year)});
|
||||||
},
|
},
|
||||||
|
|
||||||
.A => try writeTwelveHour(self.hour, .upper),
|
.A => try writeTwelveHour(self.hour, .upper),
|
||||||
|
@ -277,15 +383,24 @@ pub const DateTime = struct {
|
||||||
.s => try writer.print("{d}", .{self.second}),
|
.s => try writer.print("{d}", .{self.second}),
|
||||||
.ss => try writer.print("{d:0>2}", .{self.second}),
|
.ss => try writer.print("{d:0>2}", .{self.second}),
|
||||||
|
|
||||||
.S => try writer.print("{d:>1}", .{self.nanosecond / tenthsPerNanoSecond}),
|
// .S => try writer.print("{d:>1}", .{self.nanosecond / tenthsPerNanoSecond}),
|
||||||
.SS => try writer.print("{d:0>2}", .{self.nanosecond / hundredthsPerNanoSecond}),
|
// .SS => try writer.print("{d:0>2}", .{self.nanosecond / hundredthsPerNanoSecond}),
|
||||||
.SSS => try writer.print("{d:0>3}", .{self.nanosecond / milliSecondsPerNanoSecond}),
|
// .SSS => try writer.print("{d:0>3}", .{self.nanosecond / milliSecondsPerNanoSecond}),
|
||||||
.SSSS => try writer.print("{d:0>4}", .{self.nanosecond / (milliSecondsPerNanoSecond / 10)}),
|
// .SSSS => try writer.print("{d:0>4}", .{self.nanosecond / (milliSecondsPerNanoSecond / 10)}),
|
||||||
.SSSSS => try writer.print("{d:0>5}", .{self.nanosecond / (milliSecondsPerNanoSecond / 100)}),
|
// .SSSSS => try writer.print("{d:0>5}", .{self.nanosecond / (milliSecondsPerNanoSecond / 100)}),
|
||||||
.SSSSSS => try writer.print("{d:0>6}", .{self.nanosecond / microSecondsPerNanoSecond}),
|
// .SSSSSS => try writer.print("{d:0>6}", .{self.nanosecond / microSecondsPerNanoSecond}),
|
||||||
.SSSSSSS => try writer.print("{d:0>7}", .{self.nanosecond / (microSecondsPerNanoSecond / 10)}),
|
// .SSSSSSS => try writer.print("{d:0>7}", .{self.nanosecond / (microSecondsPerNanoSecond / 10)}),
|
||||||
.SSSSSSSS => try writer.print("{d:0>8}", .{self.nanosecond / (microSecondsPerNanoSecond / 100)}),
|
// .SSSSSSSS => try writer.print("{d:0>8}", .{self.nanosecond / (microSecondsPerNanoSecond / 100)}),
|
||||||
.SSSSSSSSS => try writer.print("{d:0>9}", .{self.nanosecond}),
|
// .SSSSSSSSS => try writer.print("{d:0>9}", .{self.nanosecond}),
|
||||||
|
.S => try writer.print("{d:>1}", .{tag.cnv(self.nanosecond)}),
|
||||||
|
.SS => try writer.print("{d:>2}", .{tag.cnv(self.nanosecond)}),
|
||||||
|
.SSS => try writer.print("{d:>3}", .{tag.cnv(self.nanosecond)}),
|
||||||
|
.SSSS => try writer.print("{d:>4}", .{tag.cnv(self.nanosecond)}),
|
||||||
|
.SSSSS => try writer.print("{d:>5}", .{tag.cnv(self.nanosecond)}),
|
||||||
|
.SSSSSS => try writer.print("{d:>6}", .{tag.cnv(self.nanosecond)}),
|
||||||
|
.SSSSSSS => try writer.print("{d:>7}", .{tag.cnv(self.nanosecond)}),
|
||||||
|
.SSSSSSSS => try writer.print("{d:>8}", .{tag.cnv(self.nanosecond)}),
|
||||||
|
.SSSSSSSSS => try writer.print("{d:>9}", .{tag.cnv(self.nanosecond)}),
|
||||||
|
|
||||||
// .z => try writer.writeAll(@tagName(self.timezone)),
|
// .z => try writer.writeAll(@tagName(self.timezone)),
|
||||||
// .Z => try writer.writeAll("+00:00"),
|
// .Z => try writer.writeAll("+00:00"),
|
||||||
|
@ -313,10 +428,104 @@ pub const DateTime = struct {
|
||||||
var list = std.ArrayList(u8).init(alloc);
|
var list = std.ArrayList(u8).init(alloc);
|
||||||
defer list.deinit();
|
defer list.deinit();
|
||||||
|
|
||||||
try self.format(fmt, .{}, list.writer());
|
try self.formatX(fmt, .{}, list.writer());
|
||||||
return list.toOwnedSlice();
|
return list.toOwnedSlice();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn parse(comptime fmt: []const u8, value: []const u8) !Self {
|
||||||
|
if (fmt.len == 0) @compileError("DateTime: format string can't be empty");
|
||||||
|
|
||||||
|
@setEvalBranchQuota(100000);
|
||||||
|
|
||||||
|
var date: Self = .{
|
||||||
|
.nanosecond = 0,
|
||||||
|
.second = 0,
|
||||||
|
.minute = 0,
|
||||||
|
.hour = 0,
|
||||||
|
.day = 1,
|
||||||
|
.month = .Jan,
|
||||||
|
.year = 1970,
|
||||||
|
.weekday = .Thu,
|
||||||
|
};
|
||||||
|
|
||||||
|
var left = value;
|
||||||
|
|
||||||
|
comptime var start = 0;
|
||||||
|
comptime var end = 0;
|
||||||
|
comptime var next: ?FormatSeq = null;
|
||||||
|
inline for (fmt, 0..) |char, index| {
|
||||||
|
end = index + 1;
|
||||||
|
if (comptime std.meta.stringToEnum(FormatSeq, fmt[start..end])) |tag| {
|
||||||
|
next = tag;
|
||||||
|
if (index < fmt.len - 1) continue;
|
||||||
|
}
|
||||||
|
if (next) |tag| {
|
||||||
|
switch (tag) {
|
||||||
|
.YY => {
|
||||||
|
const year = readInt(left, 2);
|
||||||
|
date.year = try std.fmt.parseInt(Year, year, 10) + 2000;
|
||||||
|
left = left[year.len..];
|
||||||
|
date.weekday = DayOfWeek.dayOfWeek(date.year, date.month, date.day);
|
||||||
|
},
|
||||||
|
.YYYY, .YYY => {
|
||||||
|
const year = readInt(left, 4);
|
||||||
|
date.year = try std.fmt.parseInt(Year, year, 10);
|
||||||
|
left = left[year.len..];
|
||||||
|
date.weekday = DayOfWeek.dayOfWeek(date.year, date.month, date.day);
|
||||||
|
},
|
||||||
|
.SSSSSSSSS => {
|
||||||
|
date.nanosecond = try readFrac(left, 9);
|
||||||
|
left = left[9..];
|
||||||
|
},
|
||||||
|
.SSSSSSSS => {
|
||||||
|
date.nanosecond = try readFrac(left, 8);
|
||||||
|
left = left[8..];
|
||||||
|
},
|
||||||
|
.SSSSSSS => {
|
||||||
|
date.nanosecond = try readFrac(left, 7);
|
||||||
|
left = left[7..];
|
||||||
|
},
|
||||||
|
.SSSSSS => {
|
||||||
|
date.nanosecond = try readFrac(left, 6);
|
||||||
|
left = left[6..];
|
||||||
|
},
|
||||||
|
.SSSSS => {
|
||||||
|
date.nanosecond = try readFrac(left, 5);
|
||||||
|
left = left[5..];
|
||||||
|
},
|
||||||
|
.SSSS => {
|
||||||
|
date.nanosecond = try readFrac(left, 4);
|
||||||
|
left = left[4..];
|
||||||
|
},
|
||||||
|
.SSS => {
|
||||||
|
date.nanosecond = try readFrac(left, 3);
|
||||||
|
left = left[3..];
|
||||||
|
},
|
||||||
|
.SS => {
|
||||||
|
date.nanosecond = try readFrac(left, 2);
|
||||||
|
left = left[2..];
|
||||||
|
},
|
||||||
|
.S => {
|
||||||
|
date.nanosecond = try readFrac(left, 1);
|
||||||
|
left = left[1..];
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
next = null;
|
||||||
|
start = index;
|
||||||
|
}
|
||||||
|
switch (char) {
|
||||||
|
',', ' ', ':', '-', '.', 'T', 'W' => {
|
||||||
|
start = index + 1;
|
||||||
|
continue;
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
|
||||||
const FormatSeq = enum {
|
const FormatSeq = enum {
|
||||||
M, // 1 2 ... 11 12 (month, numeric)
|
M, // 1 2 ... 11 12 (month, numeric)
|
||||||
Mo, // 1st 2nd ... 11th 12th (month, numeric ordinal)
|
Mo, // 1st 2nd ... 11th 12th (month, numeric ordinal)
|
||||||
|
@ -379,6 +588,37 @@ pub const DateTime = struct {
|
||||||
// ZZ, // -0700 -0600 ... +0600 +0700
|
// ZZ, // -0700 -0600 ... +0600 +0700
|
||||||
// x, // unix milli
|
// x, // unix milli
|
||||||
// X, // unix
|
// X, // unix
|
||||||
|
|
||||||
|
pub fn cnv(comptime tag: FormatSeq, value: u30) u30 {
|
||||||
|
const name = comptime @tagName(tag);
|
||||||
|
comptime var count: i8 = undefined;
|
||||||
|
inline for (name, 1..) |c, i| {
|
||||||
|
if (c != 'S') @compileError(name ++ " is not a fractional second format sequence");
|
||||||
|
count = i;
|
||||||
|
}
|
||||||
|
if (count > 9) @compileError("fractional seconds smaller than nanoseconds are not supported");
|
||||||
|
if (count == 9) return value;
|
||||||
|
const exponent = 9 - count;
|
||||||
|
const factor = std.math.pow(u30, 10, exponent);
|
||||||
|
return @as(u30, @divTrunc(value, factor));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "cnv" {
|
||||||
|
const cases = [_]struct { tag: FormatSeq, expected: u30, value: u30 }{
|
||||||
|
.{ .tag = .S, .expected = 1, .value = 123456789 },
|
||||||
|
.{ .tag = .SS, .expected = 12, .value = 123456789 },
|
||||||
|
.{ .tag = .SSS, .expected = 123, .value = 123456789 },
|
||||||
|
.{ .tag = .SSSS, .expected = 1234, .value = 123456789 },
|
||||||
|
.{ .tag = .SSSSS, .expected = 12345, .value = 123456789 },
|
||||||
|
.{ .tag = .SSSSSS, .expected = 123456, .value = 123456789 },
|
||||||
|
.{ .tag = .SSSSSSS, .expected = 1234567, .value = 123456789 },
|
||||||
|
.{ .tag = .SSSSSSSS, .expected = 12345678, .value = 123456789 },
|
||||||
|
.{ .tag = .SSSSSSSSS, .expected = 123456789, .value = 123456789 },
|
||||||
|
};
|
||||||
|
inline for (cases) |case| {
|
||||||
|
try std.testing.expectEqual(case.expected, cnv(case.tag, case.value));
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn dayOfThisYear(self: Self) u9 {
|
pub fn dayOfThisYear(self: Self) u9 {
|
||||||
|
@ -386,12 +626,193 @@ pub const DateTime = struct {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
test "parseTest" {
|
||||||
|
const cases = [_]struct { value: []const u8, fmt: []const u8, expected: DateTime }{
|
||||||
|
.{
|
||||||
|
.value = "1970",
|
||||||
|
.fmt = "YYYY",
|
||||||
|
.expected = .{
|
||||||
|
.nanosecond = 0,
|
||||||
|
.second = 0,
|
||||||
|
.minute = 0,
|
||||||
|
.hour = 0,
|
||||||
|
.day = 1,
|
||||||
|
.month = .Jan,
|
||||||
|
.year = 1970,
|
||||||
|
.weekday = .Thu,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.value = "2001",
|
||||||
|
.fmt = "YYYY",
|
||||||
|
.expected = .{
|
||||||
|
.nanosecond = 0,
|
||||||
|
.second = 0,
|
||||||
|
.minute = 0,
|
||||||
|
.hour = 0,
|
||||||
|
.day = 1,
|
||||||
|
.month = .Jan,
|
||||||
|
.year = 2001,
|
||||||
|
.weekday = .Mon,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.value = "70",
|
||||||
|
.fmt = "YY",
|
||||||
|
.expected = .{
|
||||||
|
.nanosecond = 0,
|
||||||
|
.second = 0,
|
||||||
|
.minute = 0,
|
||||||
|
.hour = 0,
|
||||||
|
.day = 1,
|
||||||
|
.month = .Jan,
|
||||||
|
.year = 2070,
|
||||||
|
.weekday = .Wed,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.value = "123456789",
|
||||||
|
.fmt = "SSSSSSSSS",
|
||||||
|
.expected = .{
|
||||||
|
.nanosecond = 123456789,
|
||||||
|
.second = 0,
|
||||||
|
.minute = 0,
|
||||||
|
.hour = 0,
|
||||||
|
.day = 1,
|
||||||
|
.month = .Jan,
|
||||||
|
.year = 1970,
|
||||||
|
.weekday = .Thu,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.value = "12345678",
|
||||||
|
.fmt = "SSSSSSSS",
|
||||||
|
.expected = .{
|
||||||
|
.nanosecond = 123456780,
|
||||||
|
.second = 0,
|
||||||
|
.minute = 0,
|
||||||
|
.hour = 0,
|
||||||
|
.day = 1,
|
||||||
|
.month = .Jan,
|
||||||
|
.year = 1970,
|
||||||
|
.weekday = .Thu,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.value = "1234567",
|
||||||
|
.fmt = "SSSSSSS",
|
||||||
|
.expected = .{
|
||||||
|
.nanosecond = 123456700,
|
||||||
|
.second = 0,
|
||||||
|
.minute = 0,
|
||||||
|
.hour = 0,
|
||||||
|
.day = 1,
|
||||||
|
.month = .Jan,
|
||||||
|
.year = 1970,
|
||||||
|
.weekday = .Thu,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.value = "123456",
|
||||||
|
.fmt = "SSSSSS",
|
||||||
|
.expected = .{
|
||||||
|
.nanosecond = 123456000,
|
||||||
|
.second = 0,
|
||||||
|
.minute = 0,
|
||||||
|
.hour = 0,
|
||||||
|
.day = 1,
|
||||||
|
.month = .Jan,
|
||||||
|
.year = 1970,
|
||||||
|
.weekday = .Thu,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.value = "12345",
|
||||||
|
.fmt = "SSSSS",
|
||||||
|
.expected = .{
|
||||||
|
.nanosecond = 123450000,
|
||||||
|
.second = 0,
|
||||||
|
.minute = 0,
|
||||||
|
.hour = 0,
|
||||||
|
.day = 1,
|
||||||
|
.month = .Jan,
|
||||||
|
.year = 1970,
|
||||||
|
.weekday = .Thu,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.value = "1234",
|
||||||
|
.fmt = "SSSS",
|
||||||
|
.expected = .{
|
||||||
|
.nanosecond = 123400000,
|
||||||
|
.second = 0,
|
||||||
|
.minute = 0,
|
||||||
|
.hour = 0,
|
||||||
|
.day = 1,
|
||||||
|
.month = .Jan,
|
||||||
|
.year = 1970,
|
||||||
|
.weekday = .Thu,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.value = "123",
|
||||||
|
.fmt = "SSS",
|
||||||
|
.expected = .{
|
||||||
|
.nanosecond = 123000000,
|
||||||
|
.second = 0,
|
||||||
|
.minute = 0,
|
||||||
|
.hour = 0,
|
||||||
|
.day = 1,
|
||||||
|
.month = .Jan,
|
||||||
|
.year = 1970,
|
||||||
|
.weekday = .Thu,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.value = "12",
|
||||||
|
.fmt = "SS",
|
||||||
|
.expected = .{
|
||||||
|
.nanosecond = 120000000,
|
||||||
|
.second = 0,
|
||||||
|
.minute = 0,
|
||||||
|
.hour = 0,
|
||||||
|
.day = 1,
|
||||||
|
.month = .Jan,
|
||||||
|
.year = 1970,
|
||||||
|
.weekday = .Thu,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.value = "1",
|
||||||
|
.fmt = "S",
|
||||||
|
.expected = .{
|
||||||
|
.nanosecond = 100000000,
|
||||||
|
.second = 0,
|
||||||
|
.minute = 0,
|
||||||
|
.hour = 0,
|
||||||
|
.day = 1,
|
||||||
|
.month = .Jan,
|
||||||
|
.year = 1970,
|
||||||
|
.weekday = .Thu,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
inline for (cases) |case| {
|
||||||
|
const result = try DateTime.parse(case.fmt, case.value);
|
||||||
|
std.testing.expectEqual(case.expected, result) catch |err| {
|
||||||
|
std.debug.print("\n{s} {s} {} {}\n", .{ case.value, case.fmt, case.expected, result });
|
||||||
|
return err;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
test "formatTest" {
|
test "formatTest" {
|
||||||
var buffer: [1024]u8 = undefined;
|
var buffer: [1024]u8 = undefined;
|
||||||
var fba = std.heap.FixedBufferAllocator.init(&buffer);
|
var fba = std.heap.FixedBufferAllocator.init(&buffer);
|
||||||
const allocator = fba.allocator();
|
const allocator = fba.allocator();
|
||||||
|
|
||||||
const epoch = DateTime{
|
const test_date = DateTime{
|
||||||
.nanosecond = 123456789,
|
.nanosecond = 123456789,
|
||||||
.second = 0,
|
.second = 0,
|
||||||
.minute = 0,
|
.minute = 0,
|
||||||
|
@ -401,49 +822,50 @@ test "formatTest" {
|
||||||
.year = 1970,
|
.year = 1970,
|
||||||
.weekday = .Fri,
|
.weekday = .Fri,
|
||||||
};
|
};
|
||||||
|
|
||||||
const cases = [_]struct { datetime: DateTime, fmt: []const u8, result: []const u8 }{
|
const cases = [_]struct { datetime: DateTime, fmt: []const u8, result: []const u8 }{
|
||||||
.{
|
.{
|
||||||
.datetime = epoch,
|
.datetime = test_date,
|
||||||
.fmt = "YYYY-MM-DDTHH:mm:ss.SSSSSSSSS",
|
.fmt = "YYYY-MM-DDTHH:mm:ss.SSSSSSSSS",
|
||||||
.result = "1970-01-01T00:00:00.123456789",
|
.result = "1970-01-01T00:00:00.123456789",
|
||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
.datetime = epoch,
|
.datetime = test_date,
|
||||||
.fmt = "YYYY-MM-DDTHH:mm:ss.SSSSSSSS",
|
.fmt = "YYYY-MM-DDTHH:mm:ss.SSSSSSSS",
|
||||||
.result = "1970-01-01T00:00:00.12345678",
|
.result = "1970-01-01T00:00:00.12345678",
|
||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
.datetime = epoch,
|
.datetime = test_date,
|
||||||
.fmt = "YYYY-MM-DDTHH:mm:ss.SSSSSSS",
|
.fmt = "YYYY-MM-DDTHH:mm:ss.SSSSSSS",
|
||||||
.result = "1970-01-01T00:00:00.1234567",
|
.result = "1970-01-01T00:00:00.1234567",
|
||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
.datetime = epoch,
|
.datetime = test_date,
|
||||||
.fmt = "YYYY-MM-DDTHH:mm:ss.SSSSSS",
|
.fmt = "YYYY-MM-DDTHH:mm:ss.SSSSSS",
|
||||||
.result = "1970-01-01T00:00:00.123456",
|
.result = "1970-01-01T00:00:00.123456",
|
||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
.datetime = epoch,
|
.datetime = test_date,
|
||||||
.fmt = "YYYY-MM-DDTHH:mm:ss.SSSSS",
|
.fmt = "YYYY-MM-DDTHH:mm:ss.SSSSS",
|
||||||
.result = "1970-01-01T00:00:00.12345",
|
.result = "1970-01-01T00:00:00.12345",
|
||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
.datetime = epoch,
|
.datetime = test_date,
|
||||||
.fmt = "YYYY-MM-DDTHH:mm:ss.SSSS",
|
.fmt = "YYYY-MM-DDTHH:mm:ss.SSSS",
|
||||||
.result = "1970-01-01T00:00:00.1234",
|
.result = "1970-01-01T00:00:00.1234",
|
||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
.datetime = epoch,
|
.datetime = test_date,
|
||||||
.fmt = "YYYY-MM-DDTHH:mm:ss.SSS",
|
.fmt = "YYYY-MM-DDTHH:mm:ss.SSS",
|
||||||
.result = "1970-01-01T00:00:00.123",
|
.result = "1970-01-01T00:00:00.123",
|
||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
.datetime = epoch,
|
.datetime = test_date,
|
||||||
.fmt = "YYYY-MM-DDTHH:mm:ss.SS",
|
.fmt = "YYYY-MM-DDTHH:mm:ss.SS",
|
||||||
.result = "1970-01-01T00:00:00.12",
|
.result = "1970-01-01T00:00:00.12",
|
||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
.datetime = epoch,
|
.datetime = test_date,
|
||||||
.fmt = "YYYY-MM-DDTHH:mm:ss.S",
|
.fmt = "YYYY-MM-DDTHH:mm:ss.S",
|
||||||
.result = "1970-01-01T00:00:00.1",
|
.result = "1970-01-01T00:00:00.1",
|
||||||
},
|
},
|
||||||
|
@ -453,7 +875,7 @@ test "formatTest" {
|
||||||
var array = std.ArrayList(u8).init(allocator);
|
var array = std.ArrayList(u8).init(allocator);
|
||||||
defer array.deinit();
|
defer array.deinit();
|
||||||
|
|
||||||
try case.datetime.format(case.fmt, .{}, array.writer());
|
try case.datetime.formatX(case.fmt, .{}, array.writer());
|
||||||
|
|
||||||
std.testing.expect(std.mem.eql(u8, array.items, case.result)) catch |err| {
|
std.testing.expect(std.mem.eql(u8, array.items, case.result)) catch |err| {
|
||||||
std.debug.print("{s} {s} {s}\n", .{
|
std.debug.print("{s} {s} {s}\n", .{
|
||||||
|
@ -554,7 +976,7 @@ pub const Instant = struct {
|
||||||
.minute = minute,
|
.minute = minute,
|
||||||
.second = second,
|
.second = second,
|
||||||
.nanosecond = nanosecond,
|
.nanosecond = nanosecond,
|
||||||
.weekday = weekdayFromDays(days),
|
.weekday = DayOfWeek.weekdayFromDays(days),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// pub fn format(self: @This()) []const u8 {
|
// pub fn format(self: @This()) []const u8 {
|
||||||
|
@ -807,6 +1229,17 @@ const DayOfWeek = enum(u3) {
|
||||||
pub fn isoWeekdayNumber(self: Self) u3 {
|
pub fn isoWeekdayNumber(self: Self) u3 {
|
||||||
return if (self == .Sun) 7 else @intFromEnum(self);
|
return if (self == .Sun) 7 else @intFromEnum(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn weekdayFromDays(days: i32) DayOfWeek {
|
||||||
|
return @as(
|
||||||
|
DayOfWeek,
|
||||||
|
@enumFromInt(if (days >= -4) @rem(days + 4, 7) else @rem(days + 5, 7) + 6),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
pub fn dayOfWeek(year: Year, month: Month, day: Day) Self {
|
||||||
|
const days = daysFromCivil(year, month, day);
|
||||||
|
return Self.weekdayFromDays(days);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn weekdayDifference(start: DayOfWeek, end: DayOfWeek) u3 {
|
pub fn weekdayDifference(start: DayOfWeek, end: DayOfWeek) u3 {
|
||||||
|
@ -836,13 +1269,6 @@ test "weekdayDifference" {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn weekdayFromDays(z: i32) DayOfWeek {
|
|
||||||
return @as(
|
|
||||||
DayOfWeek,
|
|
||||||
@enumFromInt(if (z >= -4) @rem(z + 4, 7) else @rem(z + 5, 7) + 6),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
test "weekdayFromDays" {
|
test "weekdayFromDays" {
|
||||||
const tests = [_]struct { days: i32, result: DayOfWeek }{
|
const tests = [_]struct { days: i32, result: DayOfWeek }{
|
||||||
.{
|
.{
|
||||||
|
@ -864,7 +1290,7 @@ test "weekdayFromDays" {
|
||||||
};
|
};
|
||||||
|
|
||||||
for (tests) |case| {
|
for (tests) |case| {
|
||||||
const result = weekdayFromDays(case.days);
|
const result = DayOfWeek.weekdayFromDays(case.days);
|
||||||
try std.testing.expect(std.meta.eql(case.result, result));
|
try std.testing.expect(std.meta.eql(case.result, result));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1000,7 +1426,7 @@ test "testPrintOrdinalSuperscript" {
|
||||||
inline for (cases) |case| {
|
inline for (cases) |case| {
|
||||||
var buffer: [16]u8 = undefined;
|
var buffer: [16]u8 = undefined;
|
||||||
var stream = std.io.fixedBufferStream(&buffer);
|
var stream = std.io.fixedBufferStream(&buffer);
|
||||||
var writer = stream.writer();
|
const writer = stream.writer();
|
||||||
|
|
||||||
try printOrdinalSuperscript(writer, case.number);
|
try printOrdinalSuperscript(writer, case.number);
|
||||||
std.testing.expect(std.mem.eql(u8, stream.getWritten(), case.result)) catch |err| {
|
std.testing.expect(std.mem.eql(u8, stream.getWritten(), case.result)) catch |err| {
|
||||||
|
@ -1015,7 +1441,7 @@ fn printLongName(writer: anytype, index: u16, names: []const []const u8) !void {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wrap(val: u16, at: u16) u16 {
|
fn wrap(val: u16, at: u16) u16 {
|
||||||
var tmp = val % at;
|
const tmp = val % at;
|
||||||
return if (tmp == 0) at else tmp;
|
return if (tmp == 0) at else tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1023,8 +1449,32 @@ test "asDateTime" {
|
||||||
_ = Instant.utc().asDateTime();
|
_ = Instant.utc().asDateTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn isLeap(year: i32) bool {
|
pub fn isLeap(year: Year) bool {
|
||||||
return @rem(year, 4) == 0 and (@rem(year, 100) != 0 or @rem(year, 400) == 0);
|
// taken from https://github.com/ziglang/zig/pull/18451
|
||||||
|
|
||||||
|
// In the western Gregorian Calendar leap a year is
|
||||||
|
// a multiple of 4, excluding multiples of 100, and
|
||||||
|
// adding multiples of 400. In code:
|
||||||
|
//
|
||||||
|
// if (@mod(year, 4) != 0)
|
||||||
|
// return false;
|
||||||
|
// if (@mod(year, 100) != 0)
|
||||||
|
// return true;
|
||||||
|
// return (0 == @mod(year, 400));
|
||||||
|
|
||||||
|
// The following is equivalent to the above
|
||||||
|
// but uses bitwise operations when testing
|
||||||
|
// for divisibility, masking with 3 as test
|
||||||
|
// for multiples of 4 and with 15 as a test
|
||||||
|
// for multiples of 16. Multiples of 16 and
|
||||||
|
// 100 are, conveniently, multiples of 400.
|
||||||
|
|
||||||
|
const mask: Year = switch (year % 100) {
|
||||||
|
0 => 0b1111,
|
||||||
|
else => 0b11,
|
||||||
|
};
|
||||||
|
return 0 == year & mask;
|
||||||
|
// return @rem(year, 4) == 0 and (@rem(year, 100) != 0 or @rem(year, 400) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "isLeap" {
|
test "isLeap" {
|
||||||
|
@ -1034,36 +1484,36 @@ test "isLeap" {
|
||||||
try std.testing.expectEqual(true, isLeap(2400));
|
try std.testing.expectEqual(true, isLeap(2400));
|
||||||
}
|
}
|
||||||
|
|
||||||
test "bigTest" {
|
// test "bigTest" {
|
||||||
const ystart = -1000000;
|
// const ystart = -1000000;
|
||||||
var prev_z: i32 = daysFromCivil(ystart, .Jan, 1) - 1;
|
// var prev_z: i32 = daysFromCivil(ystart, .Jan, 1) - 1;
|
||||||
try std.testing.expect(prev_z < 0);
|
// try std.testing.expect(prev_z < 0);
|
||||||
var prev_wd = weekdayFromDays(prev_z);
|
// var prev_wd = DayOfWeek.weekdayFromDays(prev_z);
|
||||||
try std.testing.expect(0 <= @intFromEnum(prev_wd) and @intFromEnum(prev_wd) <= 6);
|
// try std.testing.expect(0 <= @intFromEnum(prev_wd) and @intFromEnum(prev_wd) <= 6);
|
||||||
var y: Year = ystart;
|
// var y: Year = ystart;
|
||||||
while (y <= -ystart) {
|
// while (y <= -ystart) {
|
||||||
for ([_]Month{ .Jan, .Feb, .Mar, .Apr, .May, .Jun, .Jul, .Aug, .Sep, .Oct, .Nov, .Dec }) |m| {
|
// for ([_]Month{ .Jan, .Feb, .Mar, .Apr, .May, .Jun, .Jul, .Aug, .Sep, .Oct, .Nov, .Dec }) |m| {
|
||||||
var d: Day = 1;
|
// var d: Day = 1;
|
||||||
const e = m.lastDay(y);
|
// const e = m.lastDay(y);
|
||||||
while (d <= e) {
|
// while (d <= e) {
|
||||||
// std.debug.print("{d} {d} {d}\n", .{ y, @intFromEnum(m), d });
|
// // std.debug.print("{d} {d} {d}\n", .{ y, @intFromEnum(m), d });
|
||||||
const z = daysFromCivil(y, m, d);
|
// const z = daysFromCivil(y, m, d);
|
||||||
// std.debug.print("{d} {d}\n", .{ prev_z, z });
|
// // std.debug.print("{d} {d}\n", .{ prev_z, z });
|
||||||
try std.testing.expect(prev_z < z);
|
// try std.testing.expect(prev_z < z);
|
||||||
try std.testing.expect(z == prev_z + 1);
|
// try std.testing.expect(z == prev_z + 1);
|
||||||
const date = civilFromDays(z);
|
// const date = civilFromDays(z);
|
||||||
try std.testing.expect(y == date.year);
|
// try std.testing.expect(y == date.year);
|
||||||
try std.testing.expect(m == date.month);
|
// try std.testing.expect(m == date.month);
|
||||||
try std.testing.expect(d == date.day);
|
// try std.testing.expect(d == date.day);
|
||||||
const wd = weekdayFromDays(z);
|
// const wd = DayOfWeek.weekdayFromDays(z);
|
||||||
try std.testing.expect(0 <= @intFromEnum(wd) and @intFromEnum(wd) <= 6);
|
// try std.testing.expect(0 <= @intFromEnum(wd) and @intFromEnum(wd) <= 6);
|
||||||
try std.testing.expect(wd == prev_wd.next());
|
// try std.testing.expect(wd == prev_wd.next());
|
||||||
try std.testing.expect(prev_wd == wd.prev());
|
// try std.testing.expect(prev_wd == wd.prev());
|
||||||
prev_z = z;
|
// prev_z = z;
|
||||||
prev_wd = wd;
|
// prev_wd = wd;
|
||||||
d += 1;
|
// d += 1;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
y += 1;
|
// y += 1;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
Loading…
Reference in a new issue