Skip to content
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

[HOLD for payment 2024-03-19] [$500] Video duration is displayed incorrectly #37216

Closed
1 of 6 tasks
m-natarajan opened this issue Feb 26, 2024 · 52 comments
Closed
1 of 6 tasks
Assignees
Labels
Awaiting Payment Auto-added when associated PR is deployed to production Bug Something is broken. Auto assigns a BugZero manager. Daily KSv2 External Added to denote the issue can be worked on by a contributor Monthly KSv2

Comments

@m-natarajan
Copy link

m-natarajan commented Feb 26, 2024

If you haven’t already, check out our contributing guidelines for onboarding and email [email protected] to request to join our Slack channel!


Version Number:
Reproducible in staging?: repro for IST timezone
Reproducible in production?: repro for IST timezone
If this was caught during regression testing, add the test name, ID and link from TestRail:
Email or phone of affected tester (no customers):
Logs: https://stackoverflow.com/c/expensify/questions/4856
Expensify/Expensify Issue URL:
Issue reported by: @MonilBhavsar
Slack conversation: https://expensify.slack.com/archives/C049HHMV9SM/p1708409401548339

Action Performed:

  1. Open any chat and click on add attachment
  2. Select any video
  3. In the video player check the start/end timings of the video

Expected Result:

It should start with 00:00

##Actual Result:
For IST timezone(UTC + 5:30), It starts with 30:00 minutes

Workaround:

unknown

Platforms:

Which of our officially supported platforms is this issue occurring on?

  • Android: Native
  • Android: mWeb Chrome
  • iOS: Native
  • iOS: mWeb Safari
  • MacOS: Chrome / Safari
  • MacOS: Desktop

Screenshots/Videos

Add any screenshot/video evidence
Screenshot 2024-02-20 at 11 18 07 AM

Screen Shot 2024-02-26 at 10 54 32 PM

View all open jobs on GitHub

Upwork Automation - Do Not Edit
  • Upwork Job URL: https://www.upwork.com/jobs/~01c4ec8be79be38a61
  • Upwork Job ID: 1762164094751191040
  • Last Price Increase: 2024-02-26
  • Automatic offers:
    • Pujan92 | Contributor | 0
@m-natarajan m-natarajan added External Added to denote the issue can be worked on by a contributor Daily KSv2 Bug Something is broken. Auto assigns a BugZero manager. labels Feb 26, 2024
@melvin-bot melvin-bot bot changed the title Video duration is displayed incorrectly [$500] Video duration is displayed incorrectly Feb 26, 2024
Copy link

melvin-bot bot commented Feb 26, 2024

Job added to Upwork: https://www.upwork.com/jobs/~01c4ec8be79be38a61

@melvin-bot melvin-bot bot added the Help Wanted Apply this label when an issue is open to proposals by contributors label Feb 26, 2024
Copy link

melvin-bot bot commented Feb 26, 2024

Triggered auto assignment to Contributor-plus team member for initial proposal review - @parasharrajat (External)

Copy link

melvin-bot bot commented Feb 26, 2024

Triggered auto assignment to @abekkala (Bug), see https://stackoverflow.com/c/expensify/questions/14418 for more details.

@Pujan92
Copy link
Contributor

Pujan92 commented Feb 26, 2024

Proposal

Please re-state the problem that we are trying to solve in this issue.

For non-UTC timezones the video duration values aren't shown correctly

What is the root cause of that problem?

A new date gets created in the below function convertMillisecondsToTime with the local timezone and formatting on that date returns time(minutes) with the respective timezone. In case of IST(UTC+5:30) format(mm:ss) will give 30:00.

const convertMillisecondsToTime = (milliseconds: number) => {
const date = new Date(milliseconds);
return format(date, 'mm:ss');
};

What changes do you think we should make in order to solve the problem?

Instead of using Date we can use the straight logic to convert milliseconds into the minutes and seconds like below.

const minutes = Math.floor(milliseconds / 60000);
const seconds = String(((milliseconds % 60000) / 1000).toFixed(0)).padStart(2, '0');
return `${minutes}:${seconds}`;

For including hours optionally we can do like below

return hours > 0 ? 
  `${hours}:${String(minutes).padStart(2, '0')}:${seconds}` : `${minutes}:${seconds}`;

@eucool
Copy link
Contributor

eucool commented Feb 26, 2024

Proposal

