How can I set the Unix epoch of a moment js object? - javascript

I have a moment.js object whose Unix epoch value I'd like to change.
Normally I'd use myMoment = moment(someEpoch);, but because of design constraints I'm having to pass the object by reference, so I must mutate the value rather than replacing it altogether.
What is the neatest and (ideally) most performant way to do this in v2.15+?

Assuming m is a moment object, and t is the timestamp to set (in ms), probably the easiest way is:
m.add(t-m);
Or if you prefer to be more verbose:
m.add(t - m.valueOf(), 'ms');
Note that the default units are milliseconds when not specified and the input is numeric. If your input timestamp is in whole seconds, you'd have to multiply it by 1000 in either of the above formulas before subtracting the value of m.
However, if you're really after the most efficient code in terms of minimizing total operations performed internally, you could modify moment internals directly. Doing so is dangerous in that there's no guarantee the internals won't change between versions. Only the public API compatibility is guaranteed, following SemVer rules. So only do this if you are optimizing for perf and are willing to deal with potentially breaking changes in the future:
m._d.setTime(t + ((m._offset || 0) * 60000));
This is essentially an inversion of moment's valueOf function, and is probably what the implementation would look like if it were built in to moment.
Of course, if you are only working with moments in UTC mode, you can just do:
m._d.setTime(t);
One last thing, with regard to terminology, you can't actually set "the Unix epoch value", because the epoch is a fixed value. In this context, "epoch" means the timestamp that is zero, which is associated with 1970-01-01T00:00:00.000Z. It cannot be changed. You are simply using a "Unix Timestamp in milliseconds", or perhaps an "epoch-based timestamp". But it is a misnomer for your variable to be named someEpoch.

moment.js has a method to do that:
moment.unix(Number)
http://momentjs.com/docs/#/parsing/unix-timestamp/

Related

Get JavaScript local date from Moment JS

Consider the code :
let now = moment();
console.log(now.format()); // 2019-11-25T20:23:50+02:00
console.log(now.toDate()); // 2019-11-25T18:23:50.916Z
This is the output on my local machine , and when I check the app on Heroku
it gives the same values , even though I changed the TZ like this :
heroku config:add TZ="Asia/Jerusalem"
How can I get a JavaScript Date (Not a String !) object of my localtime , meaning 2019-11-25T20:23:50 ?
Let's walk through your code example:
let now = moment();
You create a Moment object. You don't pass any parameters, so it is initialized using the current timestamp (as if you called Date.now()) and set to "local mode".
console.log(now.format()); // 2019-11-25T20:23:50+02:00
By calling format, you ask the Moment object to produce a String. Since it's in local mode, the offset that applies to that moment in time for the local time zone is emitted in the result, and the wall time shown in the result is adjusted for that offset. In this case, the local time is two hours ahead of UTC. You then pass that string to console.log, which emits it to the console.
console.log(now.toDate()); // 2019-11-25T18:23:50.916Z
By calling toDate, you ask the Moment object to create a Date object. The "mode" of the moment object is no longer relevant because Date objects don't track anything other than a timestamp. Thus, the timestamp within the Moment object becomes the timestamp for the resulting Date object. Since you derived the Moment object from the current time, the result is the same as if you just called new Date() to begin with.
You then pass the string to console.log - except one can't just log an object, so it first has to convert it to something so you can see it. Here's the interesting part: There is no spec for this behavior. Implementations of ECMAScript can do whatever they like in this regard. Some implementations, like in your example, will call .toISOString() and log the result. Since .toISOString() displays the result in UTC, the result of logging a Date object is also shown in UTC. But other implementations will call .toString() on the Date object and log that, the result being in local time. It's entirely possible some future implementation could show the result in some graphical or interactive output. The point being, you can't rely on the behavior of console.log(Date) to be consistent.
No amount of changing your time zone settings will change this result. The Date object is inherently UTC-based, your output is also UTC-based, and UTC is the same over the whole planet (by design).
If you want the time zone reflected in the string output, you must use a function that produces a string with respect to local time. As you showed, you'll get that with .format() on a Moment object in local mode. You can also get one from calling .toString() on a Date object (but the resulting string is not in the same ISO 8601 format).
i would try,
moment().local().toDate()
but if you are planning to save date into db it's good practice to save time in UTC format for easier global conversion.
If you want to work timezones you may require also moment timezone package - https://momentjs.com/timezone/docs/
npm install moment-timezone
Hope this helps :)

