Jump to content

Php and javascript with timestamp and countdown


PNewCode
Go to solution Solved by Barand,

Recommended Posts

Hello :) I hope everyone is having an awesome day!
I have a nifty little countdown script that works how it's intended. I bought this from someone (only to find out he just copied and pasted it from a site that had it free) so he doesn't know how to alter it.
I am VERY brand new to JS and while what I have makes sense to me, I lack the understanding on how to make this work, despite all the studying I've got done

So here is what I want to make happen (this is day 3 on this and I can't find a clear solution)
 

In my database table, I have "duration" and "created_at" columns (there are other columns but it's just other info)
This is entered from a form that is set up to start an auction.
It successfully enters the time stamp (for example: 2023-07-16 12:45:00)
and the duration is entered successfully too (for example: 30). This number for the duration is entered to set up different lengths of time that the auction will run (sometimes 10 min sometimes 30, etc)

What I can't seem to make happen and trying is 2 things

1: Make the timer work with adding whatever is in the duration to the timestamp time, to make that count down.
2: Different time zones show different time remaining (Because the timestamp). So I need a way to have it adjusted to the viewers timezone when seeing this


Here is the full page of what I have. You'll notice that "duration" isn't in the js right now, but I couldn't get it to work with it. I'm stuck like a fly on maple syrup
BONUS THANKS if you can also tell me how to change the font color of the displaying "minutes, hours, seconds" text

 

<?php


error_reporting(E_ALL);
ini_set('display_errors', '1');


$mysqli = new mysqli(connection info deleted for posting);

if ($mysqli -> connect_errno) {
  echo "Failed to connect to MySQL: " . $mysqli -> connect_error;
  exit();
}

$sql = "SELECT * FROM auctiontitle";


if ($result = $mysqli -> query($sql)) {
  while($row = $result->fetch_assoc()) {



 $duration =  $row["duration"];
 $created_at =  $row["created_at"];
 $date =  "$created_at";





  
  }
} else {
  echo "0 results";
}



?>
<body marginwidth="0" marginheight="0">
<div align="center"> <font size="4"><b><font face="Verdana, Arial, Helvetica, sans-serif" color="#CCCCFF"> 
<div id="data" align="center"></div>

  <input type="hidden" id="date" value="<?php echo $date; ?>">
  <script>
    function func() {
        var dateValue = document.getElementById("date").value;
 
        var date = Math.abs((new Date().getTime() / 1000).toFixed(0));
        var date2 = Math.abs((new Date(dateValue).getTime() / 1000).toFixed(0));
 
        var diff = date2 - date;
 
        var days = Math.floor(diff / 86400);
        var hours = Math.floor(diff / 3600) % 24;
        var minutes = Math.floor(diff / 60) % 60;
        var seconds = diff % 60;
 
        var daysStr = days;
        if (days < 10) {
            daysStr = "0" + days;
        }
  
        var hoursStr = hours;
        if (hours < 10) {
            hoursStr = "0" + hours;
        }
  
        var minutesStr = minutes;
        if (minutes < 10) {
            minutesStr = "0" + minutes;
        }
  
        var secondsStr = seconds;
        if (seconds < 10) {
            secondsStr = "0" + seconds;
        }
 
        if (days < 0 && hours < 0 && minutes < 0 && seconds < 0) {
            daysStr = "00";
            hoursStr = "00";
            minutesStr = "00";
            secondsStr = "00";
 
            console.log("close");
            if (typeof interval !== "undefined") {
                clearInterval(interval);
            }
        }
 
        document.getElementById("data").innerHTML = hoursStr + " Hours & " + minutesStr + " Minutes & " + secondsStr + " Seconds";
    }
 
    func();
    var interval = setInterval(func, 1000);
</script>
  </font></b></font></div>

 

Link to comment
Share on other sites

@Barand I love the look of that! Very nice and fancy. However it doesn't work right. When I changed the target timestamp to 2023-07-16 18:45:00 that should have around 5 hours, 45min left, but it shows there's only an hour remaining. So if that is to detect time zones then it doesn't work right. But thank you for the post it's very nice looking
This is what it shows on the page (it's 1pm here)
image.png.aa97d25691a381ce033d1e407a576c74.png

Link to comment
Share on other sites

I do it a little different way - I do all the time figure in JavaScript (I use Vanilla JavaScript) ->

"use strict";
// Function to calculate the time remaining till a certain end time
const getTimeRemaining = (countdown_date) => {
    // Parse the end time and current time into milliseconds
    const endtimeParsed = Date.parse(countdown_date);
    const nowParsed = Date.parse(new Date());

    // Calculate the total remaining time in milliseconds
    const total = endtimeParsed - nowParsed;

    // Breakdown the total time into days, hours, minutes, and seconds
    const seconds = Math.floor((total / 1000) % 60);
    const minutes = Math.floor((total / 1000 / 60) % 60);
    const hours = Math.floor((total / (1000 * 60 * 60)) % 24);
    const days = Math.floor(total / (1000 * 60 * 60 * 24));

    // Return a time object that has the total remaining time and the breakdown
    return {
        total,
        days,
        hours,
        minutes,
        seconds
    };
};

// Function to display a countdown clock on the webpage
const myClock = (id, countdown_date) => {
    // Find the clock and its components by their IDs
    const clock = document.getElementById(`display_clock${id}`);
    const daysSpan = clock.querySelector(`.day${id}`);
    const hoursSpan = clock.querySelector(`.hour${id}`);
    const minutesSpan = clock.querySelector(`.minute${id}`);
    const secondsSpan = clock.querySelector(`.second${id}`);

    // Function to update the clock display
    const updateClock = () => {
        // Get the remaining time
        const time = getTimeRemaining(countdown_date);

        // Update the display of each component of the clock
        // padStart() is used to ensure that all components are two digits
        daysSpan.textContent = time.days;
        hoursSpan.textContent = String(time.hours).padStart(2, '0');
        minutesSpan.textContent = String(time.minutes).padStart(2, '0');
        secondsSpan.textContent = String(time.seconds).padStart(2, '0');

        // If the total remaining time is zero or less, stop the clock by clearing the interval
        if (time.total <= 0) {
            clearInterval(timeInterval);
        }
    }

    // Call updateClock once immediately, then at regular intervals
    updateClock();
    const timeInterval = setInterval(updateClock, 1000);
};

function fetchRoutine() {
    // Define the data you want to send to the server
    const grabDate = "myDate=endDate";

    // Define the options for the fetch call
    const fetchOptions = {
        method: 'POST',
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
            'X-Requested-With': 'XMLHttpRequest'
        },
        body: grabDate
    };

    // Make the fetch call
    fetch('countdown_date.php', fetchOptions)
        .then(response => {
            if (!response.ok) {
                throw new Error('Network response was not ok');
            }

            // If the response was ok, proceed to parse it as JSON
            return response.json();
        })
        .then(data => {
            console.log('data', data);

            document.getElementById("countdown_date").textContent = data.date_format;
            document.getElementById("display_title").textContent = data.title;

            let countdown_date = new Date(Date.parse(data.time_left));
            myClock(1, countdown_date);
        })
        .catch(error => {
            console.error('There has been a problem with your fetch operation:', error);
        });
}

fetchRoutine();

Here's the HTML

<!DOCTYPE html>

<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Countdown Clock</title>
        <link rel="stylesheet" href="reset.css">
        <link rel="stylesheet" href="countdown.css">
    </head>
    <body>

        <div class="info">
            <h1 id="display_title"></h1>
            <h2 id="countdown_date"></h2>
        </div>
        <div id="display_clock1">
            <figure class="box">
                <div class="day1"></div>
                <figcaption>Days</figcaption>
            </figure>
            <figure class="box">
                <div class="hour1"></div>
                <figcaption>Hours</figcaption>
            </figure>
            <figure class="box">
                <div class="minute1"></div>
                <figcaption>Minutes</figcaption>
            </figure>
            <figure class="box">
                <div class="second1"></div>
                <figcaption>Seconds</figcaption>
            </figure>
        </div>

        <script src="count_down.js"></script>

    </body>
</html>

and the css

*{
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
}

div.info {
    display: block;
    width: 100%;
    max-width: 300px;
    height: auto;
    text-align: center;
    padding: 2px;
    margin: 10px auto;
}

div.info::after { content: ''; display: block; clear: both; }

h1 {
    font-family: "Palatino Linotype", "Book Antiqua", Palatino, serif;
    font-size: 1.2em;
    line-height: 1.5;
}
h2 {
    font-family: Arial, Helvetica, sans-serif;
    font-size: 1.0em;
    font-style: italic;
    font-weight: 300;
}

div#display_clock1 {
    display: block;
    width: 100%;
    max-width: 190px;
    height: auto;
    margin: 5px auto;
    background-color: pink;
}
div#display_clock1 figure.box {
    float: left;
    display: block;
    width: 100%;
    max-width: 40px;
    height: 70px;
    color: #fff;
    text-align: center;
    padding: 0;
    margin-left: 5px;
}

