Issue in timezone with Node.js Module 'time' - node.js

I just came across an issue that has happened today (due to being 31st of January here in Australia Sydney). Basically, given a year,date,hour,minute,second. I want to create a date as if I am in a timezone (Australia/Sydney) and then convert it to UTC (i.e. getting the milliseconds).
This is done due to the fact that the database (and the server) works in UTC, where as the client can be in any given timezone (when a post request is done, the client provides both the timezone and the year,month,date,hour,minute,second values)
The problem is, that when I am creating a date for today, its throwing off the date all the way back to January the 3rd of this month, here is the code that illustrates the problem
var scheduled, someTime, time, timeinfo, timezone;
process.env.TZ = 'UTC';
time = require('time');
timeinfo = {
hour: 14,
minute: '47',
year: 2013,
month: 1,
date: 31
};
timezone = 'Australia/Sydney';
someTime = new Date(timeinfo.year, timeinfo.month - 1, timeinfo.date, timeinfo.hour, timeinfo.minute, 1, 1);
scheduled = time.Date(timeinfo.year, timeinfo.month - 1, timeinfo.date, timeinfo.hour, timeinfo.minute, 1, 1, timezone);
console.log(someTime);
console.log(scheduled);
When you run this in Node.js, the time outputted by console.log(scheduled); is completely off.
Note: I am using the time npm library.

Seems to be a bug with how node-time calculates timezones, related to the order of the operations when doing the transform. There's an open issue (#28) on github.com as of now.
I have submitted a pull request, try that in the mean-time and see if it works for your particular case.

Please try the following codes
1.For GMT Time
var GMTtimeObj = new Date();
2.For UTC Time:
var UTCtimeObj = +new Date();
Let me know does it works for your requirement.
Go through this post's answers as well it might help you..

This was a bug that was fixed recently, please look at https://github.com/TooTallNate/node-time/pull/30
Its working perfectly now

Related

Setting Date() object to specific time if I know the timezone in string

I am trying to do something in node.js
So now if a user inputs a date, example 21/10/2020 at 1pm, I would like to create a Date() object with that date but adjusted to the User's timezone.
The only information I have about the timezone is the IANA(?) name, such as "Asia/Shanghai"
so is there anyway to do something like
const adjusted = new Date(2020, 9, 21, 13, 0, 'Asia/Shanghai');
to get the correct date? I am open to using packages.
Edit: Similarly, is there any easy packages out there to find the time offset (e.g. UTC + x) given the name? For example it would return +8 if the input is 'Asia/Shanghai'
Edit 2: To anyone else who came upon this, you can do what I want using dayjs.
for example, dayjs.tz("2020-12-01 12:30", "Europe/London") would give you a dayjs object with the correct time stamp.
You can use moment-timezone to create a date with a certain timezone:
const date = moment().tz("Asia/Shanghai");
console.log(date.format());
<script src="https://momentjs.com/downloads/moment.min.js"></script>
<script src="https://momentjs.com/downloads/moment-timezone-with-data.min.js"></script>
That's a great answer from #eol.
I'd also consider giving the new Luxon module a look, it does a lot of this kind of thing very nicely and it has an IANAZone class too!
const timeZone = "Asia/Shanghai";
const DateTime = luxon.DateTime;
const dt = DateTime.fromObject( { year: 2020, month: 10, day: 21, hour: 13, zone: timeZone})
console.log(`Time (${timeZone}):`, dt.toString());
console.log(`Time (UTC):`, dt.toUTC().toString());
const IANAZone = luxon.IANAZone;
let zone = IANAZone.create(timeZone);
console.log("UTC Offset:", (zone.offset(dt) >=0 ? "+": "-") + (zone.offset(dt) / 60));
<script src="https://cdnjs.cloudflare.com/ajax/libs/luxon/1.25.0/luxon.min.js" integrity="sha512-OyrI249ZRX2hY/1CAD+edQR90flhuXqYqjNYFJAiflsKsMxpUYg5kbDDAVA8Vp0HMlPG/aAl1tFASi1h4eRoQw==" crossorigin="anonymous"></script>

