Skip to content

fix(ta): seconds to duration function #3891

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 24, 2025
Merged

Conversation

joseph-sentry
Copy link
Contributor

@joseph-sentry joseph-sentry commented Jun 11, 2025

The total test run time on https://app.codecov.io/github/getsentry/sentry/tests/master is bugged, this fixes that.

Copy link

codecov bot commented Jun 11, 2025

Bundle Report

Changes will decrease total bundle size by 2.56kB (-0.02%) ⬇️. This is within the configured threshold ✅

Detailed changes
Bundle name Size Change
gazebo-production-system 6.23MB -1.28kB (-0.02%) ⬇️
gazebo-production-esm 6.31MB -1.29kB (-0.02%) ⬇️

Affected Assets, Files, and Routes:

view changes for bundle: gazebo-production-system

Assets Changed:

Asset Name Size Change Total Size Change (%)
assets/vendor_date_fns-legacy.*.js -1.35kB 26.34kB -4.87%
assets/dates-legacy.*.js 71 bytes 568 bytes 14.29% ⚠️

Files in assets/dates-legacy.*.js:

  • ./src/shared/utils/dates.ts → Total Size: 1.1kB
view changes for bundle: gazebo-production-esm

Assets Changed:

Asset Name Size Change Total Size Change (%)
assets/vendor_date_fns.*.js -1.37kB 28.64kB -4.56%
assets/dates.*.js 82 bytes 532 bytes 18.22% ⚠️

Files in assets/dates.*.js:

  • ./src/shared/utils/dates.ts → Total Size: 1.08kB

@codecov-staging
Copy link

codecov-staging bot commented Jun 11, 2025

Bundle Report

Changes will decrease total bundle size by 2.56kB (-0.02%) ⬇️. This is within the configured threshold ✅

Detailed changes
Bundle name Size Change
gazebo-staging-system 6.23MB -1.28kB (-0.02%) ⬇️
gazebo-staging-esm 6.31MB -1.29kB (-0.02%) ⬇️

Affected Assets, Files, and Routes:

view changes for bundle: gazebo-staging-system

Assets Changed:

Asset Name Size Change Total Size Change (%)
assets/vendor_date_fns-legacy.*.js -1.35kB 26.34kB -4.87%
assets/dates-legacy.*.js 71 bytes 568 bytes 14.29% ⚠️

Files in assets/dates-legacy.*.js:

  • ./src/shared/utils/dates.ts → Total Size: 1.1kB
view changes for bundle: gazebo-staging-esm

Assets Changed:

Asset Name Size Change Total Size Change (%)
assets/vendor_date_fns.*.js -1.37kB 28.64kB -4.56%
assets/dates.*.js 82 bytes 532 bytes 18.22% ⚠️

Files in assets/dates.*.js:

  • ./src/shared/utils/dates.ts → Total Size: 1.08kB

@codecov-qa
Copy link

codecov-qa bot commented Jun 11, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 98.73%. Comparing base (4cec586) to head (3755ba1).
Report is 5 commits behind head on main.

✅ All tests successful. No failed tests found.

@@           Coverage Diff           @@
##             main    #3891   +/-   ##
=======================================
  Coverage   98.72%   98.73%           
=======================================
  Files         827      827           
  Lines       15029    15040   +11     
  Branches     4297     4306    +9     
=======================================
+ Hits        14838    14849   +11     
  Misses        184      184           
  Partials        7        7           
Files with missing lines Coverage Δ
src/shared/utils/dates.ts 100.00% <100.00%> (ø)
Components Coverage Δ
Assets 100.00% <ø> (ø)
Layouts 99.71% <ø> (ø)
Pages 98.28% <ø> (ø)
Services 99.35% <ø> (ø)
Shared 99.12% <100.00%> (+<0.01%) ⬆️
UI 99.15% <ø> (ø)

Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 4cec586...3755ba1. Read the comment docs.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@codecov-notifications
Copy link

codecov-notifications bot commented Jun 11, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

✅ All tests successful. No failed tests found.

@@           Coverage Diff           @@
##             main    #3891   +/-   ##
=======================================
  Coverage   98.72%   98.73%           
=======================================
  Files         827      827           
  Lines       15029    15040   +11     
  Branches     4297     4298    +1     
=======================================
+ Hits        14838    14849   +11     
  Misses        184      184           
  Partials        7        7           
Files with missing lines Coverage Δ
src/shared/utils/dates.ts 100.00% <100.00%> (ø)
Components Coverage Δ
Assets 100.00% <ø> (ø)
Layouts 99.71% <ø> (ø)
Pages 98.28% <ø> (ø)
Services 99.35% <ø> (ø)
Shared 99.12% <100.00%> (+<0.01%) ⬆️
UI 99.15% <ø> (ø)

Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 4cec586...3755ba1. Read the comment docs.