div#display_clock1 figure.box div {
    background-color: #2e2e2e;
    height: 50px;
    line-height: 50px;
}

div#display_clock1 figure.box figcaption {
    font-family: Arial, Helvetica, sans-serif;

    font-size: 0.6em;
    line-height: 20px;
    font-weight: bold;
    color: #000;
}

it's an old script that I made changes to, so it used a little PHP

<?php
header('Content-type: application/json');
$endDate  = filter_input(INPUT_POST, 'myDate');
if ($endDate === 'endDate') {
    $count_down_date = new DateTime('2023-07-17 00:00:00', new DateTimeZone("America/Detroit"));
    $data['time_left'] = $count_down_date->format("Y/m/d H:i:s");
    $data['date_format'] = $count_down_date->format("l - F j, Y");
    $data['title'] = "Countdown to ";
    output($data);
}
function errorOutput($output, $code = 500) {
    http_response_code($code);
    echo json_encode($output);
}

/*
 * If everything validates OK then send success message to Fetch / JavaScript
 */

function output($output) {
    http_response_code(200);
    echo json_encode($output);
}

This could be done in JavaScript or even pulling from a Database Table. Like I said it's an old script that I modernized it a little.

Edited by Strider64
Link to comment
Share on other sites

@Strider64 Thank you very much, though I don't need the count down function. I already have one that grabs the date from the database and counts down. Thank you for sharing that though. 
The trouble I'm having is adding the time from $duration to the timestamp in $created_at

