Create numerical restrictions for date; year, month and day - javascript

I'm trying to put restrictions on a date input field so users don't put in exaggerating dates like the year 3000. I found this neat solution which works. But I want the date in yyyy/mm/dd format with year also having restriction, so mm is between 1-12, dd is between 1-31, and yy is between 1900-2100.
Here's the jsfiddle, I can't get it to work with format yyyy/mm/dd. If I change the dtArrays to
dtMonth = dtArray[5];
dtDay= dtArray[7];
dtYear = dtArray[1];
Year works but mm ends up being in place of dd. What could I be doing wrong? Also are there any better ways of accomplish this? Last question.. this problem seems to be pretty simple, what books on jquery/javascript would you recommend so I may be able to get this on my own?

I think you've misunderstood what you get in dtArray (which isn't a great name). It's the output of the capture groups from this regex:
/^(\d{1,2})(\/|-)(\d{1,2})(\/|-)(\d{4})$/
which matches mm/dd/yyyy (where those are digits) so
[1] = m or mm
[2] = a / or - separator
[3] = d or dd
[4] = a / or - separator
[5] = yyyy
They aren't offsets into the string. (dtArray[0] will be the whole date matched.) With your modified regex is
/^(\d{4})(\/|-)(\d{1,2})(\/|-)(\d{1,2})$/
i.e. four digits in the first position, then you'll get
[1] = yyyy
[2] = a / or - separator
[3] = m or mm
[4] = a / or - separator
[5] = d or dd
and so
dtYear = dtArray[1];
dtMonth = dtArray[3];
dtDay = dtArray[5];
(Note at this point that the three variables will actually be strings, not integers, albeit containing string representations of integer values. However JavaScript being what it is, they'll be coerced into integers when you try and use them as integers.)

Related

New date function is not returning future date as expected

I need Date in IST format so here I am trying to pass the date into three formats, first format gives the correct result but I need the second and third format where the year is passed in the last two digits but if the digits are less then 50 it's giving correct result if it is more then 50 it's giving 1950 as year, in my code I need it to pass as two digits only.
Basically, I need the date format as dd-mm-yy or dd/mm/yy
console.log(new Date(
`04/1/2050`
))// correct
console.log(new Date(
`04/1/50`
))// false
console.log(new Date(
`04/1/40`
))// correct
Following are the rules from ECMA (https://262.ecma-international.org/11.0/#sec-date-constructor)
If 0 ≤ yi ≤ 99, let yr be 1900 + yi; otherwise, let yr be y.
So this
console.log(new Date(
`04/1/40`
))
// 1940-03-31
I guess Browser's are taking liberty in this rule. And changed this rule to something like
If 0 ≤ yi ≤ 49, let yr be 2000 + yi
You can use same logic in your code too. But make sure it is implemented same way in every browser.

remove values from array except defined range

I want date range from 12 to 15. How to get this? Please help
let dates = ["10/07/2021", "11/07/2021", "12/07/2021", "13/07/2021", "14/07/2021", "15/07/2021", "16/07/2021", "17/07/2021"];
Remove item before 12 and after 15
newDates = ["12/07/2021", "13/07/2021", "14/07/2021", "15/07/2021"];
Alternatively (this is essentially #Bravo's suggestion in the comments / #Nithleh's answer below but using regex to make the code a little cleaner):
dates = dates.filter( date => {
let d = new Date(date.replace(/(\d{2})\/(\d{2})\/(\d{4})/, '$3-$2-$1'))
return d.getDate() >= 12 && d.getDate() <= 15
} )
// shoud return ["12/07/2021", "13/07/2021", "14/07/2021", "15/07/2021"]
Regex explanation:
\d matches single digits 0-9 (and other numerical digits). {2} specifies the length of the matching set. (..) captures groups and \/ matches the /.
Your date format is 12/07/2021. In other words, a group of 2 digits followed by a forward slash / followed by a group of 2 digits followed by a / followed by a group of 4 digits. This translates into:
(\d{2})\/(\d{2})\/(\d{4}). This captures 3 parts; first part 2 digits ($1), second part 2 digits ($2) and the third part 4 digits ($3).
Replace function takes care of formatting the date into yyyy-mm-dd format since Date requires the date string to be in that format.
Now we know that the third part $3 holds year, $2 month and $1 day. So date.replace(/(\d{2})\/(\d{2})\/(\d{4})/, '$3-$2-$1') replaces (shifts the parts) the original date 12/07/2021 with the newly formatted date 2021/07/12
Now let d = new Date(date.replace(/(\d{2})\/(\d{2})\/(\d{4})/, '$3-$2-$1')) will have a date object and d.getDate() will give the day portion.
Note that this solution d.getDate() >= 12 && d.getDate() <= 15 would only work if the dates fall within the same month of the same year OR if you want to get these particular days regardless of the month or year.

Extract date(1 or 2 digit), month(1 or 2 digit) and year(2 or 4 digit) from a date string (for different pattern)

My app have a text-field where user can enter the date manually. Also, my app have preferences to select the date pattern like M D Y or D M Y or Y M D.
1) Assume, app is using M D Y pattern currently. So user can enter the date in the following formats:
09/14/2015 or 9/14/2015 or 09/14/15 or 9-14-2015 or 9-14/2015
Here I want to extract the...
month => 09 (or 9)
day => 14
year => 2015 (or 15)
Note: Since app is using M D Y pattern, if user enter the date in D M Y pattern (like 14/09/2015) or Y M Y pattern (like 2015/09/14) we should not match it.
I have the below regex
var dateString = "09/14/2015";
var match = dateString.match(/(\d{1,2})[\/ \.-](\d{1,2})[\/ \.-](\d{2,4}).*/);
but its not matching my expectation, because it allows D M Y and Y M Y pattern too.
2) In the same way, if app is using D M Y pattern I want to extract the day, month and year. (it should not allow M D Y or Y M D)
3) In the same way, if app is using Y M D pattern I want to extract the year, month and day. (it should not allow M D Y or D M Y)
Can someone fix it for me? thank you!
Try This
^((0?[13578]|10|12)(-|\/)(([1-9])|(0[1-9])|([12])([0-9]?)|(3[01]?))(-|\/)((19)([2-9])(\d{1})|(20)([01])(\d{1})|([8901])(\d{1}))|(0?[2469]|11)(-|\/)(([1-9])|(0[1-9])|([12])([0-9]?)|(3[0]?))(-|\/)((19)([2-9])(\d{1})|(20)([01])(\d{1})|([8901])(\d{1})))$
Unfortunately, it's not possible to provide a full answer to your question just by using regular expressions. They are meant to recognize patterns. In several situations, by just recognizing a pattern it's possible to tell that this pattern represents valid data. This is not always true, though and your question is an example.
Think a bit: is "15-02-29" valid?
The answer is: it depends!
This single string can represent:
15/feb/2029 - valid;
??/2nd/2029 - invalid;
2015/feb/29 - invalid, since 2015 is not a leap year;
... and so on.
So this goes way beyond regular expressions are meant to. They are just dumb string recognizers.
The solution? You can even use the regular expressions to extract the values from the passed string, but you'll have to write some extra code to validate what these values mean.
The date 06/05/2015 could mean "June 5th 2015" or "May 6th 2015" either way the date is valid and should be valid for both MDY and DMY so they cant be mutually exclusive. Once the user selects a format you have to trust them to get it right.(in some cases)
Have a look at the javascript library moment.js
You can use it to parse string dates by expected format.
moment("9/14/2015", ["MM-DD-YYYY", "YYYY MM DD", "DD-MM-YYYY"]);
I set up a little playground: http://jsfiddle.net/me2loveit2/knfjepty/