Copy link

codecov-public-qa bot commented Jun 11, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 98.73%. Comparing base (4cec586) to head (3755ba1).
Report is 5 commits behind head on main.

✅ All tests successful. No failed tests found.

@@           Coverage Diff           @@
##             main    #3891   +/-   ##
=======================================
  Coverage   98.72%   98.73%           
=======================================
  Files         827      827           
  Lines       15029    15040   +11     
  Branches     4297     4306    +9     
=======================================
+ Hits        14838    14849   +11     
  Misses        184      184           
  Partials        7        7           
Files with missing lines Coverage Δ
src/shared/utils/dates.ts 100.00% <100.00%> (ø)
Components Coverage Δ
Assets 100.00% <ø> (ø)
Layouts 99.71% <ø> (ø)
Pages 98.28% <ø> (ø)
Services 99.35% <ø> (ø)
Shared 99.12% <100.00%> (+<0.01%) ⬆️
UI 99.15% <ø> (ø)

Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 4cec586...3755ba1. Read the comment docs.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link

codecov bot commented Jun 11, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 98.73%. Comparing base (4cec586) to head (3755ba1).
Report is 5 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #3891   +/-   ##
=======================================
  Coverage   98.72%   98.73%           
=======================================
  Files         827      827           
  Lines       15029    15040   +11     
  Branches     4305     4306    +1     
=======================================
+ Hits        14838    14849   +11     
  Misses        184      184           
  Partials        7        7           
Files with missing lines Coverage Δ
src/shared/utils/dates.ts 100.00% <100.00%> (ø)
Components Coverage Δ
Assets 100.00% <ø> (ø)
Layouts 99.71% <ø> (ø)
Pages 98.28% <ø> (ø)
Services 99.35% <ø> (ø)
Shared 99.12% <100.00%> (+<0.01%) ⬆️
UI 99.15% <ø> (ø)

Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 4cec586...3755ba1. Read the comment docs.

@codecov-releaser
Copy link
Contributor

codecov-releaser commented Jun 11, 2025

✅ Deploy preview for gazebo ready!

Previews expire after 1 month automatically.

Storybook

Commit Created Cloud Enterprise
d6255da Wed, 11 Jun 2025 22:38:19 GMT Expired Expired
cd396a0 Thu, 12 Jun 2025 15:25:53 GMT Cloud Enterprise

Copy link
Contributor

✅ Sentry found no issues in your recent changes ✅

@joseph-sentry joseph-sentry requested a review from a team June 12, 2025 14:39
@rohitvinnakota-codecov
Copy link
Contributor

@sentry-ai-review

Copy link
Contributor

On it! We are reviewing the PR and will provide feedback shortly.

Copy link
Contributor

PR Description

This pull request improves the formatTimeFromSeconds utility function to provide a more accurate and efficient way to format a duration given in seconds. The primary goal is to replace the date-fns intervalToDuration function with a manual calculation, which reduces the dependency on date-fns and potentially improves performance. Additionally, the change addresses edge cases and improves the handling of float values.

Click to see more

Key Technical Changes

The core technical change is the replacement of date-fns intervalToDuration with a manual calculation of days, hours, minutes, and seconds. This involves using Math.floor and the modulo operator (%) to extract the different time components from the total seconds. The code also includes improved null and negative value handling, returning 'N/A' for invalid inputs. A new edge case was added to return '<1s' when the duration is less than 1 second. A test case was added to verify the correct formatting of float values.

Architecture Decisions

The architectural decision is to move away from the date-fns library for this specific utility function. This reduces the overall bundle size and removes a dependency. The manual calculation approach was chosen for its simplicity and potential performance benefits. The decision to return '<1s' for durations less than 1 second is a design choice to provide more informative output than '0s' in such cases.

Dependencies and Interactions

This change removes the dependency on intervalToDuration from date-fns within the formatTimeFromSeconds function. The function itself is a utility and doesn't directly interact with other parts of the system besides being called by other components that need to display formatted durations. Therefore, the impact on other parts of the system should be minimal, assuming the function continues to produce the expected output format.

Risk Considerations

The main risk is the potential for introducing errors in the manual calculation logic. Thorough testing is crucial to ensure the correctness of the new implementation, especially for edge cases and float values. Another consideration is the change in output for durations less than 1 second (from '0s' to '<1s'), which might affect existing components that rely on the previous output format. This change should be carefully reviewed to ensure compatibility.

Notable Implementation Details

