Moment JS initialisation and the utc() method - javascript

I would like to understand Moment JS' initialisation of its moment object.
For example, if I would like to create a moment for the date and time:
April 1 2000, 3:25:00 am with utc offset of +8 hours from UTC/GMT.
I represent this in a javascript object:
var obj = {
year: 2000,
month: 4, //APRIL
day: 1,
hour: 3,
minute: 25,
second: 0,
utcOffset: 8 //8 hours from UTC
}
I then create a handy function I can use to create a moment with moment js:
var makemoment = function(obj){
var m = moment([obj.year, obj.month - 1, obj.day, obj.hour, obj.minute, obj.second, 0]).utcOffset(obj.utcOffset);
return m;
}
When I use this function to create moment...
e.g.
var result = moment(obj);
If I inspect the result object above I can see that it has a property _d
that I expect to have a value such as:
_d Date {Sat Apr 01 2000 03:25:00 GMT+0800 (HKT)}
But the actual value is which for me does not make sense since I specified that the time is 3:25:00 and it is already at GMT +0800 so no need to add 8 hours to the time....
_d Date {Sat Apr 01 2000 11:25:00 GMT+0800 (HKT)}
Despite of this _d value though, if I console.log(result)
I get the correct expected date:
2000-04-01T03:25:00+08:00
If I call the utc method on the moment. e.g. result.utc()
and if I inspect the object again, I can see that now the _d has changed to my originally expected value:
_d Date {Sat Apr 01 2000 03:25:00 GMT+0800 (HKT)}
However, now if I do result.format()
I get the correct UTC date and time:
2000-03-31T19:25:00+00:00
Am I not understanding something here????
How is the _d value used in Moment.js???
Should I ignore the _d value since it is just something internal to Moment.js???
I've created JSFiddle for to illustrate my point...
http://jsfiddle.net/nx2ch4ot/2/