The reason I have this is because on the form to submit the auction, it has "How long do you want to run the auction" and you type X amount of minutes. That value goes to $duration
I figured out how to get it to add a certain amount of time each time, for example the following will add 10 min, and the countdown timer that I have will count down from 10 minutes
 

$date = date('Y-m-d H:i:s', strtotime('+10 minute'));

And then I put $date into the "created_at" column

And so far this works great.
Buuuutttttt... if I want to do an auction where I want it to run for 30 minutes, then I have to go in and change the file each time and reupload it. Which isn't an option when I have to use this auction several times in a 4 hour period.

I tried putting in $duration instead of +10 minute several times but that didn't work either
(btw in the column $duration, the value is "+30 min" or whatever amount of min I enter)

It puzzles me that this doesn't work

$date = date('Y-m-d H:i:s', strtotime('$duration'));

When the value says "+30 minute" in the database. Makes no sense to me at all

EDIT: This post is a follow up from the original to show how the date and time gets entered in the database because I gave up trying to do it with only just the first original post so I added this to the part that puts the info in the database.

Edited by PNewCode
Link to comment
Share on other sites

19 minutes ago, PNewCode said:

It puzzles me that this doesn't work

$date = date('Y-m-d H:i:s', strtotime('$duration'));

When the value says "+30 minute" in the database.

Because you put the $duration inside single quotes it is treating it as the string literal "$duration" and not "+30 minute".

EG

$duration = '+30 minute';

echo '$duration' . '<br>';
echo $duration . '<br>';

gives

$duration
+30 minute

 

Link to comment
Share on other sites

@Barand 

$date = date('Y-m-d H:i:s', strtotime($duration));

That works. NOW the next trick to make it all awesome and stuff is to make this send as if the value is "+30 minute" if only 30 is entered. I can do that easliy to add to the database, however it has to pass from the form to the php page so it gets picked up in the $_POST
 

