Monkeypatch the JavasScript date object - javascript

I know that this a crazy hack but curious about it anyhow. We have an environment that has the wrong system time and we cannot set it to the correct time. It's specialized hardware so we cannot change the system time. We do however have a service that gives us the correct current time. Our issue is that a bunch of ssl and token signing libraries break because they are getting the wrong datetime from the javascript Date object ( since we have the wrong system time).
What's the way to monkeypatch the Date object's constructor so that we can feed it the correct time to initialize with so that all subsequent calls to Date(), Date.toString(), etc... in the dependent libraries will return our new method that returns the correct non-system time?
Will this work?
var oldDate = Date;
Date = function(){
return new oldDate(specialCallToGetCorrectTime());
}
Date.prototype = oldDate.prototype;

Will this work?
No, since it does not respect arguments given to your new Date function or whether it was called as a constructor vs not. Also you forgot to fix Date.now(). You still will need to get those right:
Date = (function (oldDate, oldnow) {
function Date(year, month, date, hours, minutes, seconds, ms) {
var res, l = arguments.length;
if (l == 0) {
res = new oldDate(Date.now());
} else if (l == 1) {
res = new oldDate(year); // milliseconds since epoch, actually
} else {
res = new oldDate(
year,
month,
l > 2 ? date : 1,
l > 3 ? hours : 0,
l > 4 ? minutes : 0,
l > 5 ? seconds : 0,
l > 6 ? ms : 0)
}
if (this instanceof Date) {
return res;
} else {
return res.toString();
}
}
Date.prototype = oldDate.prototype; // required for instanceof checks
Date.now = function() {
return oldnow() + offset; // however the system time was wrong
};
Date.parse = oldDate.parse;
Date.UTC = oldDate.UTC;
return Date;
})(Date, Date.now);

I just tried this out in the latest Chrome, Firefox, and IE, and it is allowed. I'm not convinced this is better than just fixing the system time (surely it can be fixed), but the approach is doable.