Please re-state the problem that we are trying to solve in this issue.

Video duration is displayed incorrectly

What is the root cause of that problem?

In the function convertMillisecondsToTime, a new date is generated using the local timezone. The formatting applied to this date results in the representation of time in minutes, accounting for the respective timezone.

What changes do you think we should make in order to solve the problem?

We need to use date-fns-tz package to solve this issue for global timezones

import { formatDuration, intervalToDuration, utcToZonedTime } from 'date-fns-tz';

// Converts milliseconds to 'hours:minutes:seconds' or 'minutes:seconds' format in UTC
const convertMillisecondsToTime = (milliseconds: number) => {
    // Create a new Date object with milliseconds since epoch
    const date = new Date(0);

    // Set the milliseconds
    date.setUTCMilliseconds(milliseconds);

    // Get the duration object
    const duration = intervalToDuration({ start: 0, end: milliseconds });

    // Format the duration in UTC timezone with hours, minutes, and seconds if applicable
    const formattedDuration = formatDuration(duration, {
        format: ['hours', 'minutes', 'seconds'],
    });

    // Format the date in UTC timezone with hours, minutes, and seconds if applicable
    if (formattedDuration.hours > 0) {
        return format(utcToZonedTime(date, 'UTC'), 'HH:mm:ss');
    } else {
        return format(utcToZonedTime(date, 'UTC'), 'mm:ss');
    }
};

export default convertMillisecondsToTime;

Result:

simplescreenrecorder-2024-02-26_23.24.14.mp4

Note:

We already use date-fns-tz at other places as well:

import {format as tzFormat, utcToZonedTime} from 'date-fns-tz';

import {utcToZonedTime} from 'date-fns-tz';

Note:

We shouldn't use formatInTimeZone as this is doesn't work with DST, so my solution would be more fool-proof in this sense ;)

Where my proposal use of utcToZonedTime covers every case and is already used in many places in our existing codebase:

const createdAt = timezoneFormat(utcToZonedTime(new Date(), 'UTC'), CONST.DATE.FNS_DB_FORMAT_STRING);

expect(utcToZonedTime(report.lastReadTime, UTC).getTime()).toBeGreaterThanOrEqual(utcToZonedTime(currentTime, UTC).getTime());

@parasharrajat

This comment was marked as outdated.

Copy link

melvin-bot bot commented Feb 26, 2024

Triggered auto assignment to @francoisl, see https://stackoverflow.com/c/expensify/questions/7972 for more details.

@Pujan92
Copy link
Contributor

Pujan92 commented Feb 26, 2024

@parasharrajat I think the selected proposal won't work as date.setUTCHours(0, 0, 0, 0) will set minutes and seconds to 0 always in the date for start and end time.

@parasharrajat
Copy link
Member

I think I will have to run this myself. Give me few minutes.

@eucool
Copy link
Contributor

eucool commented Feb 26, 2024

@parasharrajat I think the selected proposal won't work as date.setUTCHours(0, 0, 0, 0) will set minutes and seconds to 0 always in the date for start and end time.
Thanks for bringing this up @Pujan92 ,

If this is so then i guess we need to create a condition for the start condition and set the starting to 0 :)

IMO, this should work, but again, i will also test the original proposal and get back.

Update:

Let me update a new proposal accordingly

@parasharrajat
Copy link
Member

parasharrajat commented Feb 26, 2024

My bad, looks like the proposal is not working fine. I always see the same value for both start and end time. I will revisit the proposals in some time.

@Pujan92
Copy link
Contributor

Pujan92 commented Feb 26, 2024

return format(date, 'mm:ss', { utc: true });

I am not seeing the utc as an option within FormatDateOptions here https://date-fns.org/v3.3.1/docs/format#types/FormatDateOptions/397

@parasharrajat
Copy link
Member

That too is a problem.

@ShridharGoel
Copy link
Contributor

ShridharGoel commented Feb 26, 2024

Proposal

Please re-state the problem that we are trying to solve in this issue.

Start and end time are using local timezone because of which it is using 30:00 for IST.

What is the root cause of that problem?

convertMillisecondsToTime method is timezone dependent, it is showing the start and end times based on the user's timezone.

What changes do you think we should make in order to solve the problem?

We can ensure that it picks 00:00 for starting time and is based on UTC.
Below code can be used:

