Javascript equivalent of visual foxpro gomonth() - javascript

I'm tasked with writing a web portal for a legacy application that was written in Visual Foxpro. I have to validate a pregnancy due date. The rule is that it can't be more than 9 months from the current date. I've already tried to argue that this is too vague and that it needs to be in days or weeks, but I was told that I have to mimic the legacy software.
Here's what the code in VSP is doing:
maxValueForDueDate = GOMONTH(DATE() , 9)
According to MSDN GOMONTH() handles edge cases as follows:
SET CENTURY ON
STORE GOMONTH({^1998-02-16}, 5) TO gdDeadLine
CLEAR
? gdDeadLine && Displays 07/16/1998
? GOMONTH({^1998-12-31}, 2) && Displays 02/28/1999
? GOMONTH({^1998-12-31}, -2) && Displays 10/31/1998
As you can see adding 2 months to December 31st does not result in March 2nd, unfortunately that's exactly what the following javascript does:
var dDate = new Date('1998-12-31');
dDate.setMonth(dDate.getMonth() + 2);
alert(dDate.toDateString()); // results in - Tue Mar 02 1999
Does anyone have a javascript function handy that they've written for this scenario? I've googled around, but haven't found what I need. I'm limited in my third-party usage to JQuery.

Add the number of milliseconds (or seconds or hours or days) in 2 "full months" (that is, 30 days x 24 hours). The idea is that the entire date is shifted, and not just the single [month] component. For example:
var a = new Date('1998-12-31')
var ms_in_month = 30 * (24 * 60 * 60) * 1000
var b_ticks = (+a) + 2 * ms_in_month
var b = new Date(b_ticks)
alert(b) // Sun Feb 28 1999 16:00:00 GMT-0800 (Pacific Standard Time)
The (+a) coerces the Date to a number which results in the number of milliseconds since epoch. (This could also be written as a.milliseconds). Then new Date(millis_since_epoch) does the reverse and creates a Date from the epoch offset.
Disclaimer: I am not sure what the exact rules for GOMONTH are
, and it might use the "30.5 days in a month heuristic" (365/12 = 30.41) or another variation. I suspect it does not account for the month durations (the documentation does state that "-1 [month] means -31 days") or leap years ..

You can look at the open source javascript date library Datejs
If you cannot add this file, you can at least look at the code to see how the edge cases are handled.

Related

Date appears to be changing time zone from daylight to standard upon calculation

I have a jQuery range slider that is supposed to increase and decrease the date range by a week with each value. When incrementing past a certain point (November 1st in my example) the time zone changes from daylight to standard. I assume it has something to do with the way I'm calculating the new date but I can't seem to figure out what it is.
I calculate it with:
new Date(minDate.getTime() + (sliderValue * 7) * 1000 * 60 * 60 * 24)
Here's an example fiddle: https://jsfiddle.net/aedryan/f4pvg84e/
Your code is actually working fine. The reason it changes after November 1 is because we switch from Eastern Daylight Time (EDT) to Eastern Standard Time on that date - in both cases you are representing the eastern time zone. Btw, for the future this is a nice way of adding days to a date:
/**
* extends the functionality of the Date() object to include a function called addDays that adds days to
* a javascript date based on an integer
* #param days
* #returns {Date}
*/
Date.prototype.addDays = function(days){
var dat = new Date(this.valueOf());
dat.setDate(dat.getDate() + days);
return dat;
};
You were calculating days by millisecond. However, November 1st was in fact day light savings (welcome to the wonderful world of time culture). As a result your times are off by 1 hour and that means you count 23 hours for one day and only get +6.
As opposed to making these changes by millisecond, simply add the days. This can be done easily in JavaScript as when the days extend past the amount available that month it just returns the adjusted date. That means you can use this for your newDate forumla
var newDate = new Date(2015, 7, 23+(ui.value*7));
Which looks like this: https://jsfiddle.net/u2h261ka/

Calculate difference between 2 dates considering Daylight Saving Time