<input type="text" name="duration" style="font-size:20pt;" required />



I tried to do an array like this but for the life of me I couldn't get it to work on the php page

<input type="hidden" name="duration[]" value="+" required />
<input type="text" name="duration[]" style="font-size:20pt;" required />
<input type="hidden" name="duration[]" value=" minute" required />

and also tried this but I couldn't figure out a way to have it all in one line in the post
 

<input type="hidden" name="duration2" value="+" required />
<input type="text" name="duration" style="font-size:20pt;" required />
<input type="hidden" name="duration3" value=" minute" required />

Because it HAS to pass in the very start of the php page in this line, in order for it to work for the time adjustment
 

$duration = mysqli_real_escape_string($conn, $_POST['duration']);

 

Right now I'm having to manually type +30 minute in the form field for all of this to work. It's rather annoying lol. Plus I see this being a problem if this gets ignored by users to type all that in. So.... trying to get it to work right.

Also... I still don't know how to make it so the time translates to different timezones but I'll worry about that after I get this first part solved.

SIDE NOTE: I just LOVE this site. I've learned so much. I'm absolutely addicted to creating new things for websites now :)
 

Edited by PNewCode
Link to comment
Share on other sites

  • Solution

Keep it simple for the user with datetime and time input fields

    <form method='POST'>
        <label for='start'>Auction Start</label>
        <input type='datetime-local' name='start' id='start'>
        <br>
        <label for='duration'>Duration</label>
        <input type='time' name='duration' id='duration'>
        <br><br>
        <input type='submit'>
    </form>

image.png.542c85f8c74a915ae0eb68311c87b2db.png

Store these values in your auction table

CREATE TABLE `auction` (                        +----+---------------------+----------+
  `id` int(11) NOT NULL AUTO_INCREMENT,         | id | start_time          | duration |
  `start_time` datetime DEFAULT NULL,           +----+---------------------+----------+
  `duration` time DEFAULT NULL,                 |  1 | 2023-07-17 15:00:00 | 02:30:00 |
  PRIMARY KEY (`id`)                            |  2 | 2023-07-18 12:00:00 | 03:00:00 |
) ENGINE=InnoDB;</body>                         +----+---------------------+----------+

When you want the auction end time for your countdown, query the database and use sql's addtime() function...

SELECT id
     , start_time as start
     , duration
     , addtime(start_time, duration) as finish
FROM auction;

+----+---------------------+----------+---------------------+
| id | start               | duration | finish              |
+----+---------------------+----------+---------------------+
|  1 | 2023-07-17 15:00:00 | 02:30:00 | 2023-07-17 17:30:00 |
|  2 | 2023-07-18 12:00:00 | 03:00:00 | 2023-07-18 15:00:00 |
+----+---------------------+----------+---------------------+

 

Link to comment
Share on other sites

1 minute ago, PNewCode said:

would I also add a column for "finish"?

No. Don't store derived data. If you have the start and duration then the finish is known . EG to find next, or current, auction

SELECT id
     , start_time as start
     , duration
     , addtime(start_time, duration) as finish
FROM auction
WHERE addtime(start_time, duration) > NOW()
order by start_time
LIMIT 1;

 

Link to comment
Share on other sites

@Barand You are quite amazing! I hope you know that!!! This simplified everything and works beautifully. Now I have to find a way to have the page that shows the timer, adjust to the viewers timezone so the counts down accurately.
I just entered a test auction for 11 hours, my friend in Sweden shows 5 hours remaining. BUT this will give me something to do today haha.
Thank you so much for your help!!!

Link to comment
Share on other sites

@Barand and others that see this. I don't know if I should make a new topic or not since I picked a solution, and I am worried that I may be an annoyance with all of my questions. But here I am on day 5 of this project and I can't get this last part resolved.

Here is what I have, Thanks to you!

1: User creates an auction
2: The auction accepts or declines the offer based on if it's higher or lower than the highest bid
3: When it ends, a new screen appears showing it's ended and if the logged in user is the winner then they also see a button to pay for the auction via paypal
4: I have an edit auction page where I can adjust the time, image, name, etc