const convertMillisecondsToTime = (milliseconds: number, timezone: string = 'UTC') => {
    const date = new Date(milliseconds);
    const options = {
        timeZone: timezone,
        minute: '2-digit',
        second: '2-digit',
        hour12: false
    };
    return date.toLocaleTimeString('en-US', options);
};

@dragnoir
Copy link
Contributor

dragnoir commented Feb 26, 2024

Proposal

Please re-state the problem that we are trying to solve in this issue.

Wrong time on video

What is the root cause of that problem?

Calculation on convertMillisecondsToTime depend on the Date object. We don't need the local machine Date object to convert milliseconds to time, we can just use math calculation.

What changes do you think we should make in order to solve the problem?

We need to use a functioin that calculate without the need to the Date object. This will prevent all time zone issues. The function below will handle all cases.

function convertMillisecondsToTime(milliseconds) {
  // Return 00:00 if milliseconds is 0 or negative
  if (milliseconds <= 0) {
    return '00:00';
  }

  // Calculate minutes and seconds
  const totalSeconds = Math.floor(milliseconds / 1000);
  const minutes = Math.floor(totalSeconds / 60);
  const seconds = totalSeconds % 60;

  // Format minutes and seconds
  const formattedMinutes = minutes < 10 ? `0${minutes}` : `${minutes}`;
  const formattedSeconds = seconds < 10 ? `0${seconds}` : `${seconds}`;

  // If less than one hour, return only minutes and seconds
  if (minutes < 60) {
    return `${formattedMinutes}:${formattedSeconds}`;
  }

  // If one hour or more, include hours, minutes, and seconds
  const hours = Math.floor(minutes / 60);
  const remainingMinutes = minutes % 60;
  const formattedHours = hours < 10 ? `0${hours}` : `${hours}`;

  // Return formatted time with hours, minutes, and seconds
  return `${formattedHours}:${remainingMinutes}:${formattedSeconds}`;
}

export default MillisecondsToTime;

With this adjustment, the function calculates hours, minutes and seconds directly from milliseconds without involving any timezone-dependent operations. This ensures the output is consistent regardless of the timezone. It also displat mm:ss if no hours, and hh:mm;ss if it's longer

@eucool
Copy link
Contributor

eucool commented Feb 26, 2024

Updated proposal:

@parasharrajat , updated my proposal to use date-fns-tz module instead, and so sorry for the previous proposal, i have tested the new one locally and it work well screen recording attached :)

@dukenv0307
Copy link
Contributor

dukenv0307 commented Feb 26, 2024

Proposal

Please re-state the problem that we are trying to solve in this issue.

For IST timezone(UTC + 5:30), It starts with 30:00 minutes

What is the root cause of that problem?

The duration is being formatted in a local time, which has minutes offset

What changes do you think we should make in order to solve the problem?

We can simply format the time in UTC timezone by updating this to

return formatInTimeZone(date, 'UTC', 'mm:ss');

The formatInTimeZone is from date-fns-tz.

Later once we support the h:mm:ss format as mentioned here, we can just use like below to have Youtube-consistent video length display:

const timeFormat = milliseconds >= 60 * 60 * 1000 ? 'h:mm:ss' : 'm:ss'; // check if the video length is more than 1 hour
return formatInTimeZone(date, 'UTC', timeFormat);

we can optionally use mm:ss if the video is less than 1 hour, but this is consistent with Youtube.

FYI: utcToZonedTime is a workaround because format will still convert using the local timezone, the utcToZonedTime just makes the time wrong first, so it's like wrong time + wrong timezone = sometimes right formatting. Meanwhile the formatInTimeZone works with the date we already have and just formats the date in the correct UTC timezone, instead of the local timezone that causes the issue.

The formatInTimeZone won't have any issue with DST because we're using UTC here, nothing DST-related.

What alternative solutions did you explore? (Optional)

NA

@garatkarr
Copy link

garatkarr commented Feb 26, 2024

Proposal

Please re-state the problem that we are trying to solve in this issue.

When adding a video attachment in the chat page, the preview of the video has the start duration at 30:00 instead of the expected 00:00 for the IST time zone. This issue does not exist for EST or PST time zones.

What is the root cause of that problem?

We are trying to convert duration into a Date object which is incompatible. A Date consists of a month, date, year, hour, minute, second and millisecond. The duration of a video does not and should not have month, date, year. The approach to convert duration in milliseconds to a Date object is flawed.

What changes do you think we should make in order to solve the problem?