JavaScript regexp parse date/time to milliseconds

I need a little bit of help with a regular expression to convert a date into milliseconds using regular expressions.
I am not sure what regular expression I need to do this.
Here are a few example dates:
3 dagar, 12:00:46
2 dagar, 8:01:00
1 dag, 11:34:00
0 dagar, 0:04:00
Again, I'd like a regexp that will parse these dates into milliseconds.
Alternatively I could use a library like this, to parse the date. But I have not much experience with that either.
The following regex captures days, hours, minutes and seconds.
I asume that you want the number of milliseconds since 1 Jan 1970 (epoch).
We initialize a Date object with the captured info and extract the milliseconds:
var regexp = /([0-9]*) [a-z]*, ([0-9]*):([0-9]*):([0-9]*)/;
var match = regexp.exec('3 dagar, 12:00:46'); //insert your timespan as text here
var date = new Date(1970, 0, parseInt(match[1]) + 1, match[2], match[3], match[4]);
// var result = Math.floor(date.getTime()/1000); //seconds
var result = date.getTime() - date.getTimezoneOffset() * 60000; //milliseconds
We also need to consider the timezone. The date.getTimezoneOffset() returns the offset in minutes.
Maybe you want to test this in rubular and adjust because it may cause problems if the input does not comply with the format that you provided.