Where I am stuck now is getting this timer to work for viewers in different time zones. It will be accurate in the time the user posted it, but not for others. 
For example, if I creat an auction to run for 10 hours, then it will show users in my time zone 10 hours remaining. However if someone in London views it then they see 5 hours remaining. This will cause the auction end to not be the same for everyone.

I really do appreciate all the help, and again I've learned so much. This last peice of the puzzle has me stumped.
HERE IS WHAT I'VE TRIED and what I think MIGHT work but haven't been able to get it right...

In the JS countdown, I've tried adding UTC comments to the NEW TIME in various places and also added the months in the brackets.
I've tried to create a part in the php section to convert it then use it (which I think may be the best approach but I can't figure it out)

Finally, everything I see in my searches shows example of how to convert it if you put in a specific time zone (like if I manually put in America/Denver for example) but nothing that shows universal for everyone. Also, I can't seem to find a clear answer on if my timestamps are even being stored as UTC or not lol

Here is what I have so for this now, all of this works perfect except for the timezone issue. THANK YOU SO MUCH!
 

<?php


error_reporting(E_ALL);
ini_set('display_errors', '1');


$mysqli = new mysqli("deleted for posting","deleted for posting","deleted for posting","deleted for posting");

if ($mysqli -> connect_errno) {
  echo "Failed to connect to MySQL: " . $mysqli -> connect_error;
  exit();
}

$sql = "SELECT * FROM auctiontitle";


if ($result = $mysqli -> query($sql)) {
  while($row = $result->fetch_assoc()) {



 $duration =  $row["duration"];
 $created_at =  $row["created_at"];
 $date =  "$created_at";





  
  }
} else {
  echo "0 results";
}



?> 

                        <div id="data" align="center"></div>
                        <input type="hidden" id="date" value="<?php echo $date; ?>">

<script>
    function func() {
        var dateValue = document.getElementById("date").value;
 
        var date = Math.abs((new Date().getTime() / 1000).toFixed(0));
        var date2 = Math.abs((new Date(dateValue).getTime() / 1000).toFixed(0));
 
        var diff = date2 - date;
 
        var days = Math.floor(diff / 86400);
        var hours = Math.floor(diff / 3600) % 24;
        var minutes = Math.floor(diff / 60) % 60;
        var seconds = diff % 60;
 
        var daysStr = days;
        if (days < 10) {
            daysStr = "0" + days;
        }
  
        var hoursStr = hours;
        if (hours < 10) {
            hoursStr = "0" + hours;
        }
  
        var minutesStr = minutes;
        if (minutes < 10) {
            minutesStr = "0" + minutes;
        }
  
        var secondsStr = seconds;
        if (seconds < 10) {
            secondsStr = "0" + seconds;
        }
 
        if (days < 0 && hours < 0 && minutes < 0 && seconds < 0) {
            window.location.href = "auction-ended.php","_blank";
            daysStr = "00";
            hoursStr = "00";
            minutesStr = "00";
            secondsStr = "00";
 
            console.log("close");
            if (typeof interval !== "undefined") {
                clearInterval(interval);
            }
        }
 
        document.getElementById("data").innerHTML = hoursStr + " Hours   " + minutesStr + " Minutes   " + secondsStr + " Seconds";
    }
 
    func();
    var interval = setInterval(func, 1000);
</script>


EDIT: This is what I'm thinking could work, but not sure how. Something like...
 

///// in the php section /////

$created_at =  $row["created_at"];
$created_at = (something here that converts the time to the viewers timezone);
$date = $created_at

///// then that could reflect the $date in the js countdown /////

 

Edited by PNewCode
Link to comment
Share on other sites

@Barand and others.... I DID IT YAY!
Below is the solution (in case anyone else can learn from this too)

I just changed the JS a bit and added a line to reflect the local time I had that adjusted

 

        var dateValue = document.getElementById("date").value;
 
        var dateValue2 = new Date().toLocaleString('en-US', { timeZone: 'America/New_York' });

        var date = Math.abs((new Date(dateValue2).getTime() / 1000).toFixed(0));
        var date2 = Math.abs((new Date(dateValue).getTime() / 1000).toFixed(0));


 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.