Completely remove the convertMillisecondsToTime function as the function name is not a good description of what it's supposed to do. Create a new function formatMillisecondsToTime to format the duration in milliseconds to minutes:seconds format. Replace all calls to convertMillisecondsToTime with formatMillisecondsToTime.

const padZero = (num) => String(num).padStart(2, '0')

// Formats milliseconds to 'minutes:seconds' format
const formatMillisecondsToTime = (milliseconds: number) => {
    const duration = intervalToDuration({ start: 0, end: milliseconds})

    if(duration.hours > 0) {
        return `${padZero(duration.hours)}:${padZero(duration.minutes)}:${padZero(duration.seconds)}`
    } else {
        return `${padZero(duration.minutes)}:${padZero(duration.seconds)}`
    }
};

What alternative solutions did you explore? (Optional)

n/a

@webbdays
Copy link

webbdays commented Feb 26, 2024

Having straight forward way to convert milliseconds to time is good.
Having hours is also good.
@garatkarr proposal does that.
If we feel this from @garatkarr needs additional dependency date-fns

const duration = intervalToDuration({ start: 0, end: milliseconds})

then we can go with proposal from @dragnoir with little modifications for hours as well.

const  minutes  =  Math.floor(totalSeconds  /  60);

to

const  hours      =  Math.floor((totalSeconds / 3600));
const  minutes  =  Math.floor((totalSeconds % 3600) /  60);

Along with including hours in formatted string.

Sorry @Pujan92 actually missed your proposal of similar kind. ✔️

Copy link

melvin-bot bot commented Feb 26, 2024

📣 @webbdays! 📣
Hey, it seems we don’t have your contributor details yet! You'll only have to do this once, and this is how we'll hire you on Upwork.
Please follow these steps:

  1. Make sure you've read and understood the contributing guidelines.
  2. Get the email address used to login to your Expensify account. If you don't already have an Expensify account, create one here. If you have multiple accounts (e.g. one for testing), please use your main account email.
  3. Get the link to your Upwork profile. It's necessary because we only pay via Upwork. You can access it by logging in, and then clicking on your name. It'll look like this. If you don't already have an account, sign up for one here.
  4. Copy the format below and paste it in a comment on this issue. Replace the placeholder text with your actual details.
    Screen Shot 2022-11-16 at 4 42 54 PM
    Format:
Contributor details
Your Expensify account email: <REPLACE EMAIL HERE>
Upwork Profile Link: <REPLACE LINK HERE>

@Krishna2323
Copy link
Contributor

Krishna2323 commented Feb 26, 2024

Proposal

Please re-state the problem that we are trying to solve in this issue.

Video duration is displayed incorrectly

What is the root cause of that problem?

The Date object constructor and formatting functions consider local time zone when creating and formatting the date. This leads to inconsistency if the local time zone differs from UTC.

const date = new Date(milliseconds);

What changes do you think we should make in order to solve the problem?

We can simply pass year, monthIndex, date, hours, minutes, seconds as 0 and for the ms we will pass the milliseconds we get. By setting all date components to zero except milliseconds, we create a valid base date from which milliseconds are then derived. This approach prevents any time zone differences and ensures consistent display of video durations across different locations.

const convertMillisecondsToTime = (milliseconds: number) => {
    const date = new Date(0, 0, 0, 0, 0, 0, milliseconds);
    return format(date, 'mm:ss');
};

Result

time_stamp_bug.mp4

Alternative

We can get seconds, hours, minutes,remainingSeconds by calculation and then use the pass it to date and then the date to format function.

const convertMillisecondsToTime = (milliseconds: number) => {
    // Convert milliseconds to hours, minutes, and seconds
    const seconds = Math.floor(milliseconds / 1000);
    const hours = Math.floor(seconds / 3600);
    const minutes = Math.floor((seconds % 3600) / 60);
    const remainingSeconds = seconds % 60;

    // Format the time using date-fns
    const formattedTime = format(new Date(0, 0, 0, hours, minutes, remainingSeconds), hours ? 'hh:mm:ss' : 'mm:ss');

    return formattedTime;
};

@garatkarr
Copy link

@webbdays please note, the dependency on date-fns is not a new dependency. the old code imported date-fns.

@melvin-bot melvin-bot bot removed the Help Wanted Apply this label when an issue is open to proposals by contributors label Mar 1, 2024
Copy link