Given a start date, and a number of days, I need to display the end date = start date + number of days.
So I did something like this:
var endDate=new Date(startDate.getTime()+ONE_DAY);
Everything works fine, except that for 25 and 26 October gives one day less.
Ex.:
2014-01-01 + 2 days = 2014-01-03
2014-10-25 + 2 days = 2014-10-26 (here is the case I need to treat).
This difference appear because of the clock going back 1 hour. Practically 2014-10-27 00:00:00 becomes 2014-10-26 23:00:00.
A simple solution would be to compute this at another hour (example 3 AM). But I want to just display a note when this happens.
For example, if user inputs 2014-10-25, I show a popup saying [something].
Now here is the real problem... I can't seem to find any algorithm that says when clocks goes back in year X.
Example... in 2014 the day is 26 October. In 2016 is 30 October (https://www.gov.uk/when-do-the-clocks-change). Why? This date looks random to be, but I don't think it is. So... when does clock go back/forward?
EDIT: All answers/comments are helpful related to how to fix the problem. But... I already passed that stage. Now I only have an itch about "how on earth are the days when clock is changed computed?".
To find the difference between two dates in whole days, create Date objects, subtract one from the other, then divide by the milliseconds in one day and round. The remainder will only be out by 1 hour for daylight saving so will round to the right value.
You may also need a small function to convert strings to Dates:
// Return Date given ISO date as yyyy-mm-dd
function parseISODate(ds) {
var d = ds.split(/\D/);
return new Date(d[0], --d[1], d[2]);
}
Get the difference in days:
function dateDiff(d0, d1) {
return Math.round((d1 - d0)/8.64e7);
}
// 297
console.log(dateDiff(parseISODate('2014-01-01'), parseISODate('2014-10-25')));
If you want to add days to a date, do something like:
// Add 2 days to 2014-10-25
var d = new Date(2014, 9, 25);
d.setDate(d.getDate() + 2);
console.log(d); // 2014-10-27
The built–in Date object takes account of daylight saving (thought there are bugs in some browsers).
I prefer adding days this way:
var startDate = //someDate;
var endDate = new Date(startDate.getFullYear(),
startDate.getMonth(),
startDate.getDate()+1);
This way you don't have to worry about the days in the calendar.
This code add 1 day, if you want to add more, change the startDate.getDate()+1 for startDate.getDate()+NUMBER_OF_DAYS it works fine even if you are on the last day of month i.e. October 31th.
But maybe you can use #RobG solution which is more elegant than mine

Javascript: Why a date does not return the right day?

I'm from Brazil and I've written this piece of code in Javascript
var dt = new Date(2012,9,21); // Oct-21-2012
alert(dt.getDate());
However, it produces 20 and not 21. I've tested with Firefox 18, Chrome 24 and Internet Explorer 8.
How it is possible?
You came across a huge coincidence.
In Brazil, Oct-21-2012 is the start of daylight saving time in most of the country, so local dates at Oct-21-2012 between 0:0 and 1:0 doesn't exist in Brazil!
Some people from other countries did not face the same problem in the same date.
See: http://www.timeanddate.com/news/time/brazil-dst-2012.html
In Brazil the code inside the question really outputs 20
var dt = new Date(2012,9,21); // 21-Oct-2012 0:0
alert(dt.getDate());
However, a slight change generates 21, because 1 hour is enough to "jump over" the lost hour:
var dt = new Date(2012,9,21,1); // 21-Oct-2012 1:00
alert(dt.getDate());
See: http://www.timeanddate.com/time/dst/2013.html
Edit after comments: In United States, for instance, at 10 March, 2013 will start the daylight saving time.
var dt = new Date(2013,02,10); // March-10-2013
alert(dt.getDate()); // Output: 10
Why it is right? Because in the USA the daylight saving time jumps at 2:00 and not 0:00 like in Brazil, therefore implicit 0 hour protect the generated date against problems.However, it is still possible errors in hours elapsing calculation.
-/-
In Brazil the situation should to induce a bug in many sites that handle with dates, regardless of time. One can enter a date in a form and the algorithm calculating elapsed days in a wrong way.
For instance, if somebody uses this nice javascript code to enter dates in a form (
DHML Goodies Calendar ), and after one decides to save that date in a database, it is possible that one get the wrong date, if one has a bad luck to meet special dates.
The definitive solution is use UTC (Coordinated Universal Time) time, because there is no Daylight Saving changes and you use a kind of abstract time. In most practical applications there is no problem.
var dt = new Date( Date.UTC(2012, 9, 21, 8, 5, 12));
alert( (dt.getUTCMonth()+1) + '/' + dt.getUTCDate() + '/' +
dt.getUTCFullYear() + " " + dt.getUTCHours()+ ':' +
dt.getUTCMinutes() + ':' + dt.getUTCSeconds() );
Instead of using UTC, it is easier, if someone doesn't use hours, minutes and seconds, just put a dummy hour value greater or equal than 1, as I have shown above, in Date() call.
Edit after comments: So the Brazil (and countries like Iran,Lebanon, Paraguay, Chile and Portugal ) should change the start of daylight saving time to 2:00 and not 0:00, in order to avoid this confusion and get aligned to more developed countries.
-/-

Unable to validate double digit month using Javascript

I have an HTML form where I am allowing users to enter a date to print out a report. However, if that date is within 3 days of the current date, I have it set to tell the user that they must wait 3 days. For some reason the code works when I enter something like "09/30/2012" but when I enter "10/01/2012", the error check skips. It seems at though, if it's a double digit month (10, 11, and 12), it complete skips the error check. Please let me know if you have any ideas. Thanks
JS Code:
var date = myForm.SC_date.value;
var d = new Date(date);
var varBegin = (d.getMonth()+1) + "-" + (d.getDate()-3) + "-" + d.getFullYear()
re = /^\d{1,2}\/\d{1,2}\/\d{4}$/;
if (myForm.SC_date.value == "")
window.alert("Please enter the requested date of variance. NOTE: Date must be 3 days prior to today's date.")
//Here is where I am having issues
/*else if(new Date(date) > new Date(varBegin))
window.alert("Invalid date. You must wait at least 3 days before you can request a report.")*/
else if(!myForm.SC_date.value.match(re))
window.alert("Invalid date. Please enter the date as follows: mm/dd/yyyy.")
HTML Code:
<td>Date of Variance </td>
<td colspan="2"><input name="SC_date:*" id="SC_date" type="text" tabindex="06">
</textarea><b><span class="style3">*</span> </b><span class="style2">(mm/dd/yyyy)</span>
</td>
I don't think you want to construct your "3 days ago" date by manipulating a string. I.e., this snippet here:
var varBegin = (d.getMonth()+1) + "-" + (d.getDate()-3) + "-" + d.getFullYear()
First, I'm not sure why you're using hyphens as delimiters here, when you are using forward-slashes as delimiters in your input field?
In any case, that's not a reliable way to construct the date. When you feed a string into the constructor of a Date object, you are effectively calling Date.parse(). That behaves differently on different browsers.
Check this out:
> new Date('1-1-2012');
Sun Jan 01 2012 00:00:00 GMT-0800 (PST)
> new Date('01-01-2012');
Sun Jan 01 2012 00:00:00 GMT-0800 (PST)
> new Date('2012-1-1');
Sun Jan 01 2012 00:00:00 GMT-0800 (PST)
Looks pretty good, right? But that's on Chrome.
Now check out what happens in an up-to-date version of Firefox, with the exact same calls:
> new Date('1-1-2012');
Date {Invalid Date}
> new Date('01-01-2012');
Date {Invalid Date}
> new Date('2012-1-1');
Date {Invalid Date}
> new Date('2012-01-01');
Date {Sat Dec 31 2011 16:00:00 GMT-0800 (PST)}
Furthermore, look at this behavior, in both browsers:
> new Date('2012-01-01');
Sat Dec 31 2011 16:00:00 GMT-0800 (PST)
Simply prepending zeroes to the month and date digits causes a time warp! You have to set the time and a timezone (for me, PST) to make that go away:
> new Date('2012-01-01T00:00:00-08:00')
Sun Jan 01 2012 00:00:00 GMT-0800 (PST)
Basically, dealing with date string parsing is a headache. You don't want to have to digest and account for specs like this, this, and this.
So, here's a better alternative -- pass the year, month, and date values (in that order) to the constructor of the Date object. That will reliably create the date for you, so your comparisons are valid.
Like this, for your specific example:
var WARNING_PERIOD_IN_DAYS = 3;
// Extract month, day, year from form input, 'trimming' whitespace.
var re = /^\s*(\d{1,2})\/(\d{1,2})\/(\d{4})\s*$/;
var match = re.exec(inputVal); // from "myForm.SC_date.value".
if (match) {
var month = parseInt(match[1]) - 1; // Zero-indexed months.
var date = parseInt(match[2]);
var year = parseInt(match[3]);
var inputDate = new Date(year, month, date);
var currentDate = new Date();
var threeDaysAgo = new Date(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDay() - WARNING_PERIOD_IN_DAYS);
console.log((inputDate > threeDaysAgo) ? 'Within warning period' : 'No warning needed');
}
Speaking of specs, there's one cool thing to note here, which is that in JavaScript, you can "wrap" the date value (it can be too large, or negative), and the resulting Date will still be valid and correct. Here's why:
From the ECMAScript 262 spec, here's what happens when you call setDate():
**15.9.5.36 Date.prototype.setDate (date)**
1. Let t be the result of LocalTime(this time value).
2. Let dt be ToNumber(date).
3. Let newDate be MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), dt), TimeWithinDay(t)).
4. Let u be TimeClip(UTC(newDate)).
5. Set the [[PrimitiveValue]] internal property of this Date object to u.
6. Return u.
This is the key bit: MakeDay(YearFromTime(t), MonthFromTime(t), dt)
MakeDay gets the year and the month from the current time value of the Date object (in milliseconds of epoch time), and does this:
**15.9.1.12 MakeDay (year, month, date)**
The operator MakeDay calculates a number of days from its three arguments, which must be ECMAScript Number values. This operator functions as follows:
1. If year is not finite or month is not finite or date is not finite, return NaN.
2. Let y be ToInteger(year).
3. Let m be ToInteger(month).
4. Let dt be ToInteger(date).
5. Let ym be y + floor(m /12).
6. Let mn be m modulo 12.
7. Find a value t such that YearFromTime(t) == ym and MonthFromTime(t) == mn and DateFromTime(t) == 1;
but if this is not possible (because some argument is out of range), return NaN.
8. Return Day(t) + dt - 1.
This looks rather involved, but basically it's:
The floor, modulo, and date==1 bits handle month rollovers (months that are negative or greater than 12).
The resulting instant in epoch time is converted to a number of days.
Your date value is added to that number of days. If your date value is negative, that's fine, it will just be subtracted.
The result is passed back to setDate().
setDate calls MakeDate(), which converts the number of days plus the intra-day time into milliseconds in epoch time.
The Date object's internal time is set to this new epoch time.
That's why you can do stuff like this (comments taken from the MakeDay() function in the V8 JS engine project):
// MakeDay(2007, -4, 20) --> MakeDay(2006, 8, 20)
// MakeDay(2007, -33, 1) --> MakeDay(2004, 3, 1)
// MakeDay(2007, 14, -50) --> MakeDay(2007, 8, 11)
Ok, so that was almost certainly too much detail for this particular problem... but I just wanted to make clear what's really going on behind the scenes. Thanks for your patience.
And... just one last thing...
You have a random </textarea> hanging out in that HTML snippet. If there is an opening <textarea> somewhere before it, then it's incorrectly enclosing some of your other elements. If there is no opening <textarea>, then delete it.
If you don't care about the time of the day, I recommend you do the following:
var dUser = new Date(date); //just like you did before
var dVarBegin = new Date("10/05/2012"); //here you do whatever is the date you are setting.
var diff = dVarBegin.getTime() - dUser.getTime();
//now diff is the difference in milliseconds!
I don't fully understand your requirements in relation to the 3 days. However, if what you needed was to compare dates, now you can! I hope this works for you. If you need something more, please ellaborate a little bit on the 3 days thing.
Use a library that lets you control the date formats accepted, e.g. Globalize.js or Date.js. Then define the exact test you wish to carry out especially whether time of the day is significant and whether the test should be relative to current time in user’s system (which is what you get with new Date() without arguments). You can then e.g. calculate a time difference as outlined by #Mamsaac and convert milliseconds to days with simple arithmetic.
It is illogical to use Date() and then, without checking the result, start doing pattern matching on the input. Moreover, Date() is by definition system-dependent and should seldom be used. There is no guarantee that it will accept a format like mm/dd/yyyy at all.