Regular Expression | Leap Years and More

I've recently been looking for a regular expression to do some client side date checking, and I haven't been able to find one that can satisfy the following criteria:
Has a range from 1800 - Now
Performs proper date checking with leap years
MM/DD/YYYY Form
Invalid Date Checking
(These constraints were outside of my scope and are a requirement as per the client, despite my efforts to convince them this wasn't the best route)
Current code:
$('input').keyup(function()
{
var regex = /^(?:(0[1-9]|1[012])[\/.](0[1-9]|[12][0-9]|3[01])[\/.](18|19|20)[0-9]{2})$/;
$(this).toggleClass('invalid',!regex.test($(this).val()));
});
Update:
I should note that this is primarily to see if a regular expression like this would be possible (as the use of a Regex is not my choice in this matter). I am aware of the other (and better) options for validating a date, however as previously mentioned - this is to see if it was possible through a regular expression.
As is mentioned elsewhere, regular expressions almost certanily not what you want. But, having said that, if you really want a regular expression, here is how it is built:
31 day months
(0[13578]|1[02])[\/.](0[1-9]|[12][0-9]|3[01])[\/.](18|19|20)[0-9]{2}
30 day months
(0[469]|11)[\/.](0[1-9]|[12][0-9]|30)[\/.](18|19|20)[0-9]{2}
February 1-28 always valid
(02)[\/.](0[1-9]|1[0-9]|2[0-8])[\/.](18|19|20)[0-9]{2}
February 29 also valid on leap years
(02)[\/.]29[\/.](((18|19|20)(04|08|[2468][048]|[13579][26]))|2000)
which means it would be this if you put it all together:
((0[13578]|1[02])[\/.](0[1-9]|[12][0-9]|3[01])[\/.](18|19|20)[0-9]{2})|((0[469]|11)[\/.](0[1-9]|[12][0-9]|30)[\/.](18|19|20)[0-9]{2})|((02)[\/.](0[1-9]|1[0-9]|2[0-8])[\/.](18|19|20)[0-9]{2})|((02)[\/.]29[\/.](((18|19|20)(04|08|[2468][048]|[13579][26]))|2000))
This version is a little shorter, but a little harder to understand.
((0[13578]|1[02])[\/.]31[\/.](18|19|20)[0-9]{2})|((01|0[3-9]|1[1-2])[\/.](29|30)[\/.](18|19|20)[0-9]{2})|((0[1-9]|1[0-2])[\/.](0[1-9]|1[0-9]|2[0-8])[\/.](18|19|20)[0-9]{2})|((02)[\/.]29[\/.](((18|19|20)(04|08|[2468][048]|[13579][26]))|2000))
These scripts are long and unmaintainable. It should be clear that this isn't a good idea, but it is possible.
Caveats:
range 1800-2099 (more can be added without too much difficulty, but requires changes in 4-6 disparate places)
requires 2 digit months and days (the strictness could be removed from the expression in ~8 places)
[\/.] as seperators (8 places)
Hasn't been tested (we could check it against all digit combinations and compare with the javascript date function? [proof that we're reinventing the wheel])
I would suggest that you abandon the attempt to use regular expressions for this. You're much better off parsing the date into its constituent parts (month, day, year), and then using numerical comparisons to make sure it's in the proper range.
Better yet, see if the Javascript Date.parse function will do what you want.
Parsing dates with regular expressions is possible, but frustrating. It's hard to get right, the expression is difficult for non-regex wizards to understand (which means it's difficult to prove that the thing is correct), and it is slow compared to other options.
This is how I would do it:
function validate( input ) {
var date = new Date( input );
input = input.split( '/' );
return date.getMonth() + 1 === +input[0] &&
date.getDate() === +input[1] &&
date.getFullYear() === +input[2];
}
Usage:
validate( '2/1/1983' ) // true
validate( '2/29/1983' ) // false
validate( '2/29/1984' ) // true (1984 is a leap year)
Live demo: http://jsfiddle.net/9QNRx/
this regular expression for YYYY-MM-DD format
((18|19|20)[0-9]{2}[\-.](0[13578]|1[02])[\-.](0[1-9]|[12][0-9]|3[01]))|(18|19|20)[0-9]{2}[\-.](0[469]|11)[\-.](0[1-9]|[12][0-9]|30)|(18|19|20)[0-9]{2}[\-.](02)[\-.](0[1-9]|1[0-9]|2[0-8])|(((18|19|20)(04|08|[2468][048]|[13579][26]))|2000)[\-.](02)[\-.]29
Obviously regular expressions are not the ideal way to do this. Also, it's much safer to be working with YYYY-MM-DD (ISO 8601) format, not MM/DD/YYYY.
That said, here's going for the shortest fully-working regular expression for dates from 01/01/1800 to 12/31/2099:
^(((0[1-9]|1[012])\/(?!00|29)([012]\d)|(0[13-9]|1[012])\/(29|30)|(0[13578]|1[02])\/31)\/(18|19|20)\d{2}|02\/29\/((18|19|20)(0[48]|[2468][048]|[13579][26])|2000))$
Length: 162 characters.
Breakdown:
^ # start
(
( # non-leap months & days
(0[1-9]|1[012])/(?!00|29)([012]\\d) # all months, days 01-28, uses negative lookahead
|
(0[13-9]|1[012])/(29|30) # all months except feb, days 29,30
|
(0[13578]|1[02])/31 # all 31 day months, day 31 only
)
/
(18|19|20)\\d{2} # all years
|
02/29 # leap day
/
(
(18|19|20)(0[48]|[2468][048]|[13579][26]) # leap years not divisible by 100
|
2000 # leap years divisible by 100
)
)
$ # end
Here's a fiddle that tests all use cases from 00/00/1800 to 99/99/2099.
Also, for more fun, here's another fiddle that generates the lousiest possible regular expression that still works, 1205306 characters long. It looks something like this:
^(01/01/1800|01/02/1800|01/03/1800|...|12/29/2099|12/30/2099|12/31/2099)$
RegEx to check for valid dates following ISO 8601, SQL standard.
Has a range from 1000-9999
Checks for Invalid Dates
Checks for valid leap year dates
Format: YYYY-MM-DD HH:MM:SS
^([1-9]\d{3}[\-.](0[13578]|1[02])[\-.](0[1-9]|[12][0-9]|3[01]) ([01]\d|2[0123]):([012345]\d):([012345]\d))|([1-9]\d{3}[\-.](0[469]|11)[\-.](0[1-9]|[12][0-9]|30) ([01]\d|2[0123]):([012345]\d):([012345]\d))|([1-9]\d{3}[\-.](02)[\-.](0[1-9]|1[0-9]|2[0-8]) ([01]\d|2[0123]):([012345]\d):([012345]\d))|(((([1-9]\d)(0[48]|[2468][048]|[13579][26])|(([2468][048]|[13579][26])00)))[\-.](02)[\-.]29 ([01]\d|2[0123]):([012345]\d):([012345]\d))$
^(((?:(?:1[6-9]|[2-9]\d)?\d{2})(-)(?:(?:(?:0?[13578]|1[02])(-)31)|(?:(?:0?[1,3-9]|1[0-2])(-)(?:29|30))))|(((?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))(-)(?:0?2(-)29))|((?:(?:(?:1[6-9]|[2-9]\d)?\d{2})(-)(?:(?:0?[1-9])|(?:1[0-2]))(-)(?:0[1-9]|1\d|2[0-8]))))$
Please try the above Reg Expression. I tried multiple combinations and found to be working.
Please check if this works for you too.
Format Accepted : YYYY-MM-DD
Year accepted from 1600
This is the RegEx I use for date validation on client-side. It has a range from 1000 to 2999, validates leap years and optionally the time part. Isn't it gorgeous :)
var r = /^(0[1-9]|1\d|2[0-8]|29(?=-\d\d-(?!1[01345789]00|2[1235679]00)\d\d(?:[02468][048]|[13579][26]))|30(?!-02)|31(?=-0[13578]|-1[02]))-(0[1-9]|1[0-2])-([12]\d{3})(\s([01]\d|2[0-3]):([0-5]\d):([0-5]\d))?$/gm;
r.test('20-02-2013 10:01:07'); // true
r.test('29-02-1700'); // false
r.test('29-02-1604 14:01:45'); // true
r.test('29-02-1900 20:10:50'); // false
r.test('31-12-2000'); // true
r.test('31-11-2008 05:05:05'); // false
r.test('29-02-2004 05:01:23'); // true
r.test('24-06-2014 24:10:05'); // false
I was trying to validate YYYY-MM-DD, where YYYY can be two digit and MM and DD can be one. This is what I came up with. It treats all centuries as leap years.
((\d\d)?\d\d-((0?(1|3|5|7|8)|10|12)-(31|30|[21]\d|0?[1-9])|(0?(4|6|9)|11)-(31|30|[21]\d|0?[1-9])|0?2-((2[0-8]|1\d)|0?[1-9]))|(\d\d)?((0|2|4|6|8)(0|4|8)|(1|3|5|7|9)(2|6))-0?2-29)
Adding my answer just for sport - otherwise I fully agree with #Jim.
This will match leap years, including the ones with digits fewer or more than 4.
^\d*((((^|0|[2468])[048])|[13579][26])00$)|((0[48]|(^0*|[2468])[048]|[13579][26]))$
A mini test case in Ruby (^ replaced with \A and $ with \Z, because Ruby):
r = /\A\d*((((\A|0|[2468])[048])|[13579][26])00\Z)|((0[48]|(\A0*|[2468])[048]|[13579][26]))\Z/
100000.times do |year|
leap = year % 4 == 0 && ((year % 100 != 0) || (year % 400 == 0))
leap_regex = !year.to_s[r].nil?
if leap != leap_regex
print 'Assertion broken:', year, leap, leap_regex, "\n"
end
end
Using moment (not regex) I've done the following:
Assuming you have an ISO date as a string value:
var isoDate = '2016-11-10';
var parsedIsoDate = moment(isoDate, ['YYYY-MM-DD'], true).format('YYYY-MM-DD');
if (parsedIsoDate !== isoDate) {
// Invalid date.
}
Hello Find RegEx for your Requirement
Has a range from 1800
Now Performs proper date checking with leap years
DD/MM/YYYY Format
Invalid Date Checking
^(?:(?:31(/)(?:0[13578]|1[02]))\1|(?:(?:29|30)(/)(?:0[13-9]|1[0-2])\2))(?:(?:18|19|20)\d{2})$|^(?:29(/)02\3(?:(?:(?:(?:18|19|20))(?:0[48]|[2468][048]|[13579][26]))))$|^(?:0?[1-9]|1\d|2[0-8])(/)(?:(?:0[1-9])|(?:1[0-2]))\4(?:(?:18|19|20)\d{2})$
Image and debug RegEx At https://www.debuggex.com/
Testing:
DD/MM/YYYY
01/12/190 Not Match
29/02/1903 Not Match
37/02/1903 Not Match
09/03/1703 Not Match
09/03/2103 Not Match
09/31/2103 Not Match
29/02/1904 - Match
01/12/1988 - Match
((0[13578]|1[02])[/.]31/.[0-9]{2})|((01|0[3-9]|1[1-2])/./.[0-9]{2})|((0[1-9]|1[0-2])/./.[0-9]{2})|((02)[/.]29/.)
The short version answer does not work for 10/29 and 10/30 any year the long version does work below is a simple java script program I wrote to test
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
public class RegxDateTest {
public static void main(String[] args) {
// String to be scanned to find the pattern.
String line = "This order was placed for QT3000! OK?";
String pattern ="((0[13578]|1[02])[\\/.]31[\\/.](18|19|20)[0-9]{2})|((01|0[3-9]|1[1-2])[\\/.](29|30)[\\/.](18|19|20)[0-9]{2})|((0[1-9]|1[0-2])[\\/.](0[1-9]|1[0-9]|2[0-8])[\\/.](18|19|20)[0-9]{2})|((02)[\\/.]29[\\/.](((18|19|20)(04|08|[2468][048]|[13579][26]))|2000))";
// Create a Pattern object
Pattern r = Pattern.compile(pattern);
LocalDate startDate = new LocalDate("1950-01-01");
LocalDate endDate = new LocalDate("2020-01-01");
for (LocalDate date = startDate; date.isBefore(endDate); date = date.plusDays(1))
{
if (date.toString("MM/dd/yyyy").matches(pattern)) {
// System.out.println("This date does match: " + date.toString("MM/dd/yyyy") );
}else{
System.out.println("This date does not match: " + date.toString("MM/dd/yyyy") );
}
}
String baddate1="02/29/2016";
if (baddate1.matches(pattern)) {
System.out.println("This date does match: " + baddate1 );
}else{
System.out.println("This date does not match: " + baddate1 );
}
System.out.println("alldone: " );
}
}

Categories