A few things:
It's a common convention in JavaScript that fields of an object that are prefixed by an underscore are meant to be treated as private/internal and not used directly. Though it may be more user-friendly to hide them via closures, it's also slower, and thus libraries like moment.js choose to leave them exposed.
Instead of using _d, call a public function such as .format(), or any of the others shown in the documentation.
If you really want to know more about _d, take a look at this answer.
The time zone shown in a Date object will always be relative to the computer where the code is running. JavaScript's Date object doesn't have the ability to reflect other time zones. When moment uses _d, it mostly uses it just for its instantaneous value given by _d.getTime(), which reflects only UTC. (We're actually considering removing _d entirely in a future version.)
You do indeed need to adjust for the offset, but you should be starting from moment.utc instead of local time. The corrected function is:
var makemoment = function(obj){
var m = moment.utc([obj.year, obj.month - 1, obj.day, obj.hour, obj.minute, obj.second, 0]);
m.subtract(obj.utcOffset, 'hours');
m.utcOffset(obj.utcOffset);
return m;
}
The function you wrote is very similar to the one already built in to moment. You can pass an object to either moment or moment.utc. The difference with yours is that moment's uses zero-based months, and doesn't yet support passing a utcOffset field. You might just consider using that instead.
var makemoment = function(obj){
obj.month--; // switch to zero-based months
var m = moment.utc(obj);
obj.month++; // put it back
m.subtract(obj.utcOffset, 'hours');
m.utcOffset(obj.utcOffset);
return m;
}

Related

Javascript dates: a nightmare

I understand that dealing with dates, in any environment, could be quite confusing, but I'm in a nightmare with a function that should be a trivial job.
I want to manipulate in different ways some dates, but I get errors or wrong results.
I report hereafter a very simple example made to test the execution; the goal here is to get the current month beginning date, just to show what happens:
function DateAdjust() {
var newdate = new Date(); //1: 2018-12-12T21:00:20.099Z
newdate = newdate.setDate(1); //2: 1543698020099
newdate=Date(newdate); //3: Wed Dec 12 2018 21:01:43 GMT+0000 (Ora standard dell’Europa occidentale)
var d = newdate.getDate(); //4: newdate.getDate is not a function
}
4 lines, 3 unexpected results (as shown by Firefox's debugger):
1. the starting date has no day-of-week and no timezone
2. setting the day, result is transformed in milliseconds (why?); I do not know if it is correct.
3. reconverting in string gives the original date, unmodified (why?) but with week day and timezone
4. trying to get the day value an error is thrown (why?)
My environment:
Win 7 32bits SP1
Firefox 63.0.3 (32 bit)
jquery-2.2.4.min.js
I know these questions are boring, but hope someone will find few minutes to clear my mind.
Regarding line 1, the Z at the end is the timezone designation for UTC in ISO 8601 (see Wikipedia).
If the time is in UTC, add a Z directly after the time without a space. Z is the zone designator for the zero UTC offset. "09:30 UTC" is therefore represented as "09:30Z" or "0930Z". "14:45:15 UTC" would be "14:45:15Z" or "144515Z".
Regarding line 2 see the MDN article on setDate (emphasis mine):
The number of milliseconds between 1 January 1970 00:00:00 UTC and the given date (the Date object is also changed in place).
So you can see the 'correct' behavior you probably expect simply by ignoring the return value:
var newdate = new Date(); //1: 2018-12-12T21:00:20.099Z
newdate.setDate(1); //2: 1543698020099
console.log(newdate); //3: 2018-12-01T21:00:20.099Z
Regarding line 3, see MDN article on Date (emphasis mine):
Note: JavaScript Date objects can only be instantiated by calling
JavaScript Date as a constructor: calling it as a regular function
(i.e. without the new operator) will return a string rather than a
Date object; unlike other JavaScript object types, JavaScript Date
objects have no literal syntax.
Regarding line 4, the above also explains this error, since newdate is now a string rather than a Date object.
For what it's worth, I agree with the other commenters. JavaScript's date functions are pretty messy compared to many other modern languages. I strongly recommend using a library like moment, luxon, or date-fns. It'll make your life much easier.
I do recommend using moment.js
But there are 2 problems with your code:
1-
newdate = newdate.setDate(1);
setDate mutates newDate in place, and return it in miliseconds, not a new Date object. If you just want to set the date, do this instead:
newdate.setDate(1);
2-
newdate=Date(newdate);
Not realy sure why you are trying to get a new Date object, but you need the new, otherwise it will just be a string
newdate= new Date(newdate);
Fixing problem 1 should eliminate the need for the code of problem 2
var newdate = new Date(); // 1
console.log(typeof newdate, newdate); // object Wed Dec 12 2018 23:00:44 GMT+0200 (Eastern European Standard Time)
newdate = newdate.setDate(1); // 2
console.log(typeof newdate, newdate); //number 1543698085383
newdate=Date(newdate); //3
console.log(typeof newdate, newdate); //string Wed Dec 12 2018 23:04:44 GMT+0200 (Eastern European Standard Time)
var d = newdate.getDate(); // 4
console.log(typeof d, d); //
Date type is assigned to the object.
number is assigned to newdate. which is ticks
returns string
string.getDate() is not defined, so undefined.
hope it helps.

Javascript Date toJSON() outputting incorrect date

I am based in Australia and while new Date() give me the current date and time in Australia, for instance
Fri Aug 26 2016 09:16:16 GMT+1000 (AUS Eastern Standard Time)
, if I write new Date().toJSON()
I get 2016-08-25T23:20:08.242Z,
how can I get the same format as in yyyy-mm-ddThh:mn:ss but keeping my local day and time, ie it should be the 26 and not the 25th.
Edit: when I write programmatically new Date(2016, 11, x) with var x = 31, using toJSON() I have no guarantee to see displayed 2016-12-31 because of timezones, so was wondering is there is a different javascript function that would give me the intended result.
I would use moment.js for that.
var date = moment("Fri Aug 26 2016 09:16:16 GMT+1000");
console.log(moment(date).format('YYYY-MM-DD T hh:mm:ss'));
https://jsfiddle.net/Refatrafi/ys4nu8o9/
toJSON() returns timestamps in ISO 8601 format. Z at the end of string means that used UTC. Date objects in ECMAScript are internally UTC. The specification for Date.prototype.toJSON says that it uses Date.prototype.toISOString, which states that "the timezone is always UTC".
The date isn't wrong, it's in UTC. Without timezone information, yyyy-mm-ddThh:mn:ss is meaningless unless you explicitly want to assume that it's in the AEST timezone.
If you're transmitting the date as a string to be parsed back into some sort of Date-like object later on (by your webserver, for example), there's nothing you need to do. 2016-08-25T23:20:08.242Z unambiguously refers to the same point in time no matter what you use to parse it.
If you're trying to format the date object and display it somewhere, you can extract the different parts of the Date object and build up the representation you want:
function format_date(d) {
var pretty_date = [d.getFullYear(), d.getMonth() + 1, d.getDate()].join('-');
var pretty_time = [d.getHours(), d.getMinutes(), d.getSeconds()].join(':');
return pretty_date + 'T' + pretty_time;
}
As the other answers have pointed out, if you plan on working more with dates, consider using a library that makes it easier. JavaScript doesn't have a very rich API, so you'll have to write more code.

Conversion of date into long format, How it works?

I was trying to convert date object into long format (may be in milliseconds format) as we do in java.
So to fulfill my need, after some trial and error, I found below way which works for me:
var date = new Date();
var longFormat = date*1; // dont know what it does internally
console.log(longFormat); // output was 1380625095292
To verify, I reverse it using new Date(longFormat); and it gave me correct output. In short I was able to fulfill my need some how, but I am still blank what multiplication does internally ? When I tried to multiply current date with digit 2, it gave me some date of year 2057 !! does anyone know, what exactly happening ?
The long format displays the number of ticks after 01.01.1970, so for now its about 43 years.
* operator forces argument to be cast to number, I suppose, Date object has such casting probably with getTime().
You double the number of milliseconds - you get 43 more years, hence the 2057 (or so) year.
What you are getting when you multiply, is ticks
Visit: How to convert JavaScript date object into ticks
Also, when you * 2 it, you get the double value of ticks, so the date is of future
var date = new Date()
var ticks = date.getTime()
ref: Javascript Date Ticks
getTime returns the number of milliseconds since January 1, 1970. So when you * 1 it, you might have got value of this milliseconds. When you * 2 it, those milliseconds are doubled, and you get date of 2057!!
Dates are internally stored as a timestamp, which is a long-object (more info on timestamps). This is why you can create Dates with new Date(long). If you try to multiply a Date with an integer, this is what happens:
var date = new Date();
var longFormat = date*1;
// date*1 => date.getTime() * 1
console.log(longFormat); // output is 1380.....
Javascript tries to find the easiest conversion from date to a format that can be multiplied with the factor 1, which is in this case the internal long format
Just use a date object methods.
Read the docs: JavaScript Date object
var miliseconds=yourDateObject.getMiliseconds();
If You want to get ticks:
var ticks = ((yourDateObject.getTime() * 10000) + 621355968000000000);
or
var ticks = someDate.getTime();
Javascript date objects are based on a UTC time value that is milliseconds since 1 January 1970. It just so happens that Java uses the same epoch but the time value is seconds.
To get the time value, the getTime method can be used, or a mathematic operation can be applied to the date object, e.g.
var d = new Date();
alert(d.getTime()); // shows time value
alert(+d); // shows time value
The Date constructor also accepts a time value as an argument to create a date object, so to copy a date object you can do:
var d2 = new Date(+d);
If you do:
var d3 = new Date(2 * d);
you are effectively creating a date that is (very roughly):
1970 + (2013 - 1970) * 2 = 2056
You could try the parsing functionality of the Date constructor, whose result you then can stringify:
>
new Date("04/06/13").toString()
"Sun Apr 06 1913 00:00:00 GMT+0200"
// or something
But the parsing is implementation-dependent, and there won't be many engines that interpret your odd DD/MM/YY format correctly. If you had used MM/DD/YYYY, it probably would be recognized everywhere.
Instead, you want to ensure how it is parsed, so have to do it yourself and feed the single parts into the constructor:
var parts = "04/06/13".split("/"),
date = new Date(+parts[2]+2000, parts[1]-1, +parts[0]);
console.log(date.toString()); // Tue Jun 04 2013 00:00:00 GMT+0200

How do you check whether a date is UTC in Javascript?

I've read this question:
How do you convert a JavaScript date to UTC?
and based on this I implemented this conversion in a dateTools module as follows:
[Update]
var dt, utcTime;
dt = new Date();
utcTime = new Date(Date.UTC(dt.getFullYear(),
dt.getMonth(),
dt.getDate(),
dt.getHours(),
dt.getMinutes(),
dt.getSeconds(),
dt.getMilliseconds()));
Now I'd like to write unit tests. My idea was to check whether the result is actually in UTC, but I don't know how.
All the toString, toUTCString and similar methods seem to be identical for the input (non UTC) and output (UTC) date.
Only the result of the getTime method differs.
Is there a way to check wheter a date is UTC in javascript? If not, is there a better idea to unit test this?
To give more context:
Only converting the it to a UTC string is not that helpful, because in the next step the date is sent to an Asp.net service and therefore converted to a string like:
'/Date([time])/'
with this code
var aspDate = '/Date(' + date.getTime() + ')/';
var aspDate = '/Date(' + date.getTime() + ')/';
This outputs the internal UNIX epoch value (UTC), which represents a timestamp. You can use the various toString methods to get a more verbose string representation of that timestamp:
.toString() uses the users timezone, result is something like "Fri Jan 25 2013 15:20:14 GMT+0100" (for me, at least, you might live in a different timezone)
.toUTCString() uses UTC, and the result will look like "Fri, 25 Jan 2013 14:20:15 GMT"
.toISOString() uses UTC, and formats the datestring according to ISO: "2013-01-25T14:20:20.061Z"
So how do we construct the time value that we want?
new Date() or Date.now() result in the current datetime. No matter what the user's timezone is, the timestamp is just the current moment.
new Date(year, month, …) uses the users timezone for constructing a timestamp from the single values. If you expect this to be the same across your user community, you are screwed. Even when not using time values but only dates it can lead to odd off-by-one errors.
You can use the setYear, setMonth, … and getYear, getMonth … methods to set/get single values on existing dates according to the users timezone. This is appropriate for input from/output to the user.
getTimezoneOffset() allows you to query the timezone that will be used for all these
new Date(timestring) and Date.parse cannot be trusted. If you feed them a string without explicit timezone denotation, the UA can act random. And if you want to feed a string with a proper format, you will be able to find a browser that does not accept it (old IEs, especially).
Date.UTC(year, month, …) allows you to construct a timestamp from values in the UTC timezone. This comes in handy for input/output of UTC strings.
Every get/set method has a UTC equivalent which you can also use for these things.
You can see now that your approach to get the user-timezone values and use them as if they were in UTC must be flawed. It means either dt or utcTime has the wrong value, although using the wrong output method may let it appear correct.
getTimezoneOffset
Syntax: object.getTimezoneOffset( ) This method
returns the difference in minutes between local time and Greenwich
Mean Time. This value is not a constant, as you might think, because
of the practice of using Daylight Saving Time.
i.e.
var myDate = new Date;
var myUTCDate = new Date(myDate - myDate.getTimezoneOffset() * 60000);
alert(myUTCDate);
note: 60000 is the number of milliseconds in a minute;

Is there a simple conversion for this datetime format?

I'm retrieving data from a JSON feed using jQuery and as part of the feed I'm getting 'datetime' attributes like "2009-07-01 07:30:09". I want to put this information into a javascript Date object for easy use but I don't believe the Date object would recognize this kind of format if I simply plugged it into the constructor. Is there a function or maybe a clever trick I can use to quickly break down this format into something the Date object can recognize and use?
The "date" attribute you are retrieving from that webservice is not a real Date, as it is not a recognized date format.
The easiest way to handle it as a Date object would be to replace the empty space with a "T":
var receivedDate = "2009-07-01 07:30:09";
var serializedDate = new Date(receivedDate.replace(" ", "T"));
alert(serializedDate);
This is not the most correct, as it is not handling timezones, but in most cases will work.
See this and this.
input = "2009-07-01 07:30:09";
var res = input.match(/([\d\-]+) (\d+):(\d+):(\d+)/);
date = new Date(Date.parse(res[1]));
date.setHours(res[2]);
date.setMinutes(res[3]);
date.setSeconds(res[4]);
console.log(date);
Edit: My original answer was
t = new Date(Date.parse("2009-07-01 07:30:09"));
which did not throw any error in chrome but all the same incorrectly parsed the date. This threw me off. Date.parse indeed appears to be quite flaky and parsing the complete date and time with it is probably not very reliable.
Edit2: DateJS appears to be a good solution for when some serious parsing of text to date is needed but at 25 kb it is a bit heavy for casual use.
var str="2009-07-01 07:30:09";
It depends on the time zone,
and if the date string has subtracted 1 for the month.
If it is GMT time, and the 07 means July and not August:
var str="2009-07-01 07:30:09";
var d=new Date(), time;
str=str.split(/\D0?/);
str[1]-=1;
time=str.splice(3);
d.setUTCFullYear.apply(d,str);
d.setUTCHours.apply(d,time)
alert(d)
/* returned value: (Date)
Wed Jul 01 2009 03:30:09 GMT-0400 (Eastern Daylight Time) or local equivilent
*/
This may be a bit cumbersome, but the JavaScript Date object will take an argument list of YYYY,MM,DD,HH,MM,SS. Parse out the date value and pass it to a Date constructor, e.g.
var splitDT= '2009-07-01 07:30:09'.split(' '); // ['2009-07-01','07:30:09']
var d= splitDT[0].split('-');
var t= splitDT[1].split(':');
alert( (new Date(d[0],d[1],d[2],t[0],t[1],t[2])) );
Bah. Had to use the array index values instead. Yeah, that's a mess. But it works.

Categories

Resources