Is there a natural language parser for date/times in javascript?

Is there a natural language parser for date/times in javascript?
I made Chrono a small library for parsing dates in JavaScript. I added a date range parsing feature (such as '12 Nov - 13 Dec 2012') .
SugarJS supports some natural language parsing of dates and times.
You can jump to the live example here: http://sugarjs.com/dates
For example, it supports the following inputs:
the day after tomorrow
2 weeks from monday
May 25th of next year
You can then covert the result into different date formats or use the API to further manipulate the date.
Does Date.js satisfy your needs? Or are you looking for something else?
Chrono v2 is the only library I've found that also parses timezones.
Unfortunately, the only documented way of using it is via NPM (npm i chrono-node) or as ES6 Module (import * as chrono from 'chrono-node'), but I found a way to use the library with the traditional script tag approach for those interested.
Non-NPM / non-module usage:
Include this script: https://www.unpkg.com/chrono-node/dist/bundle.js
Use the global variable chrono in your script (available methods here)
E.g. chrono.parseDate('Tomorrow at 4 PM PST')
⚠ Note: I have not tested this extensively, so don't expect it to work flawlessly
For node, I've found chrono to work well
Chrono supports most date and time formats, such as :
Today, Tomorrow, Yesterday, Last Friday, etc
17 August 2013 - 19 August 2013
This Friday from 13:00 - 16.00
5 days ago
2 weeks from now
Sat Aug 17 2013 18:40:39 GMT+0900 (JST)
2014-11-30T08:15:30-05:30
Sherlock is a great one.
var Sherlock = require('sherlockjs');
var sherlocked = Sherlock.parse('Homework 5 due next monday at 3pm');
// Basic properties
var title = sherlocked.eventTitle; // 'Homework 5 due'
var startDate = sherlocked.startDate; // Date object pointing to next monday at 3pm
var endDate = sherlocked.endDate; // null in this case, since no duration was given
var isAllDay = sherlocked.isAllDay; // false, since a time is included with the event
// Example of an additional custom property added by Watson
var validated = sherlocked.validated; // true
You can use the jQuery datepicker translation, get the day and month number and select the day from datepicker days.
You can add values to this object, and you can download up to 60 languages I think. (The object below is not complete, I removed some code to simplify it).
$.datepicker.regional['sv'] = {
monthNames:['Januari','Februari','Mars','April','Maj','Juni','Juli','Augusti','September','Oktober','November','December'],
monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun','Jul','Aug','Sep','Okt','Nov','Dec'],
dayNamesShort: ['Sön','Mån','Tis','Ons','Tor','Fre','Lör'],
dayNames: ['Söndag','Måndag','Tisdag','Onsdag','Torsdag','Fredag','Lördag'],
dayNamesMin: ['Sö','Må','Ti','On','To','Fr','Lö']
};
Now get the day and month number
var dateObject = new Date();
var day = dateObject.getDay();
var month = dateObject.getMonth();
var monthText = $.datepicker.regional['sv']['monthNames'][month];
var dayText = $.datepicker.regional['sv']['dayNames'][day];

Categories