Yes, provided the implementation allows you to redefine window.Date
(It's polite to wrap this sort of thing in a closure)

Related

MomentJS and JS Date objects not referring to the same hour

I've got a server instance (NodeJS) that receives a set of objects, and schedules them for sending push notifications to users.
Some of these objects, are periodic, and this periodicity is handled by a string like this:
90=>Mon&Tue&Thu=>16:00
Which is read as:
offset_minutes=>days_of_the_week=>initial_hour
Then, what I do is to check whether the current day matches one of the given days in the string, and then, modify the date to the given hour in the "initial_hour", and finally, substract the "offset_minutes" amount of minutes from the Date object.
Seems straightforward until now, right? Well, not that much. Let's first see the code:
const isToday = weekDays.split("&")
.map(a => {
switch (a) {
case 'Mon': return 1;
case 'Tue': return 2;
case 'Wed': return 3;
case 'Thu': return 4;
case 'Fri': return 5;
case 'Sat': return 6;
case 'Sun': return 7;
}
})
.some(v => v == currentDay);
if (isToday) {
let finalDate = moment(today)
.set("hour", Number(hour))
.set("minute", Number(mins));
if (offset) {
finalDate.subtract('minutes', Number(offset));
}
return finalDate.toDate();
Everything works well, until I do the MomentJS transformations. When I output a Date object with the ".toDate()" method, this object is always set to 2 hours before the expected time. But if I use the .toISOString() method, I get the proper time for all the occurrencies.
I guess that something is wrong with my Date objects, setting them up at a different timezone than the one I have. A couple of examples:
For the string 90=>Mon&Tue&Thu=>16:00 I get the Date object: 2019-10-14T14:00:11.852Z
For the string 30=>Mon&Tue&Wed&Thu&Fri&Sat&Sun=>18:30 I get the Date object: 2019-10-14T16:30:11.866Z
I would like to know what's the explanation for such a behavior, and if I can do something to change it so the normal Javascript Date object points to the same hour than my momentjs object, or the .toISOString() output.
Thank you!
The posted code is incomplete and doesn't demonstrate the issue described.
I've reimplemented the code without moment.js as best I can and simplified it. It seems to work fine:
function parseThing(s) {
// Parse input string
let b = s.split('=>');
let offset = +b[0];
let days = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];
let weekDays = b[1].split('&').map(day => days.indexOf(day));
let [hr, min] = b[2].split(':');
// Get a date for today
let date = new Date();
// If today included, return an adjusted date
if (weekDays.includes(date.getDay())) {
date.setHours(hr, min, 0, 0);
if (offset) {
date.setMinutes(date.getMinutes()+ Number(offset));
}
return date;
}
// If today isn't included, return null
return null;
}
let s0 = '90=>Mon&Tue&Thu=>16:00';
let s1 = '0=>Mon&Tue&Wed&Thu&Fri&Sat&Sun=>18:30';
console.log(parseThing(s0).toString());
console.log(parseThing(s1).toString());
Where the local day is one of those in the string (Mon, Tue, Thu) it returns a Date equivalent to a local time of 17:30, which is 90 minutes offset from 16:00, which seems to be correct.
PS I've changed Sunday to 0 as I can't see any rationale for it to be 7. Also seconds and milliseconds are zeroed too.

Do something when time is above the set time

I am just a newbie. I am trying delete a span when the time is above 6:30 pm daily. Code below:
(function(){
var d = new Date();
d.setHours(18,30,0);
if (d<new Date().toLocaleString());{
$("span:contains('Material Receive')").remove()
return false;}})();
However it s not working. It is always removing, i.e 24x7.
getHours Method will fit perfect i think
var d = new Date();
if (1830 < d.getHours()+""+d.getMinutes()){
$("span:contains('Material Receive')").remove()
return false;
}
Try to not compare an object with a string. Use 2 numbers instead. And lose the stray semicolon.
if (d.getTime() < new Date().getTime()){...}
Above answers already explained for you. Anyway:
Getting current date and time in JavaScript
I didn't understand exactly what you want to do, I suppose to delete a span every day at 18:30, right?
In this case, when you create the date object, you have to access hours and minutes to check time so:
( function() {
var d = new Date();
if( ( d.getHours() == 18 ) && ( d.getMinutes() == 30 ) ) {
$("span:contains('Material Receive')").remove();
return false; //Useless in a self-invoking function
}
})();

Cannot print message according to time

I've three different times, two of them are in string forms (time1 and time2) and one from system date currDate. Next step according to the one of two above times I want to print messages when the system date reaches one of them. For this I've function callEachMinute that calls each minute to get system time (but here in code I did not include the whole procedure). Here is the current status of the code:
Script:
function callEachMinute() {
var currDate = new Date();
var time_1 = '8:30';
var time_2 = '23:00';
timeComparison(currDate, time_1, time_2)
}
function timeComparison(currTime, time1, time2) {
// Time 1 formatting
var t1 = new Date();
var parts1 = time1.split(":");
t1.setHours(parts1[0],parts1[1]);
// Iftor-Time formatting
var t2 = new Date();
var parts2 = timeI.split(":");
t2.setHours(parts2[0],parts2[1]);
/* Notification procedure */
if (currTime == t1) {
// Message for Time1
alert("Time 1 is reached");
}
if (currTime == t2) {
// Message for Time2
alert("Time 2 is reached");
}
}
Problem:
When the system time is reached one of times (time1 or time2) nothing happens. Any solution for this problem?
There are a few things that could be problematic here.
You set up a Date object then want to compare it to currTime:
if (currTime == t1) {
unfortunatley Javascript's == operator when applied to objects compares two objects to see if they are references to the same object, so even if currTime and t1 contained exactly the same time this check would evaluate to false since they are different instances. You could do this by converting to a string:
if (currTime.toString() == t1.toString) {
which would work if the string representations for each data work out the same.
However, a more straight forward approach might be to tackle this the other way around - extract the hours and minutes from currTime, build a string and compare that to your time strings. Something like:
// in timecomparison function
var hrs = currTime.getHours();
var mins = currTime.getMinutes();
var now = hrs+":"+mins
// now do comparisons
if (now == time1 ) {
....
}
and so on.

Javascript Timestamp from ISO8061

I'm having a bit of an issue when dealing with getting a timestamp from an iso8061 date.
For some reason it work perfectly in Chrome, but causes an Invalid Date error in Firefox. The exact line is:
var date = new Date(time.replace(/-/g,"/").replace(/[TZ]/g," "));
I've tried passing the date through (as the var time) 2011-03-09T16:46:58+00:00, 2011-03-09T16:46:58+0000 and 2011-03-09T16:48:37Z as per the spec outlined http://www.jibbering.com/faq/#dates but I still can't seem to get it to work in firefox. In fact, the last method didn't work in either browser.
If anyone could help me turn this iso8061 date into a timestamp, that would be great.
Thanks,
Angelo R.
take a look at JavaScript ISO8601/RFC3339 Date Parser:
their code:
Date.prototype.setISO8601 = function(dString){
var regexp = /(\d\d\d\d)(-)?(\d\d)(-)?(\d\d)(T)?(\d\d)(:)?(\d\d)(:)?(\d\d)(\.\d+)?(Z|([+-])(\d\d)(:)?(\d\d))/;
if (dString.toString().match(new RegExp(regexp))) {
var d = dString.match(new RegExp(regexp));
var offset = 0;
this.setUTCDate(1);
this.setUTCFullYear(parseInt(d[1],10));
this.setUTCMonth(parseInt(d[3],10) - 1);
this.setUTCDate(parseInt(d[5],10));
this.setUTCHours(parseInt(d[7],10));
this.setUTCMinutes(parseInt(d[9],10));
this.setUTCSeconds(parseInt(d[11],10));
if (d[12]) {
this.setUTCMilliseconds(parseFloat(d[12]) * 1000);
}
else {
this.setUTCMilliseconds(0);
}
if (d[13] != 'Z') {
offset = (d[15] * 60) + parseInt(d[17],10);
offset *= ((d[14] == '-') ? -1 : 1);
this.setTime(this.getTime() - offset * 60 * 1000);
}
}
else {
this.setTime(Date.parse(dString));
}
return this;
};
and then you can use it this way:
var today = new Date();
today.setISO8601('2008-12-19T16:39:57.67Z');
probably not that comfortable, but you can rewrite this function, or write another one which will return date based on ISO-8601 format
The way that the Date constructor handles string arguments differs across browsers. As the first answer to this question points out, IE recognizes hyphens, but Firefox does not, as just one example.
It's probably best to use the constructor that expects individual date parts.

Relative Time jQuery Plugin (like Twitter, FB, etc) Breaks in Safari?

Works in all browsers except Firefox, any ideas?
(function($){
$.relativetime = function(options) {
var defaults = {
time:new Date(),
suffix:'ago',
prefix:''
};
options = $.extend(true, defaults, options);
//Fixes NaN in some browsers by removing dashes...
_dateStandardizer = function(dateString){
modded_date = options.time.toString().replace(/-/g,' ');
return new Date(modded_date)
}
//Time object with all the times that can be used throughout
//the plugin and for later extensions.
time = {
unmodified:options.time, //the original time put in
original:_dateStandardizer(options.time).getTime(), //time that was given in UNIX time
current:new Date().getTime(), //time right now
displayed:'' //what will be shown
}
//The difference in the unix timestamps
time.diff = time.current-time.original;
//Here we save a JSON object with all the different measurements
//of time. "week" is not yet in use.
time.segments = {
second:time.diff/1000,
minute:time.diff/1000/60,
hour:time.diff/1000/60/60,
day:time.diff/1000/60/60/24,
week:time.diff/1000/60/60/24/7,
month:time.diff/1000/60/60/24/30,
year:time.diff/1000/60/60/24/365
}
//Takes a string and adds the prefix and suffix options around it
_uffixWrap = function(str){
return options.prefix+' '+str+' '+options.suffix;
}
//Converts the time to a rounded int and adds an "s" if it's plural
_niceDisplayDate = function(str,date){
_roundedDate = Math.round(date);
s='';
if(_roundedDate !== 1){ s='s'; }
return _uffixWrap(_roundedDate+' '+str+s)
}
//Now we loop through all the times and find out which one is
//the right one. The time "days", "minutes", etc that gets
//shown is based on the JSON time.segments object's keys
for(x in time.segments){
if(time.segments[x] >= 1){
time.displayed = _niceDisplayDate(x,time.segments[x])
}
else{
break;
}
}
//If time.displayed is still blank (a bad date, future date, etc)
//just return the original, unmodified date.
if(time.displayed == ''){time.displayed = time.unmodified;}
//Give it to em!
return time.displayed;
};
})(jQuery);
In Safari, this code returns the given date which my plugin date if it fails. This could happen due to a future date or an invalid date. However, I'm not sure as the time that is given is standard YY MM DD HH:mm:ss
Demo:
http://jsfiddle.net/8azeT/
I think the string used is wrong and then stripped of '-' very wrong:
'010111' - interpreted by FF as Jan 1 1911 (US FF)
Correct format is '01/01/2011' (US FF)
I wouldn't use this format at all as each country has it's own way of showing/ parsing dates.
The safest way to parse a string is probably to use:
'January 1, 2011 1:30:11 pm GMT'
but I would use a date object instead in the options and skip the string parsing to make sure the date is correct.
http://jsfiddle.net/8azeT/4/
Question is about Safari but content FF?

Categories

Resources