0

I am trying to make a countdown timer for ticket response expiry. My code will successfully calculate the time left when dealing with hours bar the extra hour (+0100) GMT.

I have tried dealing with this in all manner of ways suggested on here to no avail. Any suggestions? Should I give in & learn Luxon?

The converttoUTC function seen is not called as it has not worked & only messed up the calculation further.

The dates that's been pulled from the table is in the following format 2022-04-15 17:47:19 The Time Limits being pulled from the table are in the following format, "15 mins" "6 hours".

    <!--===========================================================================================-->

    <script>
        function func(creationDatePlusLimit) {
            // var dateValue= document.getElementById("date").value;

            var date =  Math.abs((new Date().getTime() / 1000).toFixed(0));
            var date2 = Math.abs((new Date(createdOnDate).getTime() / 1000).toFixed(0));
            var diff = date2 - date;

            var days = Math.floor(diff / 86400);
            var hours = Math.floor(diff / 3600) % 24;
            var mins = Math.floor(diff / 60) % 60;
            var secs = diff % 60;


            // document.getElementById("data").innerHTML = days + " days, " + hours + ":" + mins + ":" + secs;
            if (days>=0) {
                return days + " days, " + hours + ":" + mins + ":" + secs;
            } else {
                return "late";
            }
        }


        const loopThroughTableRows = () => {
            const tableRows = Array.from(document.getElementsByTagName('tr'));
            tableRows.shift(); // removes first one, header

            tableRows.forEach(row => {
                var rowCols = row.getElementsByTagName('td');
                var createdOnDate = rowCols[3];
                var timeLimit = rowCols[7];

                function convertDateToUTC(date) {
                    return new Date(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds());
                }

               const  createdDate = new Date(createdOnDate.innerText);




                // if time limit is in days, remove text, & add to creation date-------------------//
                var limitdays = timeLimit.innerText;
                if (limitdays.includes(" days")) {
                    limitdays = limitdays.replace("days", "");
                    limitdays= parseInt(limitdays);

                    function addDaysToDate(createddate, days) {
                        var result = createddate;
                        result.setDate(createddate.getDate()+days);
                        return result;
                    }
                    var newDate = addDaysToDate(createdDate, limitdays);

                    // format newdate to iso & remove unwanted characters
                    newDate = newDate.toISOString();
                    if (newDate.includes("T")) {
                        newDate = newDate.replace("T", " ");
                    }
                    if (newDate.includes(".000Z")) {
                        newDate = newDate.replace(".000Z", "");
                    }
                };
                //===================================================================================//

                // if time limit is in hours, remove text, & add to creation date-------------------//
                // var limithours = timeLimit.innerText;
                // if (limithours.includes(" hours")) {
                //     limithours = limithours.replace("hours", "");
                //     limithours= parseInt(limithours);
                //
                //     function addHoursToDate(createddate, hours) {
                //         var result = createddate;
                //         // result.setHours(createddate.getDate()+6);
                //         return result;
                //     }
                //     var newDate = addHoursToDate(createdDate, limithours);
                //
                //     // format newdate to iso & remove unwanted characters
                //     newDate = newDate.toISOString();
                //     if (newDate.includes("T")) {
                //         newDate = newDate.replace("T", " ");
                //     }
                //     if (newDate.includes(".000Z")) {
                //         newDate = newDate.replace(".000Z", "");
                //     }
                // };
                //===================================================================================//

            const testRow = rowCols[8];
                const timeDifference = func(newDate);
                testRow.innerText = newDate;
            });
        }
        loopThroughTableRows();

        setInterval(loopThroughTableRows, 1000)
    </script>   
  • Managed to get it working for days with a rather sketchy newDate.setHours(newDate.getHours()+2); It is not calculating the hours correctly at all though. I am in the UK. I thought I'd have to add 1 hours not 2. Bizarre. – riverside96 Apr 18 '22 at 02:05
  • We heavily rely on Luxon to avoid running into time zone issues and daylight saving timings. It saves you time in the long run. – Satya S Apr 18 '22 at 02:17
  • 1
    A major problem with trying to work out what's happening is that the code parses strings to make dates, converts milliseconds to seconds for calcs then back to milliseconds for dates, counts days as 8.64e4 seconds but also using get/setDate, has a horrid *convertDateToUTC" method, etc. When you mix methods like that it's really hard to work out what's happening. – RobG Apr 18 '22 at 06:46
  • Keep in mind that Date internally represents the value in UTC - only when formatting it back, the timezone is taken into account. So if you keep all your calculations in UTC - everything should be fine. – IVO GELOV Apr 18 '22 at 07:43

1 Answers1

0

Given you have a creation date like "2022-04-15 17:47:19" and duration to expiry in the format "n [days|hours|minutes]", you probably want to do everything as local to avoid timezone issues. If you use Date objects, then it's simple represent it as a UTC timestamp using toISOString.

Consider the following, which returns a Date object for the expiry based on the creationDate and time limit. It does everything as local, so timezone and daylight saving issues are handled by the Date object. There's no validation of input, so that should be added.

// Parse YYYY-MM-DD HH:mm:ss as local
function parseISOLocal (ts) {
  let [Y, M, D, H, m, s] = ts.split(/\D/);
  return new Date(Y, M-1, D, H, m, s);
}

// Format a Date as YYYY-MM-DD HH:mm:ss
function formatISOLocal(date = new Date()) {
  return date.toLocaleString('en-CA',{hour12: false}).replace(',','');
}

// Parse limit in "value [days|hours|minutes]" to {value, unit}
// e.g. "3 days" to {value: 3, unit:'day'}
function normaliseLimit(limit) {
  let [value, unit] = limit.toLowerCase().split(/\s+/);
  return {value: +value, unit: {d:'day', h:'hour', m:'minute'}[unit[0]]};
}

// Given:
//   createdAt in YYYY-MM-DD HH:mm:ss format and
//   limit as "number [days|hours|minutes]" return a Date for expiry
//   I.e. createdAt plus limit
function getExpiryDate(createdAt, limitString) {
  let expiry = parseISOLocal(createdAt);
  let limit = normaliseLimit(limitString);
  let method = {day:'Date', hour:'Hours', minute:'Minutes'}[limit.unit];
  return new Date(expiry[`set${method}`](expiry[`get${method}`]() + limit.value));
}

let createdAt = formatISOLocal();
[{createdAt: createdAt, limit:'1 Day'},
 {createdAt: createdAt, limit:'3 hours'},
 {createdAt: createdAt, limit:'12 minutes'}
].forEach(({createdAt, limit}) => console.log(
  `createdAt: ${createdAt}\n` +
  `limit    : ${limit}\n` +
  `Expires  : ${formatISOLocal(getExpiryDate(createdAt, limit))}`
));

Once you have the expiry date, you can work out the remaining time as days, hours, minutes, seconds as given at Difference between two dates in years, months, days in JavaScript and use it in a timer to show a count down, to work out which items have expired, etc.

RobG
  • 142,382
  • 31
  • 172
  • 209
  • I managed to get it working by manually setting an additional hour for the days, hours & mins. Your solution sure does look clean though! – riverside96 Apr 18 '22 at 14:24