daGUY
daGUY

Reputation: 28773

Round a timestamp to the nearest date

I need to group a bunch of items in my web app by date created.

Each item has an exact timestamp, e.g. 1417628530199. I'm using Moment.js and its "time from now" feature to convert these raw timestamps into nice readable dates, e.g. 2 Days Ago. I then want to use the readable date as a header for a group of items created on the same date.

The problem is that the raw timestamps are too specific - two items that are created on the same date but a minute apart will each have a unique timestamp. So I get a header for 2 Days Ago with the first item underneath, then another header for 2 Days Ago with the second item underneath, etc.

What's the best way to round the raw timestamps to the nearest date, so that any items created on the same date will have the exact same timestamp and thus can be grouped together?

Upvotes: 23

Views: 33964

Answers (9)

rmja
rmja

Reputation: 34

Here is a way to get the nearest date for any time:

const time = new Date();
const date = new Date(new Date(time.setHours(time.getHours() + 12)).setHours(0, 0, 0, 0));

The idea is as follows:

  • Add 12 hours to the time
  • Round down to nearest date by removing the time component. By adding the 12 hours before we round down, we ensure that we effectively round to the nearest date.

Examples:

const time = new Date(2023, 10, 07, 11, 00, 00) // => date = new Date(2023, 10, 07)
const time = new Date(2023, 10, 07, 13, 00, 00) // => date = new Date(2023, 10, 08)

Upvotes: 0

OKEE
OKEE

Reputation: 460

I find very simple and intuitive solution to be:

const d = new Date(Math.floor(Date.now() / 86400000) * 86400000);
// 86400000 = 24 * 60 * 60 * 1000

Also if you wish to round to other values, for example to whole hours, you can easily expand the mentioned solution to:

const d = new Date(Math.floor(Date.now() / 3600000) * 3600000);
// 3600000 = 60 * 60 * 1000

Upvotes: 0

juvian
juvian

Reputation: 16068

Well, using js you can do:

var d = new Date(1417628530199);
d.setHours(0);
d.setMinutes(0);
d.setSeconds(0);
d.setMilliseconds(0);

A shorter way of writing it is d.setHours(0, 0, 0, 0);

Upvotes: 39

Matt Budish
Matt Budish

Reputation: 136

Here is a clean way to get just the date in one line with no dependencies:

let d = new Date().setHours(0, 0, 0, 0);

Upvotes: 12

Travis J
Travis J

Reputation: 82297

Just construct a new Date from the existing one using only the year, month, and date. Add half a day to ensure that it is the closest date.

var offset = new Date(Date.now() +43200000);
var rounded = new Date(offset .getFullYear(),offset .getMonth(),offset .getDate());
console.log(new Date());
console.log(rounded);

Since this seems to have a small footprint, it can also be useful to extend the prototype to include it in the Date "class".

Date.prototype.round = function(){
    var dateObj = new Date(+this+43200000);
    return new Date(dateObj.getFullYear(), dateObj.getMonth(), dateObj.getDate());
};
console.log(new Date().round());

Minimized:

Date.prototype.round = function(){var d = new Date(+this+43200000);return new Date(d.getFullYear(), d.getMonth(), d.getDate());};

Upvotes: 5

thomasttvo
thomasttvo

Reputation: 33

function getDateOfTimeStamp(time) {
  var originTime = 0;
  var offsetOriginTime = originTime + new Date().getTimezoneOffset() * 60 * 1000;
  var timeSinceOrigin = time - offsetOriginTime;
  var timeModulo = timeSinceOrigin % (24 * 60 * 60 * 1000);
  var normalizedTime = time - timeModulo;

  console.log(new Date(normalizedTime) ,new Date(time));
  return normalizedTime;
}

This worked for my project. Pure math, no string manipulation needed, no external lib needed, so it's super fast.

You can try by copying the above function to javascript console and then do normalizeTimeToDate(Date.now())

Upvotes: 0

norep
norep

Reputation: 131

function roundDownDate(date) {
  if (typeof date !== "object" || !date.getUTCMilliseconds) {
      throw Error("Arg must be a Date object.");
  }
  var offsetMs = date.getTimezoneOffset() * 60 * 1000,
      oneDayMs = 24 * 60 * 60 * 1000;
  return new Date(Math.floor((date.getTime() - offsetMs) / oneDayMs) * oneDayMs + offsetMs);
};

This should work and is pretty fast.

Upvotes: 1

Joe L.
Joe L.

Reputation: 4643

Try this:

Date.prototype.formatDate = function() {
   var yyyy = this.getFullYear().toString();
   var mm = (this.getMonth()+1).toString();
   var dd  = this.getDate().toString();
   return yyyy + (mm[1]?mm:"0"+mm[0]) + (dd[1]?dd:"0"+dd[0]);
  };

var utcSeconds = 1417903843000,
    d = new Date(0);

d.setUTCSeconds(Math.round( utcSeconds / 1000.0));

var myTime = (function(){
        var theTime = moment(d.formatDate(), 'YYYYMMDD').startOf('day').fromNow();
        if(theTime.match('hours ago')){
            return 'Today';
        }
        return theTime;
    })();

alert( myTime );

http://jsfiddle.net/cdn5rvck/4/

Upvotes: 2

Topher Fangio
Topher Fangio

Reputation: 20677

Using Moment.js, you can use the following code to round everything to the beginning of the day:

moment().startOf('day').toString();
// -> Prints out "Fri Dec 05 2014 00:00:00 GMT-0800"

You can read more about startOf() in the docs.

Upvotes: 14

Related Questions