Set date() to midnight in users timezone with moment.js - javascript

I use moment.js to display a UTC date in the users local timezone:
var date = new Date(Date.UTC(2016,03,30,0,0,0));
var now = new Date();
var diff = (date.getTime()/1000) - (now.getTime()/1000);
var textnode = document.createTextNode(moment(date).format('dddd, DD.MM.YYYY') + ' a las ' + moment(date).format('HH:mm A'));
document.getElementsByClassName("date")[0].appendChild(textnode.cloneNode(true));
I later use the diff variable to show a countdown timer.
I would like to show a different countdown timer to everyone in their local time zone. (Using the difference till its midnight in their time zone, not in UTC)
But I am struggeling to get it work. Instead of using var date = new Date(Date.UTC(2016,03,30,0,0,0)); I probably need to use some function of moment.js that gives me till midnight in the users time zone.
The best example would be new years eve. If I use UTC everyone would have the same counter (9 hours left) but in different parts of the world this wouldn't make sense. For someone in australia it should be 2 hours left, and for someone in the US 14 hours.

I'm not sure that I fully understand your question, but I'll give you some general advice and tips.
When using moment.js, there is very little need to ever use the Date object. Only use it for interacting with other APIs that expect a Date object.
To get a moment in UTC, just use moment.utc(...), passing the appropriate arguments, such as moment.utc([2016,3,30]) or moment.utc('2016-04-30') for midnight April 30th UTC.
If you want to convert that back to the user's local time, use the .local() function. For example, moment.utc('2016-04-30').local() will create a moment with the equivalent local time to the UTC time provided.
If you want a moment in the user's local time, then that would be moment(...), such as moment([2016,3,30]) or moment('2016-04-30') for midnight April 30th local time.
You can difference two moments using the diff function, which can give the answer in specific units, such as m1.diff(m2, 'seconds') where m1 and m2 are moment objects.
You don't need to call format twice. Just encapsulate any text you want outputed with square brackets. .format('dddd, DD.MM.YYYY [a las] HH:mm A')
You might look into moment's locale support. If I'm not mistaken, "a las" indicates Spanish, however it's not always "a las", but sometimes "a la", if the hour is 1. Also, moment only uses those words in its .calendar() function, such as when producing a phrase like "mañana a las 13:17". A regular date formatted with .format('LLLL') in the Spanish locale would be something like: "sábado, 19 de marzo de 2016 13:17". So, you might want to verify that "a las" is exactly what you want in every case.
The title to this question was how to set a date to midnight. For that, I recommend using moment's startOf function. m.startOf('day') will give set the moment m to the start of the day, which is usually midnight. Keep in mind that not every local day actually starts at midnight in every time zone. Due to anomalies like daylight saving time, some days might start at 1:00. For example, this occurs in Brazil on October 16th this year.
Also, if you created the moment in UTC mode, you may wish to convert it back to local mode first before setting it to the start of the day. If you don't want to change the original moment object, be sure to clone it first.
Putting this all together:
var m1 = moment.utc([2016,3,30]);
var m2 = m1.clone().local().startOf('day');
var now = moment();
var diff = m1.diff(now, 'seconds');

Related

Timezone independent dates javascript

Using javascript/react native + redux i need to save timestamps in a time format that is aware of local time when saving the date, but unaware when reading the same date in another timezone.
Take a hypothetical user that travels west around the world in one day, saving a time stamp every hour, all i different timezones, all at 2021-01-30 at 18:00 hours local time. Resulting in 24 timestamps at 18:00.
Using a function in the likes of isWithinInterval from date-fns in a similar fashion as below, all timestamps should return true.
isWithinInterval(
timestamp,
{start: new Date(2021,0,30,17,30}, end: new Date(2021,0,30,18,30)},
) // -> true
How do one go about doing this? Preferrably in a react-redux compatiable (serializable) way. By default, your date object will be saved in UTC based on the local time on your device.
I had such a hard time to wrap my head around the date objects that it took a long time for me to understand that this problem is actually what "date-fns-tz" package is all about. This is how i'm currently solving it:
Create a utc-time identical to the local time
using:
import {zonedTimeToUtc} from "date-fns-tz"
const myDate = new Date() // eg 2021-02-03 10:00 UTC +5
const localTimeIdenticalUtc = zonedTimeToUtc(localDateObject, localTimeZone) // 2021-02-03 10:00 UTC +-0
When i want to use the UTC-date, i transfer it back to an identical localDate for whatever time zone i am in.
import {utcToZonedTime } from "date-fns-tz"
const zonedTimeToUtc(localTimeIdenticalUtc, localTimeZone) // 2021-02-03 10:00 UTC +5

Using moment.utc() incorrectly converting the date into utc format of "days" format-Moment Javascript