melvin-bot bot commented Mar 1, 2024

📣 @Pujan92 🎉 An offer has been automatically sent to your Upwork account for the Contributor role 🎉 Thanks for contributing to the Expensify app!

Offer link
Upwork job
Please accept the offer and leave a comment on the Github issue letting us know when we can expect a PR to be ready for review 🧑‍💻
Keep in mind: Code of Conduct | Contributing 📖

@melvin-bot melvin-bot bot added the Overdue label Mar 4, 2024
Copy link

melvin-bot bot commented Mar 4, 2024

@francoisl, @abekkala, @Pujan92, @parasharrajat Uh oh! This issue is overdue by 2 days. Don't forget to update your issues!

@melvin-bot melvin-bot bot added Reviewing Has a PR in review Weekly KSv2 and removed Daily KSv2 Overdue labels Mar 4, 2024
@abekkala
Copy link
Contributor

abekkala commented Mar 4, 2024

Not overdue, PR has been created and linked

@melvin-bot melvin-bot bot added Weekly KSv2 Awaiting Payment Auto-added when associated PR is deployed to production and removed Weekly KSv2 labels Mar 12, 2024
@melvin-bot melvin-bot bot changed the title [$500] Video duration is displayed incorrectly [HOLD for payment 2024-03-19] [$500] Video duration is displayed incorrectly Mar 12, 2024
@melvin-bot melvin-bot bot removed the Reviewing Has a PR in review label Mar 12, 2024
Copy link

melvin-bot bot commented Mar 12, 2024

Reviewing label has been removed, please complete the "BugZero Checklist".

Copy link

melvin-bot bot commented Mar 12, 2024

The solution for this issue has been 🚀 deployed to production 🚀 in version 1.4.50-5 and is now subject to a 7-day regression period 📆. Here is the list of pull requests that resolve this issue:

If no regressions arise, payment will be issued on 2024-03-19. 🎊

For reference, here are some details about the assignees on this issue:

Copy link

melvin-bot bot commented Mar 12, 2024

BugZero Checklist: The PR fixing this issue has been merged! The following checklist (instructions) will need to be completed before the issue can be closed:

  • [@Pujan92 / @parasharrajat] The PR that introduced the bug has been identified. Link to the PR:
  • [@Pujan92 / @parasharrajat] The offending PR has been commented on, pointing out the bug it caused and why, so the author and reviewers can learn from the mistake. Link to comment:
  • [@Pujan92 / @parasharrajat] A discussion in #expensify-bugs has been started about whether any other steps should be taken (e.g. updating the PR review checklist) in order to catch this type of bug sooner. Link to discussion:
  • [@Pujan92 / @parasharrajat] Determine if we should create a regression test for this bug.
  • [@Pujan92 / @parasharrajat] If we decide to create a regression test for the bug, please propose the regression test steps to ensure the same bug will not reach production again.
  • [@abekkala] Link the GH issue for creating/updating the regression test once above steps have been agreed upon:

@abekkala
Copy link
Contributor

PAYMENT SUMMARY FOR MAR 19

@parasharrajat parasharrajat mentioned this issue Mar 13, 2024
58 tasks
@parasharrajat
Copy link
Member

BugZero Checklist: The PR fixing this issue has been merged! The following checklist (instructions) will need to be completed before the issue can be closed:

Regression Test Steps

  1. Open any chat and click on add attachment
  2. Select any video
  3. In the video player check the start/end timings of the video

Do you agree 👍 or 👎 ?

@abekkala
Copy link
Contributor

Regression Test Steps

  1. Open any chat and click on add attachment
  2. Select any video
  3. In the video player verify the start/end timings of the video

@melvin-bot melvin-bot bot added Daily KSv2 Monthly KSv2 and removed Weekly KSv2 labels Mar 18, 2024
@abekkala
Copy link
Contributor

@Pujan92 payment sent and contract ended - thank you! 🎉

@abekkala
Copy link
Contributor

PAYMENT SUMMARY FOR MAR 19

@parasharrajat
Copy link
Member

Payment requested as per #37216 (comment)

@JmillsExpensify
Copy link

$500 approved for @parasharrajat

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Awaiting Payment Auto-added when associated PR is deployed to production Bug Something is broken. Auto assigns a BugZero manager. Daily KSv2 External Added to denote the issue can be worked on by a contributor Monthly KSv2
Projects
None yet
Development

No branches or pull requests