Creating and comparing dates inside CosmosDB stored procedures

There is limited guidance for CosmosDB stored procedures and their handling of new Date() and the comparison of dates.
The following code is a CosmosDB stored procedure to 'freeze' the writing of documents after a given time. The property currentDoc.FreezeDate is in ISO-8601 format, e.g. '2017-11-15T13:34:04Z'.
Note: this is an example of the situation I'm trying to understand. It is not production code.
function tryUpdate(newDoc) {
__.queryDocuments(
__.getSelfLink(),
{ /* query to fetch the document */ },
(error, results) => {
var currentDoc = results[0]; // doc from the database
// fail if the document is still locked
if (new Date(currentDoc.FreezeDate) < new Date()) {
getContext().getResponse().setBody({ success: false });
return;
}
// else update the document
/* snip */
}
);
}
My question is: within CosmosDB stored procedures, is new Date() affected by timezones, especially given that the database may be in a different region than the invoking code? Is the date comparison code here valid in all situations?
As far as I can see, CosmosDB is storing DateTime values without the corresponding Timezone, aka. not as DateTimeOffset. This means it should not matter where the code is executed, since it is always normalized to something like this:
"2014-09-15T23:14:25.7251173Z"
Javascript Date object are timestamps - they merely contain a number of milliseconds since the epoch. There is no timezone info in a Date object. Which calendar date (day, minutes, seconds) this timestamp represents is a matter of the interpretation (one of to...String methods).
(taken from Parse date without timezone javascript)
In other words, no matter where you are in the world, new Date() will always have the same value internally.
If you want to remove uncertainty in exchange for readability, I would recommend only storing the seconds or milliseconds since the epoch (Unix Time). This is also what is used internally by date (new Date().value - milliseconds). Incidentally, the internal cosmos document field _ts is also a timestamp in epoch format.
Be aware that the value of new Date() might by off the 'correct global time` by a couple of minutes - I don't know if Azure/Cosmos guarantees a certain deviation window.

new Date(epoch) returning invalid date inside Ember component

I have a date-filter component that I am using in my Ember application that only works on initial render, not on a page reload, or even if I save a file (which triggers the application to live update).
In the main template of my application, I render the date-filter like this passing it a unix timestamp
{{date-filter unixepoch=item.date}}
Then, in components/date-filter.js, I use a computed property called timeConverter to change the unix epoch into a time string formatted according to user's language of choice, and then in my templates/components/date-filter.hbs file I do {{timeConverter}} to display the results
timeConverter: function(){
//step 1: get the epoch I passed in to the component
var epoch = this.get('unixepoch');
//step 2: create a human readable date string such as `Jun 29, 2015, 12:36PM`
var datestring = new Date(epoch)
//do language formatting --code omitted as the problem is with step2
}
It is step 2 that fails (returning invalid date) if I refresh the page or even save the file. It always returns the proper date string the first time this component is called. Even if I do new Date(epoch) in the parent component, and try to pass the result in to this component (to do foreign language formatting), I'm having the same problem.
Question: how can I figure out what's happening inside new Date(epoch), or whether it's an issue related to the component?
I suspect your epoch value is a string (of all digits). If so, then
var datestring = new Date(+epoch);
// Note ------------------^
...will fix it by converting it to a number (+ is just one way to do it, this answer lists your options and their pros/cons). Note that JavaScript uses the newer "milliseconds since The Epoch" rather than the older (original) "seconds since The Epoch." So if doing this starts giving you dates, but they're much further back in time than you were expecting, you might want epoch * 1000 to convert seconds to milliseconds.
If it's a string that isn't all digits, it's not an epoch value at all. The only string value that the specification requires new Date to understand is the one described in the spec here (although all major JavaScript engines also understand the undocumented format using / [not -] in U.S. date order [regardless of locale]: mm/dd/yyyy — don't use it, use the standard one).

