fix(datetime): floor sub-second negative timestamps instead of snapping to epoch - #262

Merged
sachiniyer merged 1 commit into
mainfrom
siyer/fix-datetime-negative-timestamp
Apr 22, 2026
Merged

fix(datetime): floor sub-second negative timestamps instead of snapping to epoch#262
sachiniyer merged 1 commit into
mainfrom
siyer/fix-datetime-negative-timestamp

Conversation

@sachiniyer

@sachiniyersachiniyer commented Apr 22, 2026

Copy link
Copy Markdown
Contributor

Summary

format_timestamp converted timestamp_ms → seconds by integer division, which truncates toward zero. Timestamps in the (-1000, 0) ms window therefore collapsed onto the Unix epoch (1970-01-01 00:00:00) instead of formatting as the preceding second (1969-12-31 23:59:59).

Swap chrono::DateTime::from_timestamp(timestamp_ms / MS_TO_SECONDS, 0) for chrono::DateTime::from_timestamp_millis(timestamp_ms), which takes millisecond timestamps directly and floors correctly. The MS_TO_SECONDS constant is no longer used.

Test plan

  • cargo test --lib utils::datetime — 7 pass, including new format_datetime_small_negative_is_not_epoch regression test
  • Existing positive-path tests (including sub-second format_datetime_rounds_down_sub_second) still pass — from_timestamp_millis produces the same formatted output for those inputs
  • cargo clippy -- -D warnings clean
  • cargo fmt --check clean

Fixes#209.

🤖 Generated with Claude Code


Open in Devin Review

@devin-ai-integrationdevin-ai-integrationBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 potential issues.

Open in Devin Review

Comment threadsrc/utils/datetime.rs

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚩 Pre-existing pub(super) violations outside the PR scope

The REVIEW.md rule prohibits pub(super), and there are existing usages in src/commands/satisfying_sort/numeric.rs, render.rs, sort_state.rs, and logo_math.rs. These are not touched by this PR and are not related to the change, so they are not flagged as bugs here, but the repository owner may want to clean them up separately.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment threadsrc/utils/datetime.rs
// `from_timestamp_millis` floors toward negative infinity, so timestamps
// in (-1000, 0) correctly land in the second before the epoch instead of
// collapsing to epoch via integer-division truncation.
chrono::DateTime::from_timestamp_millis(timestamp_ms).map_or_else(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Behavioral change: sub-second precision is now preserved for all timestamps

The old code discarded sub-second information for all timestamps by dividing by 1000 and passing 0 as the nanosecond component to from_timestamp. The new from_timestamp_millis preserves millisecond precision internally. Since the format strings used (%Y-%m-%d and %Y-%m-%d %H:%M:%S %Z) only render down to whole seconds, there is no visible output difference for positive timestamps. However, for negative timestamps in the (-1000, 0) range, the old code truncated toward zero (landing on epoch), while the new code correctly floors toward negative infinity (landing in 1969). This is the intended fix, validated by the new format_datetime_small_negative_is_not_epoch test.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@cubic-dev-aicubic-dev-aiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 1 file

…ng to epoch
`format_timestamp` divided `timestamp_ms` by 1000 with integer division,
which truncates toward zero. Timestamps in the (-1000, 0) ms range
collapsed onto the Unix epoch instead of formatting as the preceding
second.
Use `chrono::DateTime::from_timestamp_millis`, which accepts millisecond
timestamps directly and floors correctly. The now-unused `MS_TO_SECONDS`
constant is removed. The existing `expected_local` test helper is
updated to match so the positive-path tests still hold (same output for
sub-second positive timestamps).
Fixes#209.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@sachiniyer
sachiniyerforce-pushed the siyer/fix-datetime-negative-timestamp branch from 868c954 to 52db5b1CompareApril 22, 2026 23:04

@devin-ai-integrationdevin-ai-integrationBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

Open in Devin Review

Comment threadsrc/utils/datetime.rs
Comment on lines 28 to 32
fn expected_local(timestamp_ms: i64, fmt: &str) -> String {
chrono::DateTime::from_timestamp(timestamp_ms / MS_TO_SECONDS, 0)
chrono::DateTime::from_timestamp_millis(timestamp_ms)
.expect("valid timestamp")
.with_timezone(&Local)
.format(fmt)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Test helper is tautological with the implementation under test

The expected_local helper at src/utils/datetime.rs:28-34 now uses the exact same from_timestamp_millis call as the production format_timestamp function. This means tests like format_date_known_timestamp are effectively asserting that a function equals itself, providing no independent verification of correctness. This is a pre-existing pattern (the old code also mirrored the production logic), but the migration carried it forward. A stronger approach would use hardcoded expected strings for known timestamps in a fixed timezone, or at least use an independent computation path.

(Refers to lines 28-34)

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@sachiniyer
sachiniyer merged commit 048aa32 into mainApr 22, 2026
12 checks passed
@sachiniyer
sachiniyer deleted the siyer/fix-datetime-negative-timestamp branch April 22, 2026 23:08
@sachiniyersachiniyer mentioned this pull request Apr 22, 2026
2 tasks
sachiniyer added a commit that referenced this pull request Apr 23, 2026
## Summary
Patch release rolling up the seven fixes merged since 0.2.1:
- fix(bugs): print empty-results hint when `--vulns` alone yields no
matches (#264)
- fix(datetime): floor sub-second negative timestamps instead of
snapping to epoch (#262)
- chore(deps): bump rustls-webpki to 0.103.13 for RUSTSEC-2026-0104
(#263)
- fix(repos): normalize whitespace in repo identifiers before lookup
(#261)
- fix(git): parse GitHub remotes with embedded http(s) credentials
(#260)
- fix(auth): redirect browser and surface OAuth errors on PKCE callback
failure (#258)
- refactor(config): rewrite `update_config` through the locked handle
(#257)
On merge, the release workflow will tag `v0.2.2` and publish platform
artifacts via cargo-dist.
## Test plan
- [x] `cargo build` succeeds with version 0.2.2
- [ ] Tag `v0.2.2` is created on merge and release workflow publishes
artifacts
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- devin-review-badge-begin -->
---
<a href="https://app.devin.ai/review/usedetail/cli/pull/265"
target="_blank">
<picture>
<source media="(prefers-color-scheme: dark)"
srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1">
<img
src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1"
alt="Open in Devin Review">
</picture>
</a>
<!-- devin-review-badge-end -->
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Detail Bug] Datetime formatting treats small negative timestamps as the Unix epoch

1 participant

@sachiniyer
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(datetime): floor sub-second negative timestamps instead of snapping to epoch - #262

Merged
sachiniyer merged 1 commit into
mainfrom
siyer/fix-datetime-negative-timestamp
Apr 22, 2026
Merged

fix(datetime): floor sub-second negative timestamps instead of snapping to epoch#262
sachiniyer merged 1 commit into
mainfrom
siyer/fix-datetime-negative-timestamp

Conversation

@sachiniyer

@sachiniyersachiniyer commented Apr 22, 2026

Copy link
Copy Markdown
Contributor

Summary

format_timestamp converted timestamp_ms → seconds by integer division, which truncates toward zero. Timestamps in the (-1000, 0) ms window therefore collapsed onto the Unix epoch (1970-01-01 00:00:00) instead of formatting as the preceding second (1969-12-31 23:59:59).

Swap chrono::DateTime::from_timestamp(timestamp_ms / MS_TO_SECONDS, 0) for chrono::DateTime::from_timestamp_millis(timestamp_ms), which takes millisecond timestamps directly and floors correctly. The MS_TO_SECONDS constant is no longer used.

Test plan

  • cargo test --lib utils::datetime — 7 pass, including new format_datetime_small_negative_is_not_epoch regression test
  • Existing positive-path tests (including sub-second format_datetime_rounds_down_sub_second) still pass — from_timestamp_millis produces the same formatted output for those inputs
  • cargo clippy -- -D warnings clean
  • cargo fmt --check clean

Fixes#209.

🤖 Generated with Claude Code


Open in Devin Review

@devin-ai-integrationdevin-ai-integrationBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 potential issues.

Open in Devin Review

Comment threadsrc/utils/datetime.rs

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚩 Pre-existing pub(super) violations outside the PR scope

The REVIEW.md rule prohibits pub(super), and there are existing usages in src/commands/satisfying_sort/numeric.rs, render.rs, sort_state.rs, and logo_math.rs. These are not touched by this PR and are not related to the change, so they are not flagged as bugs here, but the repository owner may want to clean them up separately.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment threadsrc/utils/datetime.rs
// `from_timestamp_millis` floors toward negative infinity, so timestamps
// in (-1000, 0) correctly land in the second before the epoch instead of
// collapsing to epoch via integer-division truncation.
chrono::DateTime::from_timestamp_millis(timestamp_ms).map_or_else(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Behavioral change: sub-second precision is now preserved for all timestamps

The old code discarded sub-second information for all timestamps by dividing by 1000 and passing 0 as the nanosecond component to from_timestamp. The new from_timestamp_millis preserves millisecond precision internally. Since the format strings used (%Y-%m-%d and %Y-%m-%d %H:%M:%S %Z) only render down to whole seconds, there is no visible output difference for positive timestamps. However, for negative timestamps in the (-1000, 0) range, the old code truncated toward zero (landing on epoch), while the new code correctly floors toward negative infinity (landing in 1969). This is the intended fix, validated by the new format_datetime_small_negative_is_not_epoch test.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@cubic-dev-aicubic-dev-aiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 1 file

…ng to epoch
`format_timestamp` divided `timestamp_ms` by 1000 with integer division,
which truncates toward zero. Timestamps in the (-1000, 0) ms range
collapsed onto the Unix epoch instead of formatting as the preceding
second.
Use `chrono::DateTime::from_timestamp_millis`, which accepts millisecond
timestamps directly and floors correctly. The now-unused `MS_TO_SECONDS`
constant is removed. The existing `expected_local` test helper is
updated to match so the positive-path tests still hold (same output for
sub-second positive timestamps).
Fixes#209.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@sachiniyer
sachiniyerforce-pushed the siyer/fix-datetime-negative-timestamp branch from 868c954 to 52db5b1CompareApril 22, 2026 23:04

@devin-ai-integrationdevin-ai-integrationBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

Open in Devin Review

Comment threadsrc/utils/datetime.rs
Comment on lines 28 to 32
fn expected_local(timestamp_ms: i64, fmt: &str) -> String {
chrono::DateTime::from_timestamp(timestamp_ms / MS_TO_SECONDS, 0)
chrono::DateTime::from_timestamp_millis(timestamp_ms)
.expect("valid timestamp")
.with_timezone(&Local)
.format(fmt)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Test helper is tautological with the implementation under test

The expected_local helper at src/utils/datetime.rs:28-34 now uses the exact same from_timestamp_millis call as the production format_timestamp function. This means tests like format_date_known_timestamp are effectively asserting that a function equals itself, providing no independent verification of correctness. This is a pre-existing pattern (the old code also mirrored the production logic), but the migration carried it forward. A stronger approach would use hardcoded expected strings for known timestamps in a fixed timezone, or at least use an independent computation path.

(Refers to lines 28-34)

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@sachiniyer
sachiniyer merged commit 048aa32 into mainApr 22, 2026
12 checks passed
@sachiniyer
sachiniyer deleted the siyer/fix-datetime-negative-timestamp branch April 22, 2026 23:08
@sachiniyersachiniyer mentioned this pull request Apr 22, 2026
2 tasks
sachiniyer added a commit that referenced this pull request Apr 23, 2026
## Summary
Patch release rolling up the seven fixes merged since 0.2.1:
- fix(bugs): print empty-results hint when `--vulns` alone yields no
matches (#264)
- fix(datetime): floor sub-second negative timestamps instead of
snapping to epoch (#262)
- chore(deps): bump rustls-webpki to 0.103.13 for RUSTSEC-2026-0104
(#263)
- fix(repos): normalize whitespace in repo identifiers before lookup
(#261)
- fix(git): parse GitHub remotes with embedded http(s) credentials
(#260)
- fix(auth): redirect browser and surface OAuth errors on PKCE callback
failure (#258)
- refactor(config): rewrite `update_config` through the locked handle
(#257)
On merge, the release workflow will tag `v0.2.2` and publish platform
artifacts via cargo-dist.
## Test plan
- [x] `cargo build` succeeds with version 0.2.2
- [ ] Tag `v0.2.2` is created on merge and release workflow publishes
artifacts
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- devin-review-badge-begin -->
---
<a href="https://app.devin.ai/review/usedetail/cli/pull/265"
target="_blank">
<picture>
<source media="(prefers-color-scheme: dark)"
srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1">
<img
src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1"
alt="Open in Devin Review">
</picture>
</a>
<!-- devin-review-badge-end -->
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Detail Bug] Datetime formatting treats small negative timestamps as the Unix epoch

1 participant

@sachiniyer
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(datetime): floor sub-second negative timestamps instead of snapping to epoch - #262

Merged
sachiniyer merged 1 commit into
mainfrom
siyer/fix-datetime-negative-timestamp
Apr 22, 2026
Merged

fix(datetime): floor sub-second negative timestamps instead of snapping to epoch#262
sachiniyer merged 1 commit into
mainfrom
siyer/fix-datetime-negative-timestamp

Conversation

@sachiniyer

@sachiniyersachiniyer commented Apr 22, 2026

Copy link
Copy Markdown
Contributor

Summary

format_timestamp converted timestamp_ms → seconds by integer division, which truncates toward zero. Timestamps in the (-1000, 0) ms window therefore collapsed onto the Unix epoch (1970-01-01 00:00:00) instead of formatting as the preceding second (1969-12-31 23:59:59).

Swap chrono::DateTime::from_timestamp(timestamp_ms / MS_TO_SECONDS, 0) for chrono::DateTime::from_timestamp_millis(timestamp_ms), which takes millisecond timestamps directly and floors correctly. The MS_TO_SECONDS constant is no longer used.

Test plan

  • cargo test --lib utils::datetime — 7 pass, including new format_datetime_small_negative_is_not_epoch regression test
  • Existing positive-path tests (including sub-second format_datetime_rounds_down_sub_second) still pass — from_timestamp_millis produces the same formatted output for those inputs
  • cargo clippy -- -D warnings clean
  • cargo fmt --check clean

Fixes#209.

🤖 Generated with Claude Code


Open in Devin Review

@devin-ai-integrationdevin-ai-integrationBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 potential issues.

Open in Devin Review

Comment threadsrc/utils/datetime.rs

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚩 Pre-existing pub(super) violations outside the PR scope

The REVIEW.md rule prohibits pub(super), and there are existing usages in src/commands/satisfying_sort/numeric.rs, render.rs, sort_state.rs, and logo_math.rs. These are not touched by this PR and are not related to the change, so they are not flagged as bugs here, but the repository owner may want to clean them up separately.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment threadsrc/utils/datetime.rs
// `from_timestamp_millis` floors toward negative infinity, so timestamps
// in (-1000, 0) correctly land in the second before the epoch instead of
// collapsing to epoch via integer-division truncation.
chrono::DateTime::from_timestamp_millis(timestamp_ms).map_or_else(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Behavioral change: sub-second precision is now preserved for all timestamps

The old code discarded sub-second information for all timestamps by dividing by 1000 and passing 0 as the nanosecond component to from_timestamp. The new from_timestamp_millis preserves millisecond precision internally. Since the format strings used (%Y-%m-%d and %Y-%m-%d %H:%M:%S %Z) only render down to whole seconds, there is no visible output difference for positive timestamps. However, for negative timestamps in the (-1000, 0) range, the old code truncated toward zero (landing on epoch), while the new code correctly floors toward negative infinity (landing in 1969). This is the intended fix, validated by the new format_datetime_small_negative_is_not_epoch test.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@cubic-dev-aicubic-dev-aiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 1 file

…ng to epoch
`format_timestamp` divided `timestamp_ms` by 1000 with integer division,
which truncates toward zero. Timestamps in the (-1000, 0) ms range
collapsed onto the Unix epoch instead of formatting as the preceding
second.
Use `chrono::DateTime::from_timestamp_millis`, which accepts millisecond
timestamps directly and floors correctly. The now-unused `MS_TO_SECONDS`
constant is removed. The existing `expected_local` test helper is
updated to match so the positive-path tests still hold (same output for
sub-second positive timestamps).
Fixes#209.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@sachiniyer
sachiniyerforce-pushed the siyer/fix-datetime-negative-timestamp branch from 868c954 to 52db5b1CompareApril 22, 2026 23:04

@devin-ai-integrationdevin-ai-integrationBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

Open in Devin Review

Comment threadsrc/utils/datetime.rs
Comment on lines 28 to 32
fn expected_local(timestamp_ms: i64, fmt: &str) -> String {
chrono::DateTime::from_timestamp(timestamp_ms / MS_TO_SECONDS, 0)
chrono::DateTime::from_timestamp_millis(timestamp_ms)
.expect("valid timestamp")
.with_timezone(&Local)
.format(fmt)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Test helper is tautological with the implementation under test

The expected_local helper at src/utils/datetime.rs:28-34 now uses the exact same from_timestamp_millis call as the production format_timestamp function. This means tests like format_date_known_timestamp are effectively asserting that a function equals itself, providing no independent verification of correctness. This is a pre-existing pattern (the old code also mirrored the production logic), but the migration carried it forward. A stronger approach would use hardcoded expected strings for known timestamps in a fixed timezone, or at least use an independent computation path.

(Refers to lines 28-34)

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@sachiniyer
sachiniyer merged commit 048aa32 into mainApr 22, 2026
12 checks passed
@sachiniyer
sachiniyer deleted the siyer/fix-datetime-negative-timestamp branch April 22, 2026 23:08
@sachiniyersachiniyer mentioned this pull request Apr 22, 2026
2 tasks
sachiniyer added a commit that referenced this pull request Apr 23, 2026
## Summary
Patch release rolling up the seven fixes merged since 0.2.1:
- fix(bugs): print empty-results hint when `--vulns` alone yields no
matches (#264)
- fix(datetime): floor sub-second negative timestamps instead of
snapping to epoch (#262)
- chore(deps): bump rustls-webpki to 0.103.13 for RUSTSEC-2026-0104
(#263)
- fix(repos): normalize whitespace in repo identifiers before lookup
(#261)
- fix(git): parse GitHub remotes with embedded http(s) credentials
(#260)
- fix(auth): redirect browser and surface OAuth errors on PKCE callback
failure (#258)
- refactor(config): rewrite `update_config` through the locked handle
(#257)
On merge, the release workflow will tag `v0.2.2` and publish platform
artifacts via cargo-dist.
## Test plan
- [x] `cargo build` succeeds with version 0.2.2
- [ ] Tag `v0.2.2` is created on merge and release workflow publishes
artifacts
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- devin-review-badge-begin -->
---
<a href="https://app.devin.ai/review/usedetail/cli/pull/265"
target="_blank">
<picture>
<source media="(prefers-color-scheme: dark)"
srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1">
<img
src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1"
alt="Open in Devin Review">
</picture>
</a>
<!-- devin-review-badge-end -->
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Detail Bug] Datetime formatting treats small negative timestamps as the Unix epoch

1 participant

@sachiniyer
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(datetime): floor sub-second negative timestamps instead of snapping to epoch - #262

Merged
sachiniyer merged 1 commit into
mainfrom
siyer/fix-datetime-negative-timestamp
Apr 22, 2026
Merged

fix(datetime): floor sub-second negative timestamps instead of snapping to epoch#262
sachiniyer merged 1 commit into
mainfrom
siyer/fix-datetime-negative-timestamp

Conversation

@sachiniyer

@sachiniyersachiniyer commented Apr 22, 2026

Copy link
Copy Markdown
Contributor

Summary

format_timestamp converted timestamp_ms → seconds by integer division, which truncates toward zero. Timestamps in the (-1000, 0) ms window therefore collapsed onto the Unix epoch (1970-01-01 00:00:00) instead of formatting as the preceding second (1969-12-31 23:59:59).

Swap chrono::DateTime::from_timestamp(timestamp_ms / MS_TO_SECONDS, 0) for chrono::DateTime::from_timestamp_millis(timestamp_ms), which takes millisecond timestamps directly and floors correctly. The MS_TO_SECONDS constant is no longer used.

Test plan

  • cargo test --lib utils::datetime — 7 pass, including new format_datetime_small_negative_is_not_epoch regression test
  • Existing positive-path tests (including sub-second format_datetime_rounds_down_sub_second) still pass — from_timestamp_millis produces the same formatted output for those inputs
  • cargo clippy -- -D warnings clean
  • cargo fmt --check clean

Fixes#209.

🤖 Generated with Claude Code


Open in Devin Review

@devin-ai-integrationdevin-ai-integrationBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 potential issues.

Open in Devin Review

Comment threadsrc/utils/datetime.rs

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚩 Pre-existing pub(super) violations outside the PR scope

The REVIEW.md rule prohibits pub(super), and there are existing usages in src/commands/satisfying_sort/numeric.rs, render.rs, sort_state.rs, and logo_math.rs. These are not touched by this PR and are not related to the change, so they are not flagged as bugs here, but the repository owner may want to clean them up separately.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment threadsrc/utils/datetime.rs
// `from_timestamp_millis` floors toward negative infinity, so timestamps
// in (-1000, 0) correctly land in the second before the epoch instead of
// collapsing to epoch via integer-division truncation.
chrono::DateTime::from_timestamp_millis(timestamp_ms).map_or_else(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Behavioral change: sub-second precision is now preserved for all timestamps

The old code discarded sub-second information for all timestamps by dividing by 1000 and passing 0 as the nanosecond component to from_timestamp. The new from_timestamp_millis preserves millisecond precision internally. Since the format strings used (%Y-%m-%d and %Y-%m-%d %H:%M:%S %Z) only render down to whole seconds, there is no visible output difference for positive timestamps. However, for negative timestamps in the (-1000, 0) range, the old code truncated toward zero (landing on epoch), while the new code correctly floors toward negative infinity (landing in 1969). This is the intended fix, validated by the new format_datetime_small_negative_is_not_epoch test.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@cubic-dev-aicubic-dev-aiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 1 file

…ng to epoch
`format_timestamp` divided `timestamp_ms` by 1000 with integer division,
which truncates toward zero. Timestamps in the (-1000, 0) ms range
collapsed onto the Unix epoch instead of formatting as the preceding
second.
Use `chrono::DateTime::from_timestamp_millis`, which accepts millisecond
timestamps directly and floors correctly. The now-unused `MS_TO_SECONDS`
constant is removed. The existing `expected_local` test helper is
updated to match so the positive-path tests still hold (same output for
sub-second positive timestamps).
Fixes#209.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@sachiniyer
sachiniyerforce-pushed the siyer/fix-datetime-negative-timestamp branch from 868c954 to 52db5b1CompareApril 22, 2026 23:04

@devin-ai-integrationdevin-ai-integrationBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

Open in Devin Review

Comment threadsrc/utils/datetime.rs
Comment on lines 28 to 32
fn expected_local(timestamp_ms: i64, fmt: &str) -> String {
chrono::DateTime::from_timestamp(timestamp_ms / MS_TO_SECONDS, 0)
chrono::DateTime::from_timestamp_millis(timestamp_ms)
.expect("valid timestamp")
.with_timezone(&Local)
.format(fmt)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Test helper is tautological with the implementation under test

The expected_local helper at src/utils/datetime.rs:28-34 now uses the exact same from_timestamp_millis call as the production format_timestamp function. This means tests like format_date_known_timestamp are effectively asserting that a function equals itself, providing no independent verification of correctness. This is a pre-existing pattern (the old code also mirrored the production logic), but the migration carried it forward. A stronger approach would use hardcoded expected strings for known timestamps in a fixed timezone, or at least use an independent computation path.

(Refers to lines 28-34)

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@sachiniyer
sachiniyer merged commit 048aa32 into mainApr 22, 2026
12 checks passed
@sachiniyer
sachiniyer deleted the siyer/fix-datetime-negative-timestamp branch April 22, 2026 23:08
@sachiniyersachiniyer mentioned this pull request Apr 22, 2026
2 tasks
sachiniyer added a commit that referenced this pull request Apr 23, 2026
## Summary
Patch release rolling up the seven fixes merged since 0.2.1:
- fix(bugs): print empty-results hint when `--vulns` alone yields no
matches (#264)
- fix(datetime): floor sub-second negative timestamps instead of
snapping to epoch (#262)
- chore(deps): bump rustls-webpki to 0.103.13 for RUSTSEC-2026-0104
(#263)
- fix(repos): normalize whitespace in repo identifiers before lookup
(#261)
- fix(git): parse GitHub remotes with embedded http(s) credentials
(#260)
- fix(auth): redirect browser and surface OAuth errors on PKCE callback
failure (#258)
- refactor(config): rewrite `update_config` through the locked handle
(#257)
On merge, the release workflow will tag `v0.2.2` and publish platform
artifacts via cargo-dist.
## Test plan
- [x] `cargo build` succeeds with version 0.2.2
- [ ] Tag `v0.2.2` is created on merge and release workflow publishes
artifacts
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- devin-review-badge-begin -->
---
<a href="https://app.devin.ai/review/usedetail/cli/pull/265"
target="_blank">
<picture>
<source media="(prefers-color-scheme: dark)"
srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1">
<img
src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1"
alt="Open in Devin Review">
</picture>
</a>
<!-- devin-review-badge-end -->
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Detail Bug] Datetime formatting treats small negative timestamps as the Unix epoch

1 participant

@sachiniyer
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(datetime): floor sub-second negative timestamps instead of snapping to epoch - #262

Merged
sachiniyer merged 1 commit into
mainfrom
siyer/fix-datetime-negative-timestamp
Apr 22, 2026
Merged

fix(datetime): floor sub-second negative timestamps instead of snapping to epoch#262
sachiniyer merged 1 commit into
mainfrom
siyer/fix-datetime-negative-timestamp

Conversation

@sachiniyer

@sachiniyersachiniyer commented Apr 22, 2026

Copy link
Copy Markdown
Contributor

Summary

format_timestamp converted timestamp_ms → seconds by integer division, which truncates toward zero. Timestamps in the (-1000, 0) ms window therefore collapsed onto the Unix epoch (1970-01-01 00:00:00) instead of formatting as the preceding second (1969-12-31 23:59:59).

Swap chrono::DateTime::from_timestamp(timestamp_ms / MS_TO_SECONDS, 0) for chrono::DateTime::from_timestamp_millis(timestamp_ms), which takes millisecond timestamps directly and floors correctly. The MS_TO_SECONDS constant is no longer used.

Test plan

  • cargo test --lib utils::datetime — 7 pass, including new format_datetime_small_negative_is_not_epoch regression test
  • Existing positive-path tests (including sub-second format_datetime_rounds_down_sub_second) still pass — from_timestamp_millis produces the same formatted output for those inputs
  • cargo clippy -- -D warnings clean
  • cargo fmt --check clean

Fixes#209.

🤖 Generated with Claude Code


Open in Devin Review

@devin-ai-integrationdevin-ai-integrationBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 potential issues.

Open in Devin Review

Comment threadsrc/utils/datetime.rs

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚩 Pre-existing pub(super) violations outside the PR scope

The REVIEW.md rule prohibits pub(super), and there are existing usages in src/commands/satisfying_sort/numeric.rs, render.rs, sort_state.rs, and logo_math.rs. These are not touched by this PR and are not related to the change, so they are not flagged as bugs here, but the repository owner may want to clean them up separately.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment threadsrc/utils/datetime.rs
// `from_timestamp_millis` floors toward negative infinity, so timestamps
// in (-1000, 0) correctly land in the second before the epoch instead of
// collapsing to epoch via integer-division truncation.
chrono::DateTime::from_timestamp_millis(timestamp_ms).map_or_else(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Behavioral change: sub-second precision is now preserved for all timestamps

The old code discarded sub-second information for all timestamps by dividing by 1000 and passing 0 as the nanosecond component to from_timestamp. The new from_timestamp_millis preserves millisecond precision internally. Since the format strings used (%Y-%m-%d and %Y-%m-%d %H:%M:%S %Z) only render down to whole seconds, there is no visible output difference for positive timestamps. However, for negative timestamps in the (-1000, 0) range, the old code truncated toward zero (landing on epoch), while the new code correctly floors toward negative infinity (landing in 1969). This is the intended fix, validated by the new format_datetime_small_negative_is_not_epoch test.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@cubic-dev-aicubic-dev-aiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 1 file

…ng to epoch
`format_timestamp` divided `timestamp_ms` by 1000 with integer division,
which truncates toward zero. Timestamps in the (-1000, 0) ms range
collapsed onto the Unix epoch instead of formatting as the preceding
second.
Use `chrono::DateTime::from_timestamp_millis`, which accepts millisecond
timestamps directly and floors correctly. The now-unused `MS_TO_SECONDS`
constant is removed. The existing `expected_local` test helper is
updated to match so the positive-path tests still hold (same output for
sub-second positive timestamps).
Fixes#209.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@sachiniyer
sachiniyerforce-pushed the siyer/fix-datetime-negative-timestamp branch from 868c954 to 52db5b1CompareApril 22, 2026 23:04

@devin-ai-integrationdevin-ai-integrationBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

Open in Devin Review

Comment threadsrc/utils/datetime.rs
Comment on lines 28 to 32
fn expected_local(timestamp_ms: i64, fmt: &str) -> String {
chrono::DateTime::from_timestamp(timestamp_ms / MS_TO_SECONDS, 0)
chrono::DateTime::from_timestamp_millis(timestamp_ms)
.expect("valid timestamp")
.with_timezone(&Local)
.format(fmt)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Test helper is tautological with the implementation under test

The expected_local helper at src/utils/datetime.rs:28-34 now uses the exact same from_timestamp_millis call as the production format_timestamp function. This means tests like format_date_known_timestamp are effectively asserting that a function equals itself, providing no independent verification of correctness. This is a pre-existing pattern (the old code also mirrored the production logic), but the migration carried it forward. A stronger approach would use hardcoded expected strings for known timestamps in a fixed timezone, or at least use an independent computation path.

(Refers to lines 28-34)

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@sachiniyer
sachiniyer merged commit 048aa32 into mainApr 22, 2026
12 checks passed
@sachiniyer
sachiniyer deleted the siyer/fix-datetime-negative-timestamp branch April 22, 2026 23:08
@sachiniyersachiniyer mentioned this pull request Apr 22, 2026
2 tasks
sachiniyer added a commit that referenced this pull request Apr 23, 2026
## Summary
Patch release rolling up the seven fixes merged since 0.2.1:
- fix(bugs): print empty-results hint when `--vulns` alone yields no
matches (#264)
- fix(datetime): floor sub-second negative timestamps instead of
snapping to epoch (#262)
- chore(deps): bump rustls-webpki to 0.103.13 for RUSTSEC-2026-0104
(#263)
- fix(repos): normalize whitespace in repo identifiers before lookup
(#261)
- fix(git): parse GitHub remotes with embedded http(s) credentials
(#260)
- fix(auth): redirect browser and surface OAuth errors on PKCE callback
failure (#258)
- refactor(config): rewrite `update_config` through the locked handle
(#257)
On merge, the release workflow will tag `v0.2.2` and publish platform
artifacts via cargo-dist.
## Test plan
- [x] `cargo build` succeeds with version 0.2.2
- [ ] Tag `v0.2.2` is created on merge and release workflow publishes
artifacts
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- devin-review-badge-begin -->
---
<a href="https://app.devin.ai/review/usedetail/cli/pull/265"
target="_blank">
<picture>
<source media="(prefers-color-scheme: dark)"
srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1">
<img
src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1"
alt="Open in Devin Review">
</picture>
</a>
<!-- devin-review-badge-end -->
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Detail Bug] Datetime formatting treats small negative timestamps as the Unix epoch

1 participant

@sachiniyer
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(datetime): floor sub-second negative timestamps instead of snapping to epoch - #262

Merged
sachiniyer merged 1 commit into
mainfrom
siyer/fix-datetime-negative-timestamp
Apr 22, 2026
Merged

fix(datetime): floor sub-second negative timestamps instead of snapping to epoch#262
sachiniyer merged 1 commit into
mainfrom
siyer/fix-datetime-negative-timestamp

Conversation

@sachiniyer

@sachiniyersachiniyer commented Apr 22, 2026

Copy link
Copy Markdown
Contributor

Summary

format_timestamp converted timestamp_ms → seconds by integer division, which truncates toward zero. Timestamps in the (-1000, 0) ms window therefore collapsed onto the Unix epoch (1970-01-01 00:00:00) instead of formatting as the preceding second (1969-12-31 23:59:59).

Swap chrono::DateTime::from_timestamp(timestamp_ms / MS_TO_SECONDS, 0) for chrono::DateTime::from_timestamp_millis(timestamp_ms), which takes millisecond timestamps directly and floors correctly. The MS_TO_SECONDS constant is no longer used.

Test plan

  • cargo test --lib utils::datetime — 7 pass, including new format_datetime_small_negative_is_not_epoch regression test
  • Existing positive-path tests (including sub-second format_datetime_rounds_down_sub_second) still pass — from_timestamp_millis produces the same formatted output for those inputs
  • cargo clippy -- -D warnings clean
  • cargo fmt --check clean

Fixes#209.

🤖 Generated with Claude Code


Open in Devin Review

@devin-ai-integrationdevin-ai-integrationBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 potential issues.

Open in Devin Review

Comment threadsrc/utils/datetime.rs

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚩 Pre-existing pub(super) violations outside the PR scope

The REVIEW.md rule prohibits pub(super), and there are existing usages in src/commands/satisfying_sort/numeric.rs, render.rs, sort_state.rs, and logo_math.rs. These are not touched by this PR and are not related to the change, so they are not flagged as bugs here, but the repository owner may want to clean them up separately.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment threadsrc/utils/datetime.rs
// `from_timestamp_millis` floors toward negative infinity, so timestamps
// in (-1000, 0) correctly land in the second before the epoch instead of
// collapsing to epoch via integer-division truncation.
chrono::DateTime::from_timestamp_millis(timestamp_ms).map_or_else(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Behavioral change: sub-second precision is now preserved for all timestamps

The old code discarded sub-second information for all timestamps by dividing by 1000 and passing 0 as the nanosecond component to from_timestamp. The new from_timestamp_millis preserves millisecond precision internally. Since the format strings used (%Y-%m-%d and %Y-%m-%d %H:%M:%S %Z) only render down to whole seconds, there is no visible output difference for positive timestamps. However, for negative timestamps in the (-1000, 0) range, the old code truncated toward zero (landing on epoch), while the new code correctly floors toward negative infinity (landing in 1969). This is the intended fix, validated by the new format_datetime_small_negative_is_not_epoch test.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@cubic-dev-aicubic-dev-aiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 1 file

…ng to epoch
`format_timestamp` divided `timestamp_ms` by 1000 with integer division,
which truncates toward zero. Timestamps in the (-1000, 0) ms range
collapsed onto the Unix epoch instead of formatting as the preceding
second.
Use `chrono::DateTime::from_timestamp_millis`, which accepts millisecond
timestamps directly and floors correctly. The now-unused `MS_TO_SECONDS`
constant is removed. The existing `expected_local` test helper is
updated to match so the positive-path tests still hold (same output for
sub-second positive timestamps).
Fixes#209.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@sachiniyer
sachiniyerforce-pushed the siyer/fix-datetime-negative-timestamp branch from 868c954 to 52db5b1CompareApril 22, 2026 23:04

@devin-ai-integrationdevin-ai-integrationBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

Open in Devin Review

Comment threadsrc/utils/datetime.rs
Comment on lines 28 to 32
fn expected_local(timestamp_ms: i64, fmt: &str) -> String {
chrono::DateTime::from_timestamp(timestamp_ms / MS_TO_SECONDS, 0)
chrono::DateTime::from_timestamp_millis(timestamp_ms)
.expect("valid timestamp")
.with_timezone(&Local)
.format(fmt)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Test helper is tautological with the implementation under test

The expected_local helper at src/utils/datetime.rs:28-34 now uses the exact same from_timestamp_millis call as the production format_timestamp function. This means tests like format_date_known_timestamp are effectively asserting that a function equals itself, providing no independent verification of correctness. This is a pre-existing pattern (the old code also mirrored the production logic), but the migration carried it forward. A stronger approach would use hardcoded expected strings for known timestamps in a fixed timezone, or at least use an independent computation path.

(Refers to lines 28-34)

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@sachiniyer
sachiniyer merged commit 048aa32 into mainApr 22, 2026
12 checks passed
@sachiniyer
sachiniyer deleted the siyer/fix-datetime-negative-timestamp branch April 22, 2026 23:08
@sachiniyersachiniyer mentioned this pull request Apr 22, 2026
2 tasks
sachiniyer added a commit that referenced this pull request Apr 23, 2026
## Summary
Patch release rolling up the seven fixes merged since 0.2.1:
- fix(bugs): print empty-results hint when `--vulns` alone yields no
matches (#264)
- fix(datetime): floor sub-second negative timestamps instead of
snapping to epoch (#262)
- chore(deps): bump rustls-webpki to 0.103.13 for RUSTSEC-2026-0104
(#263)
- fix(repos): normalize whitespace in repo identifiers before lookup
(#261)
- fix(git): parse GitHub remotes with embedded http(s) credentials
(#260)
- fix(auth): redirect browser and surface OAuth errors on PKCE callback
failure (#258)
- refactor(config): rewrite `update_config` through the locked handle
(#257)
On merge, the release workflow will tag `v0.2.2` and publish platform
artifacts via cargo-dist.
## Test plan
- [x] `cargo build` succeeds with version 0.2.2
- [ ] Tag `v0.2.2` is created on merge and release workflow publishes
artifacts
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- devin-review-badge-begin -->
---
<a href="https://app.devin.ai/review/usedetail/cli/pull/265"
target="_blank">
<picture>
<source media="(prefers-color-scheme: dark)"
srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1">
<img
src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1"
alt="Open in Devin Review">
</picture>
</a>
<!-- devin-review-badge-end -->
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Detail Bug] Datetime formatting treats small negative timestamps as the Unix epoch

1 participant

@sachiniyer
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(datetime): floor sub-second negative timestamps instead of snapping to epoch - #262

Merged
sachiniyer merged 1 commit into
mainfrom
siyer/fix-datetime-negative-timestamp
Apr 22, 2026
Merged

fix(datetime): floor sub-second negative timestamps instead of snapping to epoch#262
sachiniyer merged 1 commit into
mainfrom
siyer/fix-datetime-negative-timestamp

Conversation

@sachiniyer

@sachiniyersachiniyer commented Apr 22, 2026

Copy link
Copy Markdown
Contributor

Summary

format_timestamp converted timestamp_ms → seconds by integer division, which truncates toward zero. Timestamps in the (-1000, 0) ms window therefore collapsed onto the Unix epoch (1970-01-01 00:00:00) instead of formatting as the preceding second (1969-12-31 23:59:59).

Swap chrono::DateTime::from_timestamp(timestamp_ms / MS_TO_SECONDS, 0) for chrono::DateTime::from_timestamp_millis(timestamp_ms), which takes millisecond timestamps directly and floors correctly. The MS_TO_SECONDS constant is no longer used.

Test plan

  • cargo test --lib utils::datetime — 7 pass, including new format_datetime_small_negative_is_not_epoch regression test
  • Existing positive-path tests (including sub-second format_datetime_rounds_down_sub_second) still pass — from_timestamp_millis produces the same formatted output for those inputs
  • cargo clippy -- -D warnings clean
  • cargo fmt --check clean

Fixes#209.

🤖 Generated with Claude Code


Open in Devin Review

@devin-ai-integrationdevin-ai-integrationBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 potential issues.

Open in Devin Review

Comment threadsrc/utils/datetime.rs

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚩 Pre-existing pub(super) violations outside the PR scope

The REVIEW.md rule prohibits pub(super), and there are existing usages in src/commands/satisfying_sort/numeric.rs, render.rs, sort_state.rs, and logo_math.rs. These are not touched by this PR and are not related to the change, so they are not flagged as bugs here, but the repository owner may want to clean them up separately.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment threadsrc/utils/datetime.rs
// `from_timestamp_millis` floors toward negative infinity, so timestamps
// in (-1000, 0) correctly land in the second before the epoch instead of
// collapsing to epoch via integer-division truncation.
chrono::DateTime::from_timestamp_millis(timestamp_ms).map_or_else(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Behavioral change: sub-second precision is now preserved for all timestamps

The old code discarded sub-second information for all timestamps by dividing by 1000 and passing 0 as the nanosecond component to from_timestamp. The new from_timestamp_millis preserves millisecond precision internally. Since the format strings used (%Y-%m-%d and %Y-%m-%d %H:%M:%S %Z) only render down to whole seconds, there is no visible output difference for positive timestamps. However, for negative timestamps in the (-1000, 0) range, the old code truncated toward zero (landing on epoch), while the new code correctly floors toward negative infinity (landing in 1969). This is the intended fix, validated by the new format_datetime_small_negative_is_not_epoch test.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@cubic-dev-aicubic-dev-aiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 1 file

…ng to epoch
`format_timestamp` divided `timestamp_ms` by 1000 with integer division,
which truncates toward zero. Timestamps in the (-1000, 0) ms range
collapsed onto the Unix epoch instead of formatting as the preceding
second.
Use `chrono::DateTime::from_timestamp_millis`, which accepts millisecond
timestamps directly and floors correctly. The now-unused `MS_TO_SECONDS`
constant is removed. The existing `expected_local` test helper is
updated to match so the positive-path tests still hold (same output for
sub-second positive timestamps).
Fixes#209.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@sachiniyer
sachiniyerforce-pushed the siyer/fix-datetime-negative-timestamp branch from 868c954 to 52db5b1CompareApril 22, 2026 23:04

@devin-ai-integrationdevin-ai-integrationBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

Open in Devin Review

Comment threadsrc/utils/datetime.rs
Comment on lines 28 to 32
fn expected_local(timestamp_ms: i64, fmt: &str) -> String {
chrono::DateTime::from_timestamp(timestamp_ms / MS_TO_SECONDS, 0)
chrono::DateTime::from_timestamp_millis(timestamp_ms)
.expect("valid timestamp")
.with_timezone(&Local)
.format(fmt)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Test helper is tautological with the implementation under test

The expected_local helper at src/utils/datetime.rs:28-34 now uses the exact same from_timestamp_millis call as the production format_timestamp function. This means tests like format_date_known_timestamp are effectively asserting that a function equals itself, providing no independent verification of correctness. This is a pre-existing pattern (the old code also mirrored the production logic), but the migration carried it forward. A stronger approach would use hardcoded expected strings for known timestamps in a fixed timezone, or at least use an independent computation path.

(Refers to lines 28-34)

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@sachiniyer
sachiniyer merged commit 048aa32 into mainApr 22, 2026
12 checks passed
@sachiniyer
sachiniyer deleted the siyer/fix-datetime-negative-timestamp branch April 22, 2026 23:08
@sachiniyersachiniyer mentioned this pull request Apr 22, 2026
2 tasks
sachiniyer added a commit that referenced this pull request Apr 23, 2026
## Summary
Patch release rolling up the seven fixes merged since 0.2.1:
- fix(bugs): print empty-results hint when `--vulns` alone yields no
matches (#264)
- fix(datetime): floor sub-second negative timestamps instead of
snapping to epoch (#262)
- chore(deps): bump rustls-webpki to 0.103.13 for RUSTSEC-2026-0104
(#263)
- fix(repos): normalize whitespace in repo identifiers before lookup
(#261)
- fix(git): parse GitHub remotes with embedded http(s) credentials
(#260)
- fix(auth): redirect browser and surface OAuth errors on PKCE callback
failure (#258)
- refactor(config): rewrite `update_config` through the locked handle
(#257)
On merge, the release workflow will tag `v0.2.2` and publish platform
artifacts via cargo-dist.
## Test plan
- [x] `cargo build` succeeds with version 0.2.2
- [ ] Tag `v0.2.2` is created on merge and release workflow publishes
artifacts
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- devin-review-badge-begin -->
---
<a href="https://app.devin.ai/review/usedetail/cli/pull/265"
target="_blank">
<picture>
<source media="(prefers-color-scheme: dark)"
srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1">
<img
src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1"
alt="Open in Devin Review">
</picture>
</a>
<!-- devin-review-badge-end -->
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Detail Bug] Datetime formatting treats small negative timestamps as the Unix epoch

1 participant

@sachiniyer
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(datetime): floor sub-second negative timestamps instead of snapping to epoch - #262

Merged
sachiniyer merged 1 commit into
mainfrom
siyer/fix-datetime-negative-timestamp
Apr 22, 2026
Merged

fix(datetime): floor sub-second negative timestamps instead of snapping to epoch#262
sachiniyer merged 1 commit into
mainfrom
siyer/fix-datetime-negative-timestamp

Conversation

@sachiniyer

@sachiniyersachiniyer commented Apr 22, 2026

Copy link
Copy Markdown
Contributor

Summary

format_timestamp converted timestamp_ms → seconds by integer division, which truncates toward zero. Timestamps in the (-1000, 0) ms window therefore collapsed onto the Unix epoch (1970-01-01 00:00:00) instead of formatting as the preceding second (1969-12-31 23:59:59).

Swap chrono::DateTime::from_timestamp(timestamp_ms / MS_TO_SECONDS, 0) for chrono::DateTime::from_timestamp_millis(timestamp_ms), which takes millisecond timestamps directly and floors correctly. The MS_TO_SECONDS constant is no longer used.

Test plan

  • cargo test --lib utils::datetime — 7 pass, including new format_datetime_small_negative_is_not_epoch regression test
  • Existing positive-path tests (including sub-second format_datetime_rounds_down_sub_second) still pass — from_timestamp_millis produces the same formatted output for those inputs
  • cargo clippy -- -D warnings clean
  • cargo fmt --check clean

Fixes#209.

🤖 Generated with Claude Code


Open in Devin Review

@devin-ai-integrationdevin-ai-integrationBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 potential issues.

Open in Devin Review

Comment threadsrc/utils/datetime.rs

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚩 Pre-existing pub(super) violations outside the PR scope

The REVIEW.md rule prohibits pub(super), and there are existing usages in src/commands/satisfying_sort/numeric.rs, render.rs, sort_state.rs, and logo_math.rs. These are not touched by this PR and are not related to the change, so they are not flagged as bugs here, but the repository owner may want to clean them up separately.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment threadsrc/utils/datetime.rs
// `from_timestamp_millis` floors toward negative infinity, so timestamps
// in (-1000, 0) correctly land in the second before the epoch instead of
// collapsing to epoch via integer-division truncation.
chrono::DateTime::from_timestamp_millis(timestamp_ms).map_or_else(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Behavioral change: sub-second precision is now preserved for all timestamps

The old code discarded sub-second information for all timestamps by dividing by 1000 and passing 0 as the nanosecond component to from_timestamp. The new from_timestamp_millis preserves millisecond precision internally. Since the format strings used (%Y-%m-%d and %Y-%m-%d %H:%M:%S %Z) only render down to whole seconds, there is no visible output difference for positive timestamps. However, for negative timestamps in the (-1000, 0) range, the old code truncated toward zero (landing on epoch), while the new code correctly floors toward negative infinity (landing in 1969). This is the intended fix, validated by the new format_datetime_small_negative_is_not_epoch test.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@cubic-dev-aicubic-dev-aiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 1 file

…ng to epoch
`format_timestamp` divided `timestamp_ms` by 1000 with integer division,
which truncates toward zero. Timestamps in the (-1000, 0) ms range
collapsed onto the Unix epoch instead of formatting as the preceding
second.
Use `chrono::DateTime::from_timestamp_millis`, which accepts millisecond
timestamps directly and floors correctly. The now-unused `MS_TO_SECONDS`
constant is removed. The existing `expected_local` test helper is
updated to match so the positive-path tests still hold (same output for
sub-second positive timestamps).
Fixes#209.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@sachiniyer
sachiniyerforce-pushed the siyer/fix-datetime-negative-timestamp branch from 868c954 to 52db5b1CompareApril 22, 2026 23:04

@devin-ai-integrationdevin-ai-integrationBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

Open in Devin Review

Comment threadsrc/utils/datetime.rs
Comment on lines 28 to 32
fn expected_local(timestamp_ms: i64, fmt: &str) -> String {
chrono::DateTime::from_timestamp(timestamp_ms / MS_TO_SECONDS, 0)
chrono::DateTime::from_timestamp_millis(timestamp_ms)
.expect("valid timestamp")
.with_timezone(&Local)
.format(fmt)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Test helper is tautological with the implementation under test

The expected_local helper at src/utils/datetime.rs:28-34 now uses the exact same from_timestamp_millis call as the production format_timestamp function. This means tests like format_date_known_timestamp are effectively asserting that a function equals itself, providing no independent verification of correctness. This is a pre-existing pattern (the old code also mirrored the production logic), but the migration carried it forward. A stronger approach would use hardcoded expected strings for known timestamps in a fixed timezone, or at least use an independent computation path.

(Refers to lines 28-34)

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@sachiniyer
sachiniyer merged commit 048aa32 into mainApr 22, 2026
12 checks passed
@sachiniyer
sachiniyer deleted the siyer/fix-datetime-negative-timestamp branch April 22, 2026 23:08
@sachiniyersachiniyer mentioned this pull request Apr 22, 2026
2 tasks
sachiniyer added a commit that referenced this pull request Apr 23, 2026
## Summary
Patch release rolling up the seven fixes merged since 0.2.1:
- fix(bugs): print empty-results hint when `--vulns` alone yields no
matches (#264)
- fix(datetime): floor sub-second negative timestamps instead of
snapping to epoch (#262)
- chore(deps): bump rustls-webpki to 0.103.13 for RUSTSEC-2026-0104
(#263)
- fix(repos): normalize whitespace in repo identifiers before lookup
(#261)
- fix(git): parse GitHub remotes with embedded http(s) credentials
(#260)
- fix(auth): redirect browser and surface OAuth errors on PKCE callback
failure (#258)
- refactor(config): rewrite `update_config` through the locked handle
(#257)
On merge, the release workflow will tag `v0.2.2` and publish platform
artifacts via cargo-dist.
## Test plan
- [x] `cargo build` succeeds with version 0.2.2
- [ ] Tag `v0.2.2` is created on merge and release workflow publishes
artifacts
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- devin-review-badge-begin -->
---
<a href="https://app.devin.ai/review/usedetail/cli/pull/265"
target="_blank">
<picture>
<source media="(prefers-color-scheme: dark)"
srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1">
<img
src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1"
alt="Open in Devin Review">
</picture>
</a>
<!-- devin-review-badge-end -->
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Detail Bug] Datetime formatting treats small negative timestamps as the Unix epoch

1 participant

@sachiniyer