Jonathan
Jonathan

Reputation: 16349

How to the get the beginning of day of a date in javascript -- factoring in timezone

I am struggling to find out the beginning of day factoring in timezones in javascript. Consider the following:

   var raw_time = new Date(this.created_at);
   var offset_time = new Date(raw_hour.getTime() + time_zone_offset_in_ms);

   // This resets timezone to server timezone
   var offset_day = new Date(offset_time.setHours(0,0,0,0))
   // always returns 2011-12-08 05:00:00 UTC, no matter what the offset was!

   // This has the same issue:
   var another_approach_offset_day = new Date(offset_time.getFullYear(),offset_time.getMonth(),offset_time.getHours())

I expect when i pass a Pacific Timezone offset, to get: 2011-12-08 08:00:00 UTC and so on.

What is the correct way to achieve this?

I think that part of the issue is that setHours method sets the hour (from 0 to 23), according to local time.

Also note that I am using javascript embedded in mongo, so I am unable to use any additional libraries.

Thanks!


Jeez, so this was really hard for me, but here is the final solution that I came up with the following solution. The trick was I need to use setHours or SetUTCHours to get the beginning of a day -- the only choices I have are system time and UTC. So I get the beginning of a UTC day, then add back the offset!

// Goal is given a time and a timezone, find the beginning of day
function(timestamp,selected_timezone_offset) {
  var raw_time = new Date(timestamp)
  var offset_time = new Date(raw_time.getTime() + selected_timezone_offset);
  offset_time.setUTCHours(0,0,0,0);
  var beginning_of_day = new Date(offset_time.getTime() - selected_timezone_offset);
  return beginning_of_day;
}

Upvotes: 1

Views: 5299

Answers (5)

Weihang Jian
Weihang Jian

Reputation: 8755

You can make use of Intl.DateTimeFormat. This is also how luxon handles timezones.

The code below can convert any date with any timezone to its beginging/end of the time.

const beginingOfDay = (options = {}) => {
  const { date = new Date(), timeZone } = options;
  const parts = Intl.DateTimeFormat("en-US", {
    timeZone,
    hourCycle: "h23",
    hour: "numeric",
    minute: "numeric",
    second: "numeric",
  }).formatToParts(date);
  const hour = parseInt(parts.find((i) => i.type === "hour").value);
  const minute = parseInt(parts.find((i) => i.type === "minute").value);
  const second = parseInt(parts.find((i) => i.type === "second").value);
  return new Date(
    1000 *
      Math.floor(
        (date - hour * 3600000 - minute * 60000 - second * 1000) / 1000
      )
  );
};

const endOfDay = (...args) =>
  new Date(beginingOfDay(...args).getTime() + 86399999);

const beginingOfYear = () => {};

console.log(beginingOfDay({ timeZone: "GMT" }));
console.log(endOfDay({ timeZone: "GMT" }));
console.log(beginingOfDay({ timeZone: "Asia/Tokyo" }));
console.log(endOfDay({ timeZone: "Asia/Tokyo" }));

Upvotes: 0

David
David

Reputation: 727

var aDate = new Date();
var startOfTheDay = new Date(aDate.getTime() - aDate.getTime() % 86400000)

Will create the beginning of the day, of the day in question

Upvotes: 0

Guido Bouman
Guido Bouman

Reputation: 3275

If you know the date from a different date string you can do the following:

var currentDate = new Date(this.$picker.data('date'));
var today = new Date();
today.setHours(0, -currentDate.getTimezoneOffset(), 0, 0);

(based on the codebase for a project I did)

Upvotes: 0

gilly3
gilly3

Reputation: 91527

In JavaScript all dates are stored as UTC. That is, the serial number returned by date.valueOf() is the number of milliseconds since 1970-01-01 00:00:00 UTC. But, when you examine a date via .toString() or .getHours(), etc., you get the value in local time. That is, the local time of the system running the script. You can get the value in UTC with methods like .toUTCString() or .getUTCHours(), etc.

So, you can't get a date in an arbitrary timezone, it's all UTC (or local). But, of course, you can get a string representation of a date in whatever timezone you like if you know the UTC offset. The easiest way would be to subtract the UTC offset from the date and call .getUTCHours() or .toUTCString() or whatever you need:

var d = new Date();
d.setMinutes(d.getMinutes() - 480); // get pacific standard time
d.toUTCString(); // returns "Fri, 9 Dec 2011 12:56:53 UTC"

Of course, you'll need to ignore that "UTC" at the end if you use .toUTCString(). You could just go:

d.toUTCString().replace(/UTC$/, "PST");

Edit: Don't worry about when timezones overlap date boundaries. If you pass setHours() a negative number, it will subtract those hours from midnight yesterday. Eg:

var d = new Date(2011, 11, 10, 15); // d represents Dec 10, 2011 at 3pm local time
d.setHours(-1);                     // d represents Dec 9, 2011 at 11pm local time
d.setHours(-24);                    // d represents Dec 8, 2011 at 12am local time
d.setHours(52);                     // d represents Dec 10, 2011 at 4am local time

Upvotes: 5

Dexygen
Dexygen

Reputation: 12561

Where does the time_zone_offset_in_ms variable you use come from? Perhaps it is unreliable, and you should be using Date's getTimezoneOffset() method. There is an example at the following URL:

http://www.w3schools.com/jsref/jsref_getTimezoneOffset.asp

Upvotes: 0

Related Questions