I'm using moment library to convert date into a utc format. here is my date string:
var dateString = "2019-01-31T11:33:16.952+0000";
new Date("2019-01-31T11:33:16.952+0000") // o/p: Thu Jan 31 2019 03:33:16 GMT-0800 (Pacific Standard Time)
since this date is less than a week from today's date, I'm trying to display a text saying "n days ago" instead of actual date. But for some reason I'm getting a future date displayed as "6 days ago" when I do this:
moment.utc("2019-01-31T11:33:16.952+0000").local().fromNow() // shouldnt this display "5 days ago"??
Not sure why moment is not converting the date correctly, any ideas what could be wrong here?
I guess(Considering use of local() converts to your local timezone so time is deducted because you might be in -ve TimeZone) this answer is a solution you're expecting:
Ideally, you would want to pass a UTC timestamp from your server to
the client. That doesn't mean you have to switch your whole server
over to UTC, it just means that you would convert from the time in
your database to UTC on the server before sending it over the web.
Sure, it would be even better if you actually stored times in UTC, but
you said you aren't in a position to make that sort of change right
now. But let's just work off the assumption that you can't change
anything at all on the server.
We'll also assume that your server is fixed to the UTC-07:00 offset.
In real life, this would only be true for places like Arizona that
don't follow daylight saving time. So if you are in Los Angeles and
are in Pacific Time, then some of your data is based on UTC-07:00, but
some of it is based on UTC-08:00. That requires a lot more work if you
want to do it in JavaScript.
Let's also assume that the input is already a string in ISO8601
format. (If it's not, then let me know and I will adjust this code.)
var s = "2013-09-11 18:00:00"; // from action.timeStamp
var actionTime = moment(s + "-07:00", "YYYY-MM-DD HH:mm:ssZ");
var timeAgo = actionTime.fromNow(); The reason your other code didn't
work is because in the first line, you are affected by the time zone
of the browser. The zone setter in the second line just changes the
zone for formatting, not changing the actual moment in time.
Also, when you dump a moment to the console for debugging, make sure
you format it for output. Otherwise you are just looking at its
internal property values, which may or may not make sense directly.

Want to get Timezone using jquery

In jquery,
var date = new Date();
It is taking system Date Not site Time zone
var date = (new Date()).getTimezoneOffset();
it is also not working.please anyone help for this.thank you.
Return the timezone difference between UTC and Local Time:
var d = new Date()
var n = d.getTimezoneOffset();
The result n will be:
-300
The getTimezoneOffset() method returns the time difference between UTC time and local time, in minutes.
For example, If your time zone is GMT+2, -120 will be returned.
Note: The returned value is not a constant, because of the practice of using Daylight Saving Time.
Tip: The Universal Coordinated Time (UTC) is the time set by the World Time Standard.
Note: UTC time is the same as GMT time.
jQuery has only one date/time function, which is $.now()
If you meant JavaScript, the answer is still no. You can only obtain a time zone offset from date.getTimezoneOffset(). You can't get a time zone - at least not in all browsers.
You can guess at the time zone, by using the jsTimeZoneDetect library, but it is just a guess. It may or may not be accurate.
If you can guarantee your users are running a browser that supports the brand new ECMAScript Internationalization API, you can get the user's time zone with:
Intl.DateTimeFormat().resolvedOptions().timeZone

Date ranges with DST in javascript

I'm looking for best practices regarding dates - where it's the date itself that's important rather than a particular time on that day.
An excellent start was this question:
Daylight saving time and time zone best practices
I'd like some guidance applying this for my situation. I have medications starting on a particular date, and ending on another. I then need to query medications which are active in a given date range.
I've tried setting start and end dates as midnight local time, then storing in UTC on the database. I could add timezone entries too.
I'm using moment.js on both client and server, and can use moment timezone if needed.
I'm wondering how to deal with the effect of DST on my times - which makes an hour difference in my locally-midnight UTC times between DST and non DST periods.
The problem I have is for example when some medications have end dates set during a DST period, and some which were set in a non-DST period. Then, their UTC times differ by an hour. When a query is made for a particular date range starting at local midnight, it's not accurate as there are two different representations of midnight. The query itself may treat midnight as one of two different times, depending on when in the year the query is made.
The end result is that a medication may appear to end a day later than it should, or start a day earlier.
A simple but wonky workaround would be to consistently set the start date as 1am in standard (non DST) time, and end dates as 11:59pm standard (non DST) time, and query at midnight.
Or, should I check the start and end dates of each query, and work out what the UTC offset would be for each date?
But I'd much prefer to know what best practice is in this situation. Thanks.
Both the JavaScript Date object and the moment object in moment.js are for representing a specific instant in time. In other words, a date and a time. They internally track time by counting the number of milliseconds that have elapsed since the Unix Epoch (Midnight, Jan 1st 1970 UTC) - ignoring leap seconds.
That means, fundamentally, they are not the best way to work with whole calendar dates. When you have only a date, and you use a date+time value to track it, then you are arbitrarily assigning a time of day to represent the entire day. Usually, this is midnight - but as you pointed out, that leads to problems with daylight saving time.
Consider that in some parts of the world (such as Brazil) the transition occurs right at midnight - that is, in the spring, the clocks jump from 11:59:59 to 01:00:00. If you specify midnight on that date, the browser will either jump forward or jump backward (depending on which browser you are using)!
And if you convert a local date-at-midnight to a different time zone (such as UTC), you could change the date itself! If you must use a date+time to store a date-only value, use noon instead of midnight. This will mitigate most (but not all) of the adjustment issues.
The better idea is to treat whole dates as whole dates. Don't assign them a time, and don't try to adjust them to UTC. Don't use a Date or a moment. Instead, store them either as an ISO-8601 formatted string like "2014-11-25", or if you need to do math on them, consider storing them as an integer number of whole days since some starting value. For example, using the same Jan 1st 1970 epoch date, we can represent November 11th 2014 as 16399 with the following JavaScript:
function dateToValue(year, month, day) {
return Date.UTC(year, month-1, day) / 86400000;
}
function valueToDate(value) {
var d = new Date(86400000 * value);
return { year : d.getUTCFullYear(),
month : d.getUTCMonth() + 1,
day : d.getUTCDate()
};
}
There are a few other things to keep in mind when working with whole dates:
When working with ranges of whole dates, humans tend to use fully-inclusive intervals. For example, Jan 1st to Jan 2nd would be two days. This is different from date+time (and time-only) ranges, in which humans tend to use half-open intervals. For example, 1:00 to 2:00 would be one hour.
Due to time zones, everyone's concept of "today" is different around the globe. We usually define "today" by our own local time zone. So normally:
var d = new Date();
var today = { year : d.getFullYear(),
month : d.getMonth() + 1,
day : d.getDate()
};
You usually don't want to shift this to UTC or another time zone, unless your business operates globally under that time zone. This is rare, but it does occur. (Example, StackOverflow uses UTC days for its calculations of badges and other achievements.)
I hope this gets you started. You asked a fairly broad question, so I tried to answer in way that would address the primary concerns. If you have something more specific, please update your question and I'll try to respond.
If you would like even more information on this subject, I encourage you to watch my Pluralsight course, Date and Time Fundamentals.

Set JavaScript countdown to end at midnight PST?

I am trying to get a countdown to end Monday # midnight PST. I thought I had it working a week ago but apparently not.
I am using date.js
var monday = Date.today().next().monday();
var UTCmonday = new Date(monday.getTime() + monday.getTimezoneOffset() * 60000);
var PSTmonday = new Date(UTCmonday.setHours(UTCmonday.getHours() + 9));
$('#defaultCountdown').countdown({until: UTCmonday});
I think the problem is in determining UTC time? Am I right? How do I work this out?
Assuming you Pacific Standard Time, then you need to remember that PST === UTC-8
Thus, your third line would be
var PSTmonday = new Date(UTCmonday.setHours(UTCmonday.getHours() - 8));
The problem with this is that this will fail if the UTC is any earlier than 8am, since you can't pass a negative number into setHours.
Since you're using Datejs, why not use its full capabilities for changing the timezone?
http://code.google.com/p/datejs/wiki/APIDocumentation#setTimezone
Getting the time strictly in PST doesn't make much sense, as for almost half of the year PST isn't observed in the Pacific time zone. PST (UTC-8) is observed in the winter, and PDT (UTC-7) is observed in the summer. You can't represent Pacific Time as just a fixed offset, and unless it happens to be your own local time zone, you can't easily determine the transition between them without a time zone database. See the timezone tag wiki.
Also, date.js has been abandoned. I can't recommend any solution that continues its use. Support for the setTimezone method that Dancrumb suggested is culture specific, and it still doesn't take daylight saving time into consideration.
Instead, I recommend trying moment.js. You can use the moment-timezone add-on to work with the America/Los_Angeles zone - which is a good exemplar of US Pacific time. Make sure your moment-timezone-data.js file includes at least this zone. Then you can do the following:
var m = moment().tz('America/Los_Angeles').day(7).startOf('day');
var s = m.toISOString(); // if you need a string output representing UTC
var dt = m.toDate(); // if you need an actual JavaScript Date object
Let's break that down a bit:
moment() gets you the current time
tz('America/Los_Angeles') adjusts the time to the timezone you are interested in.
day(7) advances the time to the next Monday.
startOf('day') snaps the time back to midnight.

Categories

Resources