Error message "cannot find function getFullYear(...)" when entering date and trying to save the record

We are trying in a RESTLet to access the sublist "demandplandetail" from a NetSuite Item Demand Plan. Everything goes fine until a certain point. We are able to load it and process the demandplan for 2020. However, here it gets frustrating.
We know (can see from NetSuite) that there is data also for 2021. However, to access that from SuiteScript seems very difficult.
1st solution) The item demand plan has the field "year". OK, just set that to 2021, save and reload the record. Result: saving ignored, year still is 2020.
2nd solution) Set the year using a Date object as in:
var demandPlan = record.load(...)
var d = new Date();
demandPlan.setValue({
fieldId: 'year',
value: d
});
Gives the following:
:"TypeError: Cannot find function getFullYear in object NaN. (NLRecordScripting.scriptInit$lib#59)","stack":["setDatesForMonthAndYear(NLRecordScripting.scriptInit:108)","anonymous(N/serverRecordService)"
on saving the record. I also get the same using (various) strings adhering to acceptable date formats (as in '1/1/2021'). I have also tried the format package giving me a date string -> the same result.
Also read somewhere that you may need to set the start date (field 'startdate') in the record. Tried several variations but it stubbornly refuses :(.
Wonder if anyone has seen anything similar?
Best Regards,
Toni
Hi Please try the below code also check if you're passing date object to the field not the date string.
function formatDate() {
var dateROBD = format.parse({
value: new Date(),
type: format.Type.DATE
});
// this line optional if you want to try with or else ignore this
dateROBD = convertUTCDateToLocalDate(new Date(dateROBD));
return dateROBD;
}
function convertUTCDateToLocalDate(date) {
var newDate = new Date(date.getTime() + date.getTimezoneOffset() * 60 * 1000);
var offset = date.getTimezoneOffset() / 60;
var hours = date.getHours();
newDate.setHours(hours - offset);
return newDate;
}
OK, mystery solved. Turned out that this is not supported in SuiteScript 2.0 but you need to use 1.0.

setHour without change on Time Zone

I am coding a code on node.js which I need to set hour, minutes, seconds to now date without change time zone. (I get time from client which it sends time in hh:mm:ss format by UTC timezone)
My code on set time is:
var now = new Date();
console.log(now);
now.setHours(format.h);
now.setMinutes(format.m);
now.setSeconds(format.s);
the now time is:
2016-12-30T13:30:17.586Z
and format is:
13:29:29
when I set seconds, the result is
2016-12-30T18:29:29.345Z
It seems the time zone is changing; How can I set hour without timezone change?
UPDATE
I installed the momentjs and here is my code:
var now = moment();
console.log("before: " + now.format());
now.add(format.h, 'hours');
now.add(format.m, 'minutes');
now.add(format.s, 'seconds');
console.log("after: " + now.format());
here is logs:
format time= 3:45:38
before: 2017-01-06T12:55:45+03:30
after: 2017-01-06T16:41:23+03:30
Actually the time should be 2017-01-06T15:45:38+00:00
For any complex date/time manipulation it's better to use moment:
moment().set('hour', 13);
It will save you a lot of headaches.
See: http://momentjs.com/docs/
Instead of
date.setHours()
date.setMinutes()
date.setSeconds()
Use
date.setUTCHours()
date.setUTCMinutes()
date.setUTCSeconds()
And everything will work as expected :)

Momentjs timezone - getting date at time in specific timezone

I am attempting to create a date from a UTC base in a user's specific timezone, in this case "America/Los Angeles" using momentjs/momentjs timezone. However, I'm not getting the results I expect:
var tempDate = moment(1448841600000); //moment("2015-11-30"); //monday 11/30 in UTC
var adjustedStart = moment.tz(tempDate, "America/Los_Angeles");
adjustedStart.hour(9);
adjustedStart.minute(30);
console.log("adjustedStart in milliseconds:" + adjustedStart.valueOf());
The console output is 1448875800000 which is 11/30/15 9:30AM in UTC/GMT, I was expecting 1448904600000 which is 11/30/15 9:30AM in Pacific Coast time. How can I translate this start date to the right time in the user's timezone?
Yes, 1448841600000 is the date you said:
moment(1448841600000).utc().format()
// "2015-11-30T00:00:00+00:00"
But that is a day earlier in Pacific time
moment(1448841600000).tz('America/Los_Angeles').format()
// "2015-11-29T16:00:00-08:00"
When you adjust it to 9:30 pacific, it's on the 29th, not the 30th.
moment(1448841600000).tz('America/Los_Angeles').hour(9).minute(30).format()
// "2015-11-29T09:30:00-08:00"
When you call valueOf, the result is:
moment(1448841600000).tz('America/Los_Angeles').hour(9).minute(30).valueOf()
// 1448818200000
This is the correct value, however it's different than the one you provided. However, it is indeed what I get when I run your code as well.
Screenshot from Chrome debug window, with your exact code:
Also, in comments you wrote:
//moment("2015-11-30"); //monday 11/30 in UTC
Actually, that would be in local time, not UTC. If you wanted UTC, you'd use:
moment.utc("2015-11-30")
Though it's unclear to me whether you are using this string input or the numeric timestamp.
If what you are asking is that you want the UTC date to be treated as if it were local and then have an arbitrary local time applied - that is a somewhat strange operation, but it would go something like this:
var tempDate = moment.utc(1448841600000);
var adjustedStart = moment.tz([tempDate.year(), tempDate.month(), tempDate.date(), 9, 30],
"America/Los_Angeles");
console.log("adjustedStart in milliseconds:" + adjustedStart.valueOf());
// adjustedStart in milliseconds:1448904600000
This gives the value you asked for, but to me - this is a smell that something is wrong with the expectation. I'd look a lot closer at the requirement and the other parts of the system.
From http://momentjs.com/docs/:
moment#valueOf simply outputs the number of milliseconds since the Unix Epoch
It is important to note that though the displays differ above, they are both the same moment in time.
var a = moment();
var b = moment.utc();
a.format(); // 2013-02-04T10:35:24-08:00
b.format(); // 2013-02-04T18:35:24+00:00
a.valueOf(); // 1360002924000
b.valueOf(); // 1360002924000
So it shouldn't differ for different timezones.
You should use adjustedStart.format(); to see the difference

MomentJS getting JavaScript Date in UTC

I am not able to get the JavaScript Date string for MongoDB record via the following. It keeps using my local time.
var utc = moment.utc().valueOf();
console.log(moment.utc(utc).toDate());
Output:
Tue Nov 11 2014 14:42:51 GMT-0500 (EST)
I need it to be in UTC, so I can stick this timestamp in Mongo so type would be Date.
How can I do that?
A timestamp is a point in time. Typically this can be represented by a number of milliseconds past an epoc (the Unix Epoc of Jan 1 1970 12AM UTC). The format of that point in time depends on the time zone. While it is the same point in time, the "hours value" is not the same among time zones and one must take into account the offset from the UTC.
Here's some code to illustrate. A point is time is captured in three different ways.
var moment = require( 'moment' );
var localDate = new Date();
var localMoment = moment();
var utcMoment = moment.utc();
var utcDate = new Date( utcMoment.format() );
//These are all the same
console.log( 'localData unix = ' + localDate.valueOf() );
console.log( 'localMoment unix = ' + localMoment.valueOf() );
console.log( 'utcMoment unix = ' + utcMoment.valueOf() );
//These formats are different
console.log( 'localDate = ' + localDate );
console.log( 'localMoment string = ' + localMoment.format() );
console.log( 'utcMoment string = ' + utcMoment.format() );
console.log( 'utcDate = ' + utcDate );
//One to show conversion
console.log( 'localDate as UTC format = ' + moment.utc( localDate ).format() );
console.log( 'localDate as UTC unix = ' + moment.utc( localDate ).valueOf() );
Which outputs this:
localData unix = 1415806206570
localMoment unix = 1415806206570
utcMoment unix = 1415806206570
localDate = Wed Nov 12 2014 10:30:06 GMT-0500 (EST)
localMoment string = 2014-11-12T10:30:06-05:00
utcMoment string = 2014-11-12T15:30:06+00:00
utcDate = Wed Nov 12 2014 10:30:06 GMT-0500 (EST)
localDate as UTC format = 2014-11-12T15:30:06+00:00
localDate as UTC unix = 1415806206570
In terms of milliseconds, each are the same. It is the exact same point in time (though in some runs, the later millisecond is one higher).
As far as format, each can be represented in a particular timezone. And the formatting of that timezone'd string looks different, for the exact same point in time!
Are you going to compare these time values? Just convert to milliseconds. One value of milliseconds is always less than, equal to or greater than another millisecond value.
Do you want to compare specific 'hour' or 'day' values and worried they "came from" different timezones? Convert to UTC first using moment.utc( existingDate ), and then do operations. Examples of those conversions, when coming out of the DB, are the last console.log calls in the example.
Calling toDate will create a copy (the documentation is down-right wrong about it not being a copy), of the underlying JS Date object. JS Date object is stored in UTC and will always print to eastern time. Without getting into whether .utc() modifies the underlying object that moment wraps use the code below.
You don't need moment for this.
new Date().getTime()
This works, because JS Date at its core is in UTC from the Unix Epoch. It's extraordinarily confusing and I believe a big flaw in the interface to mix local and UTC times like this with no descriptions in the methods.
This will give you the UTC timezone DateTime.
var convertedUtcDateTime = moment.utc(dateTimeToBeConverted);
When you call .utc(), all you're doing is setting a flag in the Moment object that says "this must format as UTC." You can see this change if you inspect the object's properties.
As another answer mentioned, the point in time remains the same. This ensures calculations etc. can be carried out without worrying about the time zone.
A JavaScript Date also stores timezone information, and similarly will format the value it represents as local or UTC depending on what method you call.
Option 1
Use the formatting methods as they were intended, and make the last thing you do before sending the value to the server a format into a UTC string.
For Moment, that's simply calling .toISOString() on any date local or otherwise, or the .format() method after calling .utc() if you want to specify a different format.
For JS dates, that's also a .toISOString() method.
If for some reason you don't have the ability to keep the dates in local time, or can't transform to a string for the data send, you have (at least) two further options:
Option 2
Use the JS Date constructor to manually create a datetime in the local timezone, pulling the components from your UTC Moment object.
let utc = moment().utc();
let date = new Date(utc.year(), utc.month(), utc.date(), utc.hour(), utc.minute(), utc.second(), utc.millisecond());
Alternatively, get the current datetime and then set the hours and minutes as appropriate for the timezone change.
You'll end up with a date representation of the UTC time marked as local time. This is not the correct time, as you're now offset by the time zone, but it might solve a problem in a pinch.
Option 3
Similar to option 2, this is another way to create an offset Date where UTC is marked as the local time zone.
Export the ISO string from either Moment or JS, strip off the Zulu flag at the end, and use the string constructor for Date to pull it back in.
new Date(new Date().toISOString().slice(0,-1));
Again, this is not actually the correct time and calculations against other datetimes may be incorrect. Your best option is still to send up a UTC ISO string to the server when you can.
Or simply:
Date.now
From MDN documentation:
The Date.now() method returns the number of milliseconds elapsed since January 1, 1970
Available since ECMAScript 5.1
It's the same as was mentioned above (new Date().getTime()), but more shortcutted version.

Resources