Javascript timestamp number is not unique

I need a unique number to be generated to be used in my code.I use
var id = new Date().valueOf()
I know the above returns the number of milliseconds.
But the values are not unique.For example :1385035174752.This number is generated twice or more than that.
My question is Why is it not unique? and how do i get unique number from current date/time?
If you need uniqueness, use Math.random(), and not any of the Date() APIs.
Math.random returns an integer between and including 0 and 1. If you really want an semi-unique number based on the current time, you can combine the Date API with Math.random. For example:
var id = new Date().getTime() + Math.random();
In modern browsers, you can also use performance.now(). This API guarantees that every new call's return value is unique.
On Windows the resolution of the timer is about 10.5 ms. So you have chances of getting the same value even few milliseconds later. There are better timers of course, but AFAIK they are not available to JavaScript.
example.Even performance.now() sometimes don't give unique numbers. You have to make your own system to generate it. Something like make a counter and increase it by 1 each time when it is accessed.

How to Translate UTC time to arbitrary local time in Mongo J/S

I'm running a map reduce job in Mongo db.
The mapping function should map (e.g. count) events of certain nature to days in a certain time zone (the key of the map is calendar day). The time zone can be different, and is effectively an input parameter to the map/reduce job.
The time stored in the database objects is in UTC.
Example:
object1: time=78000
object2: time=86420
mapReduce(objects, tz='America/Los_Angeles')
would return: [{"1/1/1970" : 2}]
and
mapReduce(objects, tz='Europe/London')
would return: [{"1/1/1970":1},{"1/2/1970":1}]
on the same dataset.
The JavaScript Date object can perfectly convert any UTC time into a local time, but it seems to be limited to what's "current" time zone of the J/S environment. I can't seem to find a way to specify the time zone that I want the conversion to be in.
The conversion should account for DST, and preferably for leap seconds.
Is there anything that I can do to achieve this?
I found the answer that will work for me. The scope, after all, was limited to having this support in server-side mongo DB, and only on Linux.
#AsyaKamsky pointed to a greate J/S library, timezone-js, that does full and proper time zone support, considering that it uses actual time zone files from IANA. However, loading arbitrary java-script libraries into Mongo server environment is not that easy. You can only load global function definitions. timezone-js also needs to be provided with a custom transport mechanism to download the timezone files (I don't even know if MongoDB server environment provides files access), or the time zone files have to be precompiled into JSON objects, and served along with the library. I decided that this would be too tedious of an approach, and I will have to be responsible of providing mechanism to update time zone files when they are changed.
The other alternative I was looking into - is hacking the J/S implementation used in Mongo to add a function that will do the job I want it to do. That is what I have done. Things are actually as dismal in the world of glibc as they are in JavaScript, but there is a library for the job, icu.
I've made this patch, that adds a static Date.daytz() function, which, taken a UTC timestamp, and a time zone name, will return a yyyy-mm-dd string.
Considering the following map/reduce functions:
fmap = function () {
emit(Date.daytz(this.time * 1000, globtz), {count:1});
};
fred = function (k, v) {
var r = {count:0};
v.forEach(function (v0) {r.count += v0.count;});
return r;
};
I get exactly what I wanted, running these two map reduce commands:
{ "mapreduce" : "objects",
"map" : fmap,
"reduce" : fred,
"out" : { "inline" : 1 },
"scope" : { "globtz" : "Europe/London" } }
and
{ "mapreduce" : "objects",
"map" : fmap,
"reduce" : fred,
"out" : { "inline" : 1 },
"scope" : { "globtz" : "America/Los_Angeles" } }

Categories

Resources