The implementation uses Math.floor to truncate the time components to integers. The modulo operator (%) is used to extract the remaining seconds after calculating each time component (days, hours, minutes). The code constructs an array of time parts and joins them with spaces to create the final formatted string. The handling of null, negative, and zero values is done explicitly at the beginning of the function.

Comment on lines 21 to 24
const days = Math.floor(totalSeconds / 86400)
const hours = Math.floor((totalSeconds % 86400) / 3600)
const minutes = Math.floor((totalSeconds % 3600) / 60)
const seconds = Math.floor(totalSeconds % 60)
Copy link
Contributor

Choose a reason for hiding this comment

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

The manual calculation approach is good, but consider adding comments to explain the magic numbers for better maintainability. 86400 (seconds in a day), 3600 (seconds in an hour), and 60 (seconds in a minute) should be documented.

Suggested change
const days = Math.floor(totalSeconds / 86400)
const hours = Math.floor((totalSeconds % 86400) / 3600)
const minutes = Math.floor((totalSeconds % 3600) / 60)
const seconds = Math.floor(totalSeconds % 60)
// Calculate time components
const SECONDS_PER_DAY = 86400
const SECONDS_PER_HOUR = 3600
const SECONDS_PER_MINUTE = 60
const days = Math.floor(totalSeconds / SECONDS_PER_DAY)
const hours = Math.floor((totalSeconds % SECONDS_PER_DAY) / SECONDS_PER_HOUR)
const minutes = Math.floor((totalSeconds % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE)
const seconds = Math.floor(totalSeconds % SECONDS_PER_MINUTE)

Comment on lines 40 to 42
if (timeParts.length === 0 && totalSeconds > 0) {
return '<1s'
}
Copy link
Contributor

Choose a reason for hiding this comment

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

The condition timeParts.length === 0 && totalSeconds > 0 could be simplified since we already know totalSeconds > 0 from the earlier checks. Also, consider if this edge case is actually needed - if all time parts are 0 but totalSeconds > 0, it means totalSeconds is between 0 and 1, which might be better represented as '0s' for consistency.

Suggested change
if (timeParts.length === 0 && totalSeconds > 0) {
return '<1s'
}
if (timeParts.length === 0) {
return '0s'
}

Comment on lines +37 to +39

it('returns the correct time format when totalSeconds is a float', () => {
expect(formatTimeFromSeconds(12901948.144373389)).toBe('149d 7h 52m 28s')
Copy link
Contributor

Choose a reason for hiding this comment

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

The test case for float values is good, but the specific large float value 12901948.144373389 seems arbitrary. Consider using a more readable test case or adding a comment explaining why this specific value was chosen. Also, consider adding more edge cases for floats, such as values between 0 and 1.

Suggested change
it('returns the correct time format when totalSeconds is a float', () => {
expect(formatTimeFromSeconds(12901948.144373389)).toBe('149d 7h 52m 28s')
it('returns the correct time format when totalSeconds is a float', () => {
// Test large float value
expect(formatTimeFromSeconds(12901948.144373389)).toBe('149d 7h 52m 28s')
})
it('returns "0s" when totalSeconds is a small float less than 1', () => {
expect(formatTimeFromSeconds(0.5)).toBe('0s')
})

Comment on lines 22 to 24
const SECONDS_PER_DAY = 86400
const SECONDS_PER_HOUR = 3600
const SECONDS_PER_MINUTE = 60
Copy link
Contributor

Choose a reason for hiding this comment

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

these can be defined outside of the function

Comment on lines 34 to 49
if (days > 0) {
timeParts.push(`${days}d`)
}
if (hours > 0) {
timeParts.push(`${hours}h`)
}
if (minutes > 0) {
timeParts.push(`${minutes}m`)
}
if (seconds > 0) {
timeParts.push(`${seconds}s`)
}

if (timeParts.length === 0) {
return '<1s'
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Thoughts on keeping the original code here if we just moved the <1s check before?

  if (totalSeconds < 1) {
    return '<1s'
  }

  return [
    days ? `${days}d` : '',
    hours ? `${hours}h` : '',
    minutes ? `${minutes}m` : '',
    seconds ? `${seconds}s` : '',
  ]
    .filter(Boolean)
    .join(' ')

This would exit earlier and skip all of lines 34-49 if we're between 0 and 1 second

@joseph-sentry joseph-sentry enabled auto-merge June 24, 2025 19:28
@joseph-sentry joseph-sentry added this pull request to the merge queue Jun 24, 2025
Merged via the queue into main with commit 8936517 Jun 24, 2025
84 of 89 checks passed
@joseph-sentry joseph-sentry deleted the joseph/fix-total-duration branch June 24, 2025 19:37
Sign up for free